Skip to content

Commit 0ba2027

Browse files
kevans91marcan
authored andcommitted
proxyclient: tools: add a FreeBSD loader
The differences are documented in the script itself, but the main odd bit is that we pass the provided kernel as an initramfs. Our modified loader will probe for the initramfs start/end props in FDT and put up a memdisk that we load the kernel from. This choice was made for two reasons: 1.) Avoid ad-hoc interpretations of a memory region in m1n1, it doesn't care if we actually passed it an initramfs or not anyways. 2.) We already had some code on hand to do this in our loader, so I suspect we've done similar shenanigans elsewhere anyways. This also requires a U-Boot change to allow bootefi of an arbitrary location, as long the size is provided. The alignment constraints for loader/kernel were kept arbitrarily. The kernel will be bounced anyways by loader. I don't recall what alignment requirements UEFI payloads have, but 2M seems reasonable. Signed-off-by: Kyle Evans <[email protected]>
1 parent e9f36ad commit 0ba2027

1 file changed

Lines changed: 136 additions & 0 deletions

File tree

proxyclient/tools/freebsd.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: MIT
3+
import sys, pathlib
4+
import serial
5+
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
6+
7+
import argparse, pathlib
8+
9+
# FreeBSD's setup differs from Linux's in the following primary ways:
10+
#
11+
# 1.) We pretend our kernel is an initramfs and pick it up as such in a modified
12+
# loader build. This is the simplest way to avoid having ad-hoc
13+
# interpretations of stuff in m1n1 for our quirky development setup.
14+
#
15+
# 2.) U-Boot and dtb are required, loader/kernel are not. The latter are
16+
# assumed to be discoverable by the standard U-Boot process on disk if they
17+
# are not specified. Otherwise, we'll load them from memory if they are
18+
# provided.
19+
#
20+
parser = argparse.ArgumentParser(description='(FreeBSD) kernel loader for m1n1')
21+
parser.add_argument('u_boot', type=pathlib.Path, help="load u-boot before linux")
22+
parser.add_argument('dtb', type=pathlib.Path)
23+
parser.add_argument('-l', '--loader', type=pathlib.Path)
24+
parser.add_argument('-k', '--kernel', type=pathlib.Path)
25+
parser.add_argument('-b', '--bootargs', type=str, metavar='"boot arguments"')
26+
parser.add_argument('-t', '--tty', type=str)
27+
args = parser.parse_args()
28+
29+
from m1n1.setup import *
30+
31+
if args.tty is not None:
32+
tty_dev = serial.Serial(args.tty)
33+
tty_dev.reset_input_buffer()
34+
tty_dev.baudrate = 1500000
35+
else:
36+
tty_dev = None
37+
38+
if args.loader is not None:
39+
loader = args.loader.read_bytes()
40+
loader_size = len(loader)
41+
else:
42+
loader = None
43+
loader_size = 0
44+
45+
dtb = args.dtb.read_bytes()
46+
47+
if args.kernel is not None:
48+
kernel = args.kernel.read_bytes()
49+
kernel_size = len(kernel)
50+
else:
51+
kernel = None
52+
kernel_size = 0
53+
54+
if args.bootargs is not None:
55+
print('Setting boot args: "{}"'.format(args.bootargs))
56+
p.kboot_set_chosen("bootarg", args.bootargs)
57+
58+
dtb_addr = u.malloc(len(dtb))
59+
print("Loading DTB to 0x%x..." % dtb_addr)
60+
61+
iface.writemem(dtb_addr, dtb)
62+
63+
loader_base = u.memalign(2 * 1024 * 1024, loader_size)
64+
65+
print("loader_base: 0x%x" % loader_base)
66+
67+
assert not (loader_base & 0xffff)
68+
69+
if kernel is not None:
70+
kernel_base = u.memalign(65536, kernel_size)
71+
print("Loading %d kernel bytes to 0x%x..." % (kernel_size, kernel_base))
72+
iface.writemem(kernel_base, kernel, True)
73+
p.kboot_set_initrd(kernel_base, kernel_size)
74+
75+
uboot = bytearray(args.u_boot.read_bytes())
76+
uboot_size = len(uboot)
77+
uboot_addr = u.memalign(2*1024*1024, len(uboot))
78+
print("Loading u-boot to 0x%x..." % uboot_addr)
79+
80+
bootenv_start = uboot.find(b"bootcmd=run distro_bootcmd")
81+
bootenv_len = uboot[bootenv_start:].find(b"\x00\x00")
82+
bootenv_old = uboot[bootenv_start:bootenv_start+bootenv_len]
83+
bootenv = str(bootenv_old, "ascii").split("\x00")
84+
bootenv = list(filter(lambda x: not (x.startswith("baudrate") or (x.startswith("boot_") and not x.startswith("boot_efi_")) or x.startswith("distro_bootcmd")), bootenv))
85+
86+
if loader is not None:
87+
# dtb_addr not used here, the prepared fdt's at a different location. If
88+
# we use this one, we won't get any of our /chosen additions, for instance.
89+
bootcmd = "distro_bootcmd=bootefi 0x%x - 0x%x" % (loader_base, loader_size)
90+
else:
91+
bootcmd = "distro_bootcmd=devnum=0; run usb_boot"
92+
93+
if tty_dev is not None:
94+
bootenv.append("baudrate=%d" % tty_dev.baudrate)
95+
bootenv.append(bootcmd)
96+
if args.bootargs is not None:
97+
bootenv.append("bootargs=" + args.bootargs)
98+
99+
bootenv_new = b"\x00".join(map(lambda x: bytes(x, "ascii"), bootenv))
100+
bootenv_new = bootenv_new.ljust(len(bootenv_old), b"\x00")
101+
102+
if len(bootenv_new) > len(bootenv_old):
103+
raise Exception("New bootenv cannot be larger than original bootenv")
104+
uboot[bootenv_start:bootenv_start+bootenv_len] = bootenv_new
105+
106+
u.compressed_writemem(uboot_addr, uboot, True)
107+
p.dc_cvau(uboot_addr, uboot_size)
108+
p.ic_ivau(uboot_addr, uboot_size)
109+
110+
boot_addr = uboot_addr
111+
112+
p.smp_start_secondaries()
113+
114+
if p.kboot_prepare_dt(dtb_addr):
115+
print("DT prepare failed")
116+
sys.exit(1)
117+
118+
iface.dev.timeout = 40
119+
120+
if loader is not None:
121+
print("Loading %d bytes to 0x%x..0x%x..." % (loader_size, loader_base, loader_base + loader_size))
122+
iface.writemem(loader_base, loader, True)
123+
124+
p.dc_cvau(loader_base, loader_size)
125+
p.ic_ivau(loader_base, loader_size)
126+
127+
print("Ready to boot")
128+
129+
daif = u.mrs(DAIF)
130+
daif = 0xc0
131+
u.msr(DAIF, daif)
132+
print("DAIF: %x" % daif)
133+
134+
p.kboot_boot(boot_addr)
135+
136+
iface.ttymode(tty_dev)

0 commit comments

Comments
 (0)