1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
import sys, pathlib
import serial
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
import argparse, pathlib
parser = argparse.ArgumentParser(description='(Linux) kernel loader for m1n1')
parser.add_argument('payload', type=pathlib.Path)
parser.add_argument('dtb', type=pathlib.Path)
parser.add_argument('initramfs', nargs='?', type=pathlib.Path)
parser.add_argument('--compression', choices=['auto', 'none', 'gz', 'xz'], default='auto')
parser.add_argument('-b', '--bootargs', type=str, metavar='"boot arguments"')
parser.add_argument('-t', '--tty', type=str)
parser.add_argument('-u', '--u-boot', type=pathlib.Path, help="load u-boot before linux")
parser.add_argument('-T', '--tso', action="store_true", help="enable TSO")
args = parser.parse_args()
from m1n1.setup import *
if args.compression == 'auto':
suffix = args.payload.suffix
if suffix == '.gz':
args.compression = 'gz'
elif suffix == '.xz':
args.compression = 'xz'
else:
raise ValueError('unknown compression for {}'.format(args.payload))
if args.tty is not None:
tty_dev = serial.Serial(args.tty)
tty_dev.reset_input_buffer()
tty_dev.baudrate = 1500000
else:
tty_dev = None
payload = args.payload.read_bytes()
dtb = args.dtb.read_bytes()
if args.initramfs is not None:
initramfs = args.initramfs.read_bytes()
initramfs_size = len(initramfs)
else:
initramfs = None
initramfs_size = 0
if args.bootargs is not None:
print('Setting boot args: "{}"'.format(args.bootargs))
p.kboot_set_chosen("bootargs", args.bootargs)
if args.compression != 'none':
compressed_size = len(payload)
compressed_addr = u.malloc(compressed_size)
print("Loading %d bytes to 0x%x..0x%x..." % (compressed_size, compressed_addr, compressed_addr + compressed_size))
iface.writemem(compressed_addr, payload, True)
dtb_addr = u.malloc(len(dtb))
print("Loading DTB to 0x%x..." % dtb_addr)
iface.writemem(dtb_addr, dtb)
kernel_size = 512 * 1024 * 1024
kernel_base = u.memalign(2 * 1024 * 1024, kernel_size)
boot_addr = kernel_base
print("Kernel_base: 0x%x" % kernel_base)
assert not (kernel_base & 0xffff)
if initramfs is not None:
initramfs_base = u.memalign(65536, initramfs_size)
print("Loading %d initramfs bytes to 0x%x..." % (initramfs_size, initramfs_base))
iface.writemem(initramfs_base, initramfs, True)
p.kboot_set_initrd(initramfs_base, initramfs_size)
if args.u_boot:
uboot = bytearray(args.u_boot.read_bytes())
uboot_size = len(uboot)
uboot_addr = u.memalign(2*1024*1024, len(uboot))
print("Loading u-boot to 0x%x..." % uboot_addr)
bootenv_start = uboot.find(b"bootcmd=run distro_bootcmd")
bootenv_len = uboot[bootenv_start:].find(b"\x00\x00")
bootenv_old = uboot[bootenv_start:bootenv_start+bootenv_len]
bootenv = str(bootenv_old, "ascii").split("\x00")
bootenv = list(filter(lambda x: not (x.startswith("baudrate") or x.startswith("boot_") or x.startswith("distro_bootcmd")), bootenv))
if initramfs is not None:
bootcmd = "distro_bootcmd=booti 0x%x 0x%x:0x%x $fdtcontroladdr" % (kernel_base, initramfs_base, initramfs_size)
else:
bootcmd = "distro_bootcmd=booti 0x%x - $fdtcontroladdr" % (kernel_base)
if tty_dev is not None:
bootenv.append("baudrate=%d" % tty_dev.baudrate)
bootenv.append(bootcmd)
if args.bootargs is not None:
bootenv.append("bootargs=" + args.bootargs)
bootenv_new = b"\x00".join(map(lambda x: bytes(x, "ascii"), bootenv))
bootenv_new = bootenv_new.ljust(len(bootenv_old), b"\x00")
if len(bootenv_new) > len(bootenv_old):
raise Exception("New bootenv cannot be larger than original bootenv")
uboot[bootenv_start:bootenv_start+bootenv_len] = bootenv_new
u.compressed_writemem(uboot_addr, uboot, True)
p.dc_cvau(uboot_addr, uboot_size)
p.ic_ivau(uboot_addr, uboot_size)
boot_addr = uboot_addr
p.cpufreq_init()
p.smp_start_secondaries()
if args.tso:
print("Enabling TSO:")
actlr = u.mrs("ACTLR_EL1")
actlr |= (1 << 1) # TSO
print(" CPU #0")
u.msr("ACTLR_EL1", actlr)
for i in range(1, 64):
if p.smp_is_alive(i):
print(f" CPU #{i}")
u.msr("ACTLR_EL1", actlr, call=lambda addr, *args: p.smp_call_sync(i, addr & ~REGION_RX_EL1, *args))
p.kboot_set_chosen("apple,tso", "")
if p.kboot_prepare_dt(dtb_addr):
print("DT prepare failed")
sys.exit(1)
iface.dev.timeout = 40
if args.compression == 'none':
kernel_size = len(payload)
print("Loading %d bytes to 0x%x..0x%x..." % (kernel_size, kernel_base, kernel_base + kernel_size))
iface.writemem(kernel_base, payload, True)
elif args.compression == 'gz':
print("Uncompressing gz ...")
kernel_size = p.gzdec(compressed_addr, compressed_size, kernel_base, kernel_size)
elif args.compression == 'xz':
print("Uncompressing xz ...")
kernel_size = p.xzdec(compressed_addr, compressed_size, kernel_base, kernel_size)
else:
raise ValueError('unsupported compression {}'.format(args.compression))
print(kernel_size)
if kernel_size < 0:
raise Exception("Decompression error!")
print("Decompress OK...")
p.dc_cvau(kernel_base, kernel_size)
p.ic_ivau(kernel_base, kernel_size)
print("Ready to boot")
daif = u.mrs(DAIF)
daif = 0xc0
u.msr(DAIF, daif)
print("DAIF: %x" % daif)
p.kboot_boot(boot_addr)
iface.ttymode(tty_dev)
|