mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-14 03:17:05 +00:00
chainload.py: Cleanup, move Mach-O loader to macho.py
Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
a489a646bd
commit
7c2dace0b0
4 changed files with 110 additions and 83 deletions
|
@ -4,70 +4,27 @@ import argparse, pathlib
|
|||
|
||||
parser = argparse.ArgumentParser(description='Mach-O loader for m1n1')
|
||||
parser.add_argument('payload', type=pathlib.Path)
|
||||
parser.add_argument('-1', '--el1', action="store_true")
|
||||
parser.add_argument('-s', '--sepfw', action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
from setup import *
|
||||
from tgtypes import *
|
||||
from tgtypes import BootArgs
|
||||
from macho import MachO
|
||||
import adt
|
||||
import asm
|
||||
|
||||
payload = args.payload.read_bytes()
|
||||
macho = MachO(args.payload.read_bytes())
|
||||
|
||||
obj = MachO.parse(payload)
|
||||
|
||||
vmin, vmax = (1 << 64), 0
|
||||
|
||||
entry = None
|
||||
|
||||
for cmd in obj.cmds:
|
||||
if cmd.cmd == LoadCmdType.SEGMENT_64:
|
||||
vmin = min(vmin, cmd.args.vmaddr)
|
||||
vmax = max(vmax, cmd.args.vmaddr + cmd.args.vmsize)
|
||||
elif cmd.cmd == LoadCmdType.UNIXTHREAD:
|
||||
entry = cmd.args[0].data.pc
|
||||
|
||||
memory_size = vmax - vmin
|
||||
|
||||
image = bytearray(memory_size)
|
||||
image = macho.prepare_image()
|
||||
|
||||
new_base = u.base
|
||||
|
||||
def align(v, a=16384):
|
||||
return (v + a - 1) & ~(a - 1)
|
||||
|
||||
for cmdi, cmd in enumerate(obj.cmds):
|
||||
is_m1n1 = None
|
||||
if cmd.cmd == LoadCmdType.SEGMENT_64:
|
||||
if is_m1n1 is None:
|
||||
is_m1n1 = cmd.args.segname == "_HDR"
|
||||
dest = cmd.args.vmaddr - vmin
|
||||
end = min(len(payload), cmd.args.fileoff + cmd.args.filesize)
|
||||
size = end - cmd.args.fileoff
|
||||
print(f"LOAD: {cmd.args.segname} {size} bytes from {cmd.args.fileoff:x} to {dest + new_base:x}")
|
||||
image[dest:dest + size] = payload[cmd.args.fileoff:end]
|
||||
if cmd.args.vmsize > size:
|
||||
clearsize = cmd.args.vmsize - size
|
||||
if cmd.args.segname == "PYLD":
|
||||
print("SKIP: %d bytes from 0x%x to 0x%x" % (clearsize, dest + new_base + size, dest + new_base + size + clearsize))
|
||||
memory_size -= clearsize - 4 # leave a payload end marker
|
||||
image = image[:memory_size]
|
||||
else:
|
||||
print("ZERO: %d bytes from 0x%x to 0x%x" % (clearsize, dest + new_base + size, dest + new_base + size + clearsize))
|
||||
image[dest + size:dest + cmd.args.vmsize] = bytes(clearsize)
|
||||
|
||||
entry -= vmin
|
||||
entry = macho.entry
|
||||
entry -= macho.vmin
|
||||
entry += new_base
|
||||
|
||||
if args.sepfw:
|
||||
adt_base = u.ba.devtree - u.ba.virt_base + u.ba.phys_base
|
||||
adt_size = u.ba.devtree_size
|
||||
print(f"Fetching ADT ({adt_size} bytes)...")
|
||||
adt = adt.load_adt(iface.readmem(adt_base, u.ba.devtree_size))
|
||||
|
||||
sepfw_start, sepfw_length = adt["chosen"]["memory-map"].SEPFW
|
||||
|
||||
sepfw_start, sepfw_length = u.adt["chosen"]["memory-map"].SEPFW
|
||||
else:
|
||||
sepfw_start, sepfw_length = 0, 0
|
||||
|
||||
|
@ -90,9 +47,12 @@ if args.sepfw:
|
|||
|
||||
print(f"Setting up bootargs...")
|
||||
tba = u.ba.copy()
|
||||
#tba.phys_base = new_base
|
||||
#tba.virt_base = 0xfffffe0010000000 + new_base & (32 * 1024 * 1024 - 1)
|
||||
tba.top_of_kdata = new_base + image_size
|
||||
|
||||
if args.sepfw:
|
||||
tba.top_of_kernel_data = new_base + image_size
|
||||
else:
|
||||
# SEP firmware is in here somewhere, keep top_of_kdata high so we hopefully don't clobber it
|
||||
tba.top_of_kernel_data = max(tba.top_of_kernel_data, new_base + image_size)
|
||||
|
||||
iface.writemem(image_addr + bootargs_off, BootArgs.build(tba))
|
||||
|
||||
|
@ -116,18 +76,10 @@ iface.writemem(stub.addr, stub.data)
|
|||
p.dc_cvau(stub.addr, stub.len)
|
||||
p.ic_ivau(stub.addr, stub.len)
|
||||
|
||||
if args.el1:
|
||||
print("Setting up EL1 config")
|
||||
|
||||
# Enable physical timer for EL1
|
||||
u.msr(CNTHCTL_EL2, 3 << 10) # EL1PTEN | EL1PCTEN
|
||||
|
||||
# Unredirect IRQs/FIQs
|
||||
u.msr(HCR_EL2, u.mrs(HCR_EL2) & ~(3 << 3)) # ~(IMO | FMO)
|
||||
|
||||
print(f"Entry point: 0x{entry:x}")
|
||||
print(f"Jumping to stub at 0x{stub.addr:x}")
|
||||
|
||||
p.reboot(stub.addr, new_base + bootargs_off, image_addr, new_base, image_size, el1=args.el1)
|
||||
p.reboot(stub.addr, new_base + bootargs_off, image_addr, new_base, image_size)
|
||||
|
||||
iface.nop()
|
||||
print("Proxy is alive again")
|
||||
|
|
47
proxyclient/macho.py
Normal file
47
proxyclient/macho.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from tgtypes import *
|
||||
from utils import *
|
||||
|
||||
class MachO:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.obj = MachOFile.parse(data)
|
||||
self.load_info()
|
||||
|
||||
def load_info(self):
|
||||
self.vmin, self.vmax = (1 << 64), 0
|
||||
self.entry = None
|
||||
for cmd in self.obj.cmds:
|
||||
if cmd.cmd == MachOLoadCmdType.SEGMENT_64:
|
||||
self.vmin = min(self.vmin, cmd.args.vmaddr)
|
||||
self.vmax = max(self.vmax, cmd.args.vmaddr + cmd.args.vmsize)
|
||||
elif cmd.cmd == MachOLoadCmdType.UNIXTHREAD:
|
||||
self.entry = cmd.args[0].data.pc
|
||||
|
||||
def prepare_image(self):
|
||||
memory_size = self.vmax - self.vmin
|
||||
|
||||
image = bytearray(memory_size)
|
||||
|
||||
for cmdi, cmd in enumerate(self.obj.cmds):
|
||||
is_m1n1 = None
|
||||
if cmd.cmd == MachOLoadCmdType.SEGMENT_64:
|
||||
if is_m1n1 is None:
|
||||
is_m1n1 = cmd.args.segname == "_HDR"
|
||||
dest = cmd.args.vmaddr - self.vmin
|
||||
end = min(len(self.data), cmd.args.fileoff + cmd.args.filesize)
|
||||
size = end - cmd.args.fileoff
|
||||
print(f"LOAD: {cmd.args.segname} {size} bytes from {cmd.args.fileoff:x} to {dest:x}")
|
||||
image[dest:dest + size] = self.data[cmd.args.fileoff:end]
|
||||
if cmd.args.vmsize > size:
|
||||
clearsize = cmd.args.vmsize - size
|
||||
if cmd.args.segname == "PYLD":
|
||||
print("SKIP: %d bytes from 0x%x to 0x%x" % (clearsize, dest + size, dest + size + clearsize))
|
||||
memory_size -= clearsize - 4 # leave a payload end marker
|
||||
image = image[:memory_size]
|
||||
else:
|
||||
print("ZERO: %d bytes from 0x%x to 0x%x" % (clearsize, dest + size, dest + size + clearsize))
|
||||
image[dest + size:dest + cmd.args.vmsize] = bytes(clearsize)
|
||||
|
||||
return image
|
|
@ -1,7 +1,7 @@
|
|||
import serial, os, struct, sys, time, json, os.path, lzma
|
||||
import serial, os, struct, sys, time, json, os.path, lzma, functools
|
||||
from proxy import *
|
||||
from tgtypes import *
|
||||
import malloc
|
||||
import malloc, adt
|
||||
|
||||
def load_registers():
|
||||
data = json.load(open(os.path.join(os.path.dirname(__file__), "..", "tools", "arm_regs.json")))
|
||||
|
@ -42,6 +42,9 @@ class ProxyUtils(object):
|
|||
|
||||
self.code_buffer = self.malloc(0x10000)
|
||||
|
||||
self.adt_data = None
|
||||
self.adt = LazyADT(self)
|
||||
|
||||
def mrs(self, reg, silent=False, call=None):
|
||||
if call is None:
|
||||
call = self.proxy.call
|
||||
|
@ -115,6 +118,31 @@ class ProxyUtils(object):
|
|||
|
||||
assert decompressed_size == len(data)
|
||||
|
||||
def get_adt(self):
|
||||
if self.adt_data is not None:
|
||||
return self.adt_data
|
||||
adt_base = self.ba.devtree - self.ba.virt_base + self.ba.phys_base
|
||||
adt_size = self.ba.devtree_size
|
||||
print(f"Fetching ADT ({adt_size} bytes)...")
|
||||
self.adt_data = self.iface.readmem(adt_base, self.ba.devtree_size)
|
||||
return self.adt_data
|
||||
|
||||
class LazyADT:
|
||||
def __init__(self, utils):
|
||||
self.utils = utils
|
||||
|
||||
@functools.cached_property
|
||||
def _adt(self):
|
||||
return adt.load_adt(self.utils.get_adt())
|
||||
def __getitem__(self, item):
|
||||
return self._adt[item]
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self._adt, item)
|
||||
def __str__(self, t=""):
|
||||
return gstr(self._adt)
|
||||
def __iter__(self):
|
||||
return iter(self._adt)
|
||||
|
||||
class RegMonitor(object):
|
||||
def __init__(self, utils):
|
||||
self.utils = utils
|
||||
|
|
|
@ -27,7 +27,7 @@ BootArgs = Struct(
|
|||
"mem_size_actual" / Hex(Int64ul),
|
||||
)
|
||||
|
||||
LoadCmdType = "LoadCmdType" / Enum(Int32ul,
|
||||
MachOLoadCmdType = "LoadCmdType" / Enum(Int32ul,
|
||||
UNIXTHREAD = 0x05,
|
||||
SEGMENT_64 = 0x19,
|
||||
UUID = 0x1b,
|
||||
|
@ -36,11 +36,11 @@ LoadCmdType = "LoadCmdType" / Enum(Int32ul,
|
|||
FILESET_ENTRY = 0x80000035,
|
||||
)
|
||||
|
||||
ArmThreadStateFlavor = "ThreadStateFlavor" / Enum(Int32ul,
|
||||
MachOArmThreadStateFlavor = "ThreadStateFlavor" / Enum(Int32ul,
|
||||
THREAD64 = 6,
|
||||
)
|
||||
|
||||
MachHeader = Struct(
|
||||
MachOHeader = Struct(
|
||||
"magic" / Hex(Int32ul),
|
||||
"cputype" / Hex(Int32ul),
|
||||
"cpusubtype" / Hex(Int32ul),
|
||||
|
@ -51,16 +51,16 @@ MachHeader = Struct(
|
|||
"reserved" / Hex(Int32ul),
|
||||
)
|
||||
|
||||
VmProt = FlagsEnum(Int32sl,
|
||||
MachOVmProt = FlagsEnum(Int32sl,
|
||||
PROT_READ = 0x01,
|
||||
PROT_WRITE = 0x02,
|
||||
PROT_EXECUTE = 0x04,
|
||||
)
|
||||
|
||||
CmdUnixThread = GreedyRange(Struct(
|
||||
"flavor" / ArmThreadStateFlavor,
|
||||
MachOCmdUnixThread = GreedyRange(Struct(
|
||||
"flavor" / MachOArmThreadStateFlavor,
|
||||
"data" / Prefixed(ExprAdapter(Int32ul, obj_ * 4, obj_ / 4), Switch(this.flavor, {
|
||||
ArmThreadStateFlavor.THREAD64: Struct(
|
||||
MachOArmThreadStateFlavor.THREAD64: Struct(
|
||||
"x" / Array(29, Hex(Int64ul)),
|
||||
"fp" / Hex(Int64ul),
|
||||
"lr" / Hex(Int64ul),
|
||||
|
@ -73,14 +73,14 @@ CmdUnixThread = GreedyRange(Struct(
|
|||
))
|
||||
|
||||
|
||||
CmdSegment64 = Struct(
|
||||
MachOCmdSegment64 = Struct(
|
||||
"segname" / PaddedString(16, "ascii"),
|
||||
"vmaddr" / Hex(Int64ul),
|
||||
"vmsize" / Hex(Int64ul),
|
||||
"fileoff" / Hex(Int64ul),
|
||||
"filesize" / Hex(Int64ul),
|
||||
"maxprot" / VmProt,
|
||||
"initprot" / VmProt,
|
||||
"maxprot" / MachOVmProt,
|
||||
"initprot" / MachOVmProt,
|
||||
"nsects" / Int32ul,
|
||||
"flags" / Hex(Int32ul),
|
||||
"sections" / GreedyRange(Struct(
|
||||
|
@ -99,17 +99,17 @@ CmdSegment64 = Struct(
|
|||
)),
|
||||
)
|
||||
|
||||
Cmd = Struct(
|
||||
"cmd" / Hex(LoadCmdType),
|
||||
MachOCmd = Struct(
|
||||
"cmd" / Hex(MachOLoadCmdType),
|
||||
"args" / Prefixed(ExprAdapter(Int32ul, obj_ - 8, obj_ + 8), Switch(this.cmd, {
|
||||
LoadCmdType.UNIXTHREAD: CmdUnixThread,
|
||||
LoadCmdType.SEGMENT_64: CmdSegment64,
|
||||
LoadCmdType.UUID: Hex(Bytes(16)),
|
||||
MachOLoadCmdType.UNIXTHREAD: MachOCmdUnixThread,
|
||||
MachOLoadCmdType.SEGMENT_64: MachOCmdSegment64,
|
||||
MachOLoadCmdType.UUID: Hex(Bytes(16)),
|
||||
}, default=GreedyBytes)),
|
||||
)
|
||||
|
||||
MachO = Struct(
|
||||
"header" / MachHeader,
|
||||
"cmds" / Array(this.header.ncmds, Cmd),
|
||||
MachOFile = Struct(
|
||||
"header" / MachOHeader,
|
||||
"cmds" / Array(this.header.ncmds, MachOCmd),
|
||||
"extradata" / GreedyBytes,
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue