m1n1/proxyclient/chainload.py
Hector Martin 3a42f80a73 chainload.py: Set up sane EL1 config for timers/IRQs
Signed-off-by: Hector Martin <marcan@marcan.st>
2021-03-28 19:31:14 +09:00

80 lines
2.3 KiB
Python
Executable file

#!/usr/bin/env python3
import argparse, pathlib
parser = argparse.ArgumentParser(description='(Linux) kernel loader for m1n1')
parser.add_argument('payload', type=pathlib.Path)
parser.add_argument('-1', '--el1', action="store_true")
args = parser.parse_args()
from setup import *
from tgtypes import *
payload = 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
# FIXME: this will currently still waste the whole m1n1 size including payload area (64+MB) on each
# chainload. The best way to fix this is to support in-place chainloading, which has other
# advantages.
try:
# Try to use the m1n1 heap to avoid wasting 128MB RAM on every load
new_base = p.memalign(0x10000, memory_size)
except:
# Fall back to proxy heap, which will be at the right place in old versions
new_base = u.memalign(0x10000, memory_size)
for cmd in obj.cmds:
if cmd.cmd == LoadCmdType.SEGMENT_64:
if cmd.args.fileoff == 0:
continue # do not load mach-o headers, not needed for now
dest = cmd.args.vmaddr - vmin + new_base
end = min(len(payload), cmd.args.fileoff + cmd.args.filesize)
size = end - cmd.args.fileoff
print("Loading %d bytes from 0x%x to 0x%x" % (size, cmd.args.fileoff, dest))
u.compressed_writemem(dest, payload[cmd.args.fileoff:end], True)
if cmd.args.vmsize > size:
clearsize = cmd.args.vmsize - size
print("Zeroing %d bytes from 0x%x to 0x%x" % (clearsize, dest + size, dest + size + clearsize))
p.memset8(dest + size, 0, clearsize)
p.dc_cvau(new_base, memory_size)
p.ic_ivau(new_base, memory_size)
entry -= vmin
entry += new_base
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("Jumping to 0x%x" % entry)
try:
p.mmu_shutdown()
except:
pass
p.reboot(entry, u.ba_addr, el1=args.el1)
iface.nop()
print("Proxy is alive again")