[boot] Build, load, and pass initrd from boot to init

The initrd image is now created by the build system, loaded by the
bootloader, and passed to srv.init, which loads it (but doesn't do
anything with it yet, so this is actually a functional regression).

This simplifies a lot of the modules code between boot and init as well:
Gone are the many subclasses of module and all the data being inline
with the module structs, except for any loaded files. Now the only
modules loaded and passed will be the initrd, and any devices only the
bootloader has knowledge of, like the UEFI framebuffer.
This commit is contained in:
Justin C. Miller
2023-01-17 19:12:40 -07:00
parent 6ef15a2721
commit 66abcc57a2
26 changed files with 399 additions and 296 deletions

View File

@@ -2,12 +2,16 @@ from . import BonnibelError
class Manifest:
from collections import namedtuple
Entry = namedtuple("Entry", ("module", "target", "output", "location", "description", "flags"))
Entry = namedtuple("Entry", ("module", "target", "output", "flags"))
formats = {
"none": 0x00,
"zstd": 0x01,
}
flags = {
"graphical": 0x01,
"panic": 0x02,
"symbols": 0x04,
"symbols": 0x80,
}
boot_flags = {
@@ -20,6 +24,8 @@ class Manifest:
config = load_config(path)
self.location = config.get("location", "jsix")
self.kernel = self.__build_entry(modules,
config.get("kernel", dict()),
name="kernel", target="kernel")
@@ -27,11 +33,24 @@ class Manifest:
self.init = self.__build_entry(modules,
config.get("init", None))
self.programs = [self.__build_entry(modules, i)
for i in config.get("programs", tuple())]
self.panics = [self.__build_entry(modules, i, target="kernel")
for i in config.get("panic", tuple())]
self.services = [self.__build_entry(modules, i)
for i in config.get("services", tuple())]
self.drivers = [self.__build_entry(modules, i)
for i in config.get("drivers", tuple())]
self.flags = config.get("flags", tuple())
initrd = config.get("initrd", dict())
self.initrd = initrd.get("name", "initrd.dat")
self.initrd_format = initrd.get("format", "none")
if not self.initrd_format in Manifest.formats:
raise BonnibelError(f"Manifest specifies unknown initrd format '{self.initrd_format}'")
self.data = []
for d in config.get("data", tuple()):
self.add_data(**d)
@@ -56,10 +75,10 @@ class Manifest:
if not f in Manifest.flags:
raise BonnibelError(f"Manifest specifies unknown flag '{f}'")
return Manifest.Entry(name, target, mod.output, mod.location, mod.description, flags)
return Manifest.Entry(name, target, mod.output, flags)
def add_data(self, output, location, desc, flags=tuple()):
e = Manifest.Entry(None, None, output, location, desc, flags)
def add_data(self, output, desc, flags=tuple()):
e = Manifest.Entry(None, None, output, flags)
self.data.append(e)
return e
@@ -69,35 +88,83 @@ class Manifest:
with open(path, 'wb') as outfile:
magic = "jsixboot".encode("utf-8") # magic string
version = 0
version = 1
reserved = 0
initrd_format = Manifest.formats.get(self.initrd_format, 0)
bootflags = sum([Manifest.boot_flags.get(s, 0) for s in self.flags])
outfile.write(struct.pack("<8sBBHHH",
magic, version, reserved,
len(self.programs), len(self.data),
bootflags))
outfile.write(struct.pack("<8s BBH HH",
magic,
version, reserved, len(self.panics),
initrd_format, bootflags))
def write_str(s):
outfile.write(struct.pack("<H", (len(s)+1)*2))
outfile.write(s.encode("utf-16le"))
data = s.encode("utf-16le")
outfile.write(struct.pack("<H", len(data)+2))
outfile.write(data)
outfile.write(b"\0\0")
def write_path(name):
write_str(join(self.location, name).replace('/','\\'))
def write_ent(ent):
flags = 0
for f in ent.flags:
flags |= Manifest.flags[f]
outfile.write(struct.pack("<H", flags))
write_str(join(ent.location, ent.output).replace('/','\\'))
write_str(ent.description)
write_path(ent.output)
write_ent(self.kernel)
write_ent(self.init)
write_path(self.initrd)
for p in self.programs:
for p in self.panics:
write_ent(p)
for d in self.data:
write_ent(d)
def write_init_config(self, path, modules):
from os.path import join
import struct
with open(path, 'wb') as outfile:
magic = "jsixinit".encode("utf-8") # magic string
version = 1
reserved = 0
string_data = bytearray()
outfile.write(struct.pack("<8s BBH HH",
magic,
version, reserved, len(self.services),
len(self.data), len(self.drivers)))
offset_ptr = outfile.tell()
outfile.write(struct.pack("<H", 0)) # filled in later
def write_str(s):
pos = len(string_data)
string_data.extend(s.encode("utf-8") + b"\0")
outfile.write(struct.pack("<H", pos))
def write_driver(ent):
write_str(ent.output)
drivers = modules[ent.module].drivers
outfile.write(struct.pack("<H", len(drivers)))
for driver in drivers:
write_str(driver)
for p in self.services:
write_str(p.output)
for p in self.data:
write_str(p.output)
for p in self.drivers:
write_driver(p)
offset = outfile.tell()
outfile.write(string_data)
outfile.seek(offset_ptr)
outfile.write(struct.pack("<H", offset))

View File

@@ -23,9 +23,9 @@ class Module:
"public_headers": (set, ()),
"includes": (tuple, ()),
"sources": (tuple, ()),
"drivers": (tuple, ()),
"variables": (dict, ()),
"default": (bool, False),
"location": (str, "jsix"),
"description": (str, None),
"no_libc": (bool, False),
}

View File

@@ -71,9 +71,13 @@ class Project:
fatroot.mkdir(exist_ok=True)
fatroot_content = []
initrd_content = []
from .manifest import Manifest
manifest = Manifest(manifest_file, modules)
def add_fatroot(source, entry):
output = join(entry.location, entry.output)
output = join(manifest.location, entry.output)
fatroot_output = f"${{build_root}}/fatroot/{output}"
build.build(
@@ -103,16 +107,30 @@ class Project:
add_fatroot(intermediary, entry)
from .manifest import Manifest
manifest = Manifest(manifest_file, modules)
def add_initrd_exe(entry):
input_path = f"${{build_root}}/{entry.target}/{entry.output}"
intermediary = f"${{build_root}}/{entry.output}"
build.build(
rule = "strip",
outputs = [intermediary],
inputs = [input_path],
implicit = [f"{input_path}.dump"],
variables = {
"name": f"Stripping {entry.module}",
"debug": f"${{build_root}}/.debug/{entry.output}.debug",
})
initrd_content.append(intermediary)
add_fatroot_exe(manifest.kernel)
add_fatroot_exe(manifest.init)
for program in manifest.programs:
add_fatroot_exe(program)
for program in manifest.panics: add_fatroot_exe(program)
for program in manifest.services: add_initrd_exe(program)
for program in manifest.drivers: add_initrd_exe(program)
syms = manifest.add_data("symbol_table.dat",
manifest.kernel.location, "Symbol table", ("symbols",))
"Symbol table", ("symbols",))
sym_out = f"${{build_root}}/symbol_table.dat"
build.build(
@@ -120,7 +138,7 @@ class Project:
outputs = [sym_out],
inputs = [f"${{build_root}}/{modules['kernel'].output}"],
)
add_fatroot(sym_out, syms)
initrd_content.append(sym_out)
bootloader = "${build_root}/fatroot/efi/boot/bootx64.efi"
build.build(
@@ -132,8 +150,20 @@ class Project:
})
build.newline()
boot_config = join(fatroot, "jsix_boot.dat")
boot_config = str(fatroot / "jsix_boot.dat")
init_config = str(output / "init.manifest")
manifest.write_boot_config(boot_config)
manifest.write_init_config(init_config, modules)
initrd_content.append(init_config)
initrd = join(fatroot, manifest.location, "initrd.dat")
build.build(
rule = "mkinitrd",
outputs = [initrd],
inputs = initrd_content,
)
build.newline()
fatroot_content.append(initrd)
build.build(
rule = "makefat",