From 66abcc57a27c503b48d32973f87711515b39c282 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Tue, 17 Jan 2023 19:12:40 -0700 Subject: [PATCH] [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. --- assets/manifests/default.yaml | 16 ++- assets/manifests/test.yaml | 16 ++- scripts/bonnibel/manifest.py | 107 ++++++++++++++---- scripts/bonnibel/module.py | 2 +- scripts/bonnibel/project.py | 46 ++++++-- src/boot/allocator.cpp | 9 +- src/boot/allocator.h | 6 +- src/boot/bootconfig.cpp | 23 ++-- src/boot/bootconfig.h | 11 +- src/boot/loader.cpp | 53 +++------ src/boot/loader.h | 24 ++-- src/boot/main.cpp | 50 ++++---- src/boot/status.h | 5 +- src/boot/video.cpp | 34 +++--- src/boot/video.h | 11 +- src/libraries/bootproto/bootproto.module | 1 + .../bootproto/bootproto/bootconfig.h | 6 +- .../bootproto/bootproto/devices/framebuffer.h | 28 +++++ src/libraries/bootproto/bootproto/init.h | 63 +++-------- src/user/drv.uart/uart.module | 1 + src/user/drv.uefi_fb/uefi_fb.module | 1 + src/user/srv.init/loader.cpp | 77 +++++++------ src/user/srv.init/loader.h | 6 + src/user/srv.init/main.cpp | 38 +++++-- src/user/srv.init/modules.cpp | 24 ++-- src/user/srv.init/modules.h | 37 +++--- 26 files changed, 399 insertions(+), 296 deletions(-) create mode 100644 src/libraries/bootproto/bootproto/devices/framebuffer.h diff --git a/assets/manifests/default.yaml b/assets/manifests/default.yaml index a33e664..eec9e89 100644 --- a/assets/manifests/default.yaml +++ b/assets/manifests/default.yaml @@ -1,8 +1,12 @@ --- +location: jsix init: srv.init -programs: - - name: panic.serial - target: kernel - flags: panic - - name: srv.logger - - name: drv.uart +initrd: + name: initrd.dat + format: zstd +panic: + - panic.serial +services: + - srv.logger +drivers: + - drv.uart diff --git a/assets/manifests/test.yaml b/assets/manifests/test.yaml index a09b3c0..9df0828 100644 --- a/assets/manifests/test.yaml +++ b/assets/manifests/test.yaml @@ -1,9 +1,13 @@ --- +location: jsix init: srv.init +initrd: + name: initrd.dat + format: zstd flags: ["test"] -programs: - - name: panic.serial - target: kernel - flags: panic - - name: drv.uart - - name: test_runner +panic: + - panic.serial +services: + - test_runner +drivers: + - drv.uart diff --git a/scripts/bonnibel/manifest.py b/scripts/bonnibel/manifest.py index 6ca161f..5cb4704 100644 --- a/scripts/bonnibel/manifest.py +++ b/scripts/bonnibel/manifest.py @@ -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("next = reinterpret_cast(mods); - mods->modules = reinterpret_cast(mods + 1); m_modules = mods; m_next_mod = mods->modules; return; @@ -110,11 +109,13 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero) } module * -allocator::allocate_module_untyped(size_t size) +allocator::allocate_module() { + static constexpr size_t size = sizeof(module); + size_t remaining = reinterpret_cast(m_modules) + page_size - - reinterpret_cast(m_next_mod); + - reinterpret_cast(m_next_mod) - sizeof(module); if (size > remaining) add_modules(); @@ -122,8 +123,6 @@ allocator::allocate_module_untyped(size_t size) ++m_modules->count; module *m = m_next_mod; m_next_mod = util::offset_pointer(m_next_mod, size); - - m->mod_length = size; return m; } diff --git a/src/boot/allocator.h b/src/boot/allocator.h index 822f0e7..d0b0f7e 100644 --- a/src/boot/allocator.h +++ b/src/boot/allocator.h @@ -32,10 +32,7 @@ public: void * allocate_pages(size_t count, alloc_type type, bool zero = false); - template - M * allocate_module(size_t extra = 0) { - return static_cast(allocate_module_untyped(sizeof(M) + extra)); - } + module * allocate_module(); void memset(void *start, size_t size, uint8_t value); void copy(void *to, void *from, size_t size); @@ -54,7 +51,6 @@ public: private: void add_register(); void add_modules(); - module * allocate_module_untyped(size_t size); uefi::boot_services &m_bs; diff --git a/src/boot/bootconfig.cpp b/src/boot/bootconfig.cpp index 9335521..36d412d 100644 --- a/src/boot/bootconfig.cpp +++ b/src/boot/bootconfig.cpp @@ -24,7 +24,6 @@ read_descriptor(descriptor &e, util::buffer &data) { e.flags = static_cast(*util::read(data)); e.path = read_string(data); - e.desc = read_string(data); } bootconfig::bootconfig(util::buffer data, uefi::boot_services *bs) @@ -35,29 +34,23 @@ bootconfig::bootconfig(util::buffer data, uefi::boot_services *bs) error::raise(uefi::status::load_error, L"Bad header in jsix_boot.dat"); const uint8_t version = *util::read(data); - if (version != 0) + if (version != 1) error::raise(uefi::status::incompatible_version, L"Bad version in jsix_boot.dat"); data += 1; // reserved byte - uint16_t num_programs = *util::read(data); - uint16_t num_data = *util::read(data); - + uint16_t num_panics = *util::read(data); + m_initrd_format = *util::read(data); m_flags = *util::read(data); read_descriptor(m_kernel, data); read_descriptor(m_init, data); + m_initrd = read_string(data); - m_programs.count = num_programs; - m_programs.pointer = new descriptor [num_programs]; + m_panics.count = num_panics; + m_panics.pointer = new descriptor [num_panics]; - for (unsigned i = 0; i < num_programs; ++i) - read_descriptor(m_programs[i], data); - - m_data.count = num_programs; - m_data.pointer = new descriptor [num_data]; - - for (unsigned i = 0; i < num_data; ++i) - read_descriptor(m_data[i], data); + for (unsigned i = 0; i < num_panics; ++i) + read_descriptor(m_panics[i], data); } } // namespace boot diff --git a/src/boot/bootconfig.h b/src/boot/bootconfig.h index a5a8cf5..66e6921 100644 --- a/src/boot/bootconfig.h +++ b/src/boot/bootconfig.h @@ -16,7 +16,6 @@ using desc_flags = bootproto::desc_flags; struct descriptor { desc_flags flags; wchar_t const *path; - wchar_t const *desc; }; /// A bootconfig is a manifest of potential files. @@ -31,15 +30,17 @@ public: inline uint16_t flags() const { return m_flags; } inline const descriptor & kernel() const { return m_kernel; } inline const descriptor & init() const { return m_init; } - descriptors programs() { return m_programs; } - descriptors data() { return m_data; } + inline const wchar_t * initrd() const { return m_initrd; } + inline uint16_t initrd_format() const { return m_initrd_format; } + inline const descriptors & panics() { return m_panics; } private: uint16_t m_flags; + uint16_t m_initrd_format; descriptor m_kernel; descriptor m_init; - descriptors m_programs; - descriptors m_data; + descriptors m_panics; + wchar_t const *m_initrd; }; } // namespace boot diff --git a/src/boot/loader.cpp b/src/boot/loader.cpp index b7abf62..63b4075 100644 --- a/src/boot/loader.cpp +++ b/src/boot/loader.cpp @@ -24,52 +24,26 @@ using memory::alloc_type; util::buffer load_file( fs::file &disk, - const descriptor &desc) + const wchar_t *path) { - status_line status(L"Loading file", desc.path); + status_line status(L"Loading file", path); - fs::file file = disk.open(desc.path); + fs::file file = disk.open(path); util::buffer b = file.load(); //console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size); return b; } - -static void -create_module(util::buffer data, const descriptor &desc, bool loaded) -{ - size_t path_len = wstrlen(desc.path); - bootproto::module_program *mod = g_alloc.allocate_module(path_len); - mod->mod_type = bootproto::module_type::program; - mod->base_address = reinterpret_cast(data.pointer); - mod->size = data.count; - if (loaded) - mod->mod_flags = static_cast( - static_cast(mod->mod_flags) | - static_cast(bootproto::module_flags::no_load)); - - // TODO: support non-ascii path characters and do real utf-16 to utf-8 - // conversion - for (int i = 0; i < path_len; ++i) { - char c = desc.path[i]; - mod->filename[i] = c == '\\' ? '/' : c; - } - mod->filename[path_len] = 0; -} - bootproto::program * load_program( fs::file &disk, - const descriptor &desc, - bool add_module) + const wchar_t *name, + const descriptor &desc) { - status_line status(L"Loading program", desc.desc); + status_line status(L"Loading program", name); - util::buffer data = load_file(disk, desc); - - if (add_module) - create_module(data, desc, true); + util::buffer data = load_file(disk, desc.path); elf::file program(data.pointer, data.count); if (!program.valid()) { @@ -129,12 +103,17 @@ load_program( void load_module( fs::file &disk, - const descriptor &desc) + const wchar_t *name, + const wchar_t *path, + bootproto::module_type type, + uint16_t subtype) { - status_line status(L"Loading module", desc.desc); + status_line status(L"Loading module", name); - util::buffer data = load_file(disk, desc); - create_module(data, desc, false); + bootproto::module *mod = g_alloc.allocate_module(); + mod->type = type; + mod->subtype = subtype; + mod->data = load_file(disk, path); } void diff --git a/src/boot/loader.h b/src/boot/loader.h index b72f94c..3f6d9c1 100644 --- a/src/boot/loader.h +++ b/src/boot/loader.h @@ -2,11 +2,11 @@ /// Definitions for loading the kernel into memory #pragma once +#include #include namespace bootproto { struct program; - struct module; } namespace boot { @@ -21,29 +21,35 @@ namespace loader { /// Load a file from disk into memory. /// \arg disk The opened UEFI filesystem to load from -/// \arg desc The program descriptor identifying the file +/// \arg path The path of the file to load util::buffer load_file( fs::file &disk, - const descriptor &desc); + const wchar_t *path); /// Parse and load an ELF file in memory into a loaded image. /// \arg disk The opened UEFI filesystem to load from /// \arg desc The descriptor identifying the program -/// \arg add_module Also create a module for this loaded program +/// \arg name The human-readable name of the program to load bootproto::program * load_program( fs::file &disk, - const descriptor &desc, - bool add_module = false); + const wchar_t *name, + const descriptor &desc); /// Load a file from disk into memory, creating an init args module -/// \arg disk The opened UEFI filesystem to load from -/// \arg desc The program descriptor identifying the file +/// \arg disk The opened UEFI filesystem to load from +/// \arg name The human-readable name of the module +/// \arg path The path of the file to load the module from +/// \arg type The major type to set on the module +/// \arg subtype The subtype to set on the module void load_module( fs::file &disk, - const descriptor &desc); + const wchar_t *name, + const wchar_t *path, + bootproto::module_type type, + uint16_t subtype); /// Verify that a loaded ELF has the j6 kernel header /// \arg program The program to check for a header diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 30c30af..fb418c2 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -75,48 +75,36 @@ load_resources(bootproto::args *args, video::screen *screen, uefi::handle image, fs::file bc_data = disk.open(L"jsix_boot.dat"); bootconfig bc {bc_data.load(), bs}; - args->kernel = loader::load_program(disk, bc.kernel(), true); - args->init = loader::load_program(disk, bc.init()); + args->kernel = loader::load_program(disk, L"kernel", bc.kernel()); + args->init = loader::load_program(disk, L"init server", bc.init()); args->flags = static_cast(bc.flags()); + loader::load_module(disk, L"initrd", bc.initrd(), + bootproto::module_type::initrd, bc.initrd_format()); + namespace bits = util::bits; using bootproto::desc_flags; if (screen) { video::make_module(screen); - // Go through the screen-specific descriptors first to - // give them priority - for (const descriptor &d : bc.programs()) { - if (!bits::has(d.flags, desc_flags::graphical)) - continue; - - if (bits::has(d.flags, desc_flags::panic)) - args->panic = loader::load_program(disk, d); - else - loader::load_module(disk, d); + // Find the screen-specific panic handler first to + // give it priority + for (const descriptor &d : bc.panics()) { + if (bits::has(d.flags, desc_flags::graphical)) { + args->panic = loader::load_program(disk, L"panic handler", d); + break; + } } } - // Load the non-graphical descriptors - for (const descriptor &d : bc.programs()) { - if (bits::has(d.flags, desc_flags::graphical)) - continue; - - if (bits::has(d.flags, desc_flags::panic) && !args->panic) - args->panic = loader::load_program(disk, d); - else - loader::load_module(disk, d); - } - - // For now the only data we load is the symbol table - for (const descriptor &d : bc.data()) { - if (!bits::has(d.flags, desc_flags::symbols)) - continue; - - util::buffer symbol_table = loader::load_file(disk, d); - args->symbol_table = symbol_table.pointer; - break; + if (!args->panic) { + for (const descriptor &d : bc.panics()) { + if (!bits::has(d.flags, desc_flags::graphical)) { + args->panic = loader::load_program(disk, L"panic handler", d); + break; + } + } } loader::verify_kernel_header(*args->kernel); diff --git a/src/boot/status.h b/src/boot/status.h index eacb4b8..cfcc506 100644 --- a/src/boot/status.h +++ b/src/boot/status.h @@ -4,6 +4,7 @@ #include #include +#include "video.h" namespace uefi { struct boot_services; @@ -11,10 +12,6 @@ namespace uefi { namespace boot { -namespace video { - struct screen; -} - // Abstract base class for status reporters. class status { diff --git a/src/boot/video.cpp b/src/boot/video.cpp index 9b0e73f..d2d6a2b 100644 --- a/src/boot/video.cpp +++ b/src/boot/video.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include "allocator.h" #include "console.h" #include "error.h" @@ -10,10 +12,7 @@ namespace boot { namespace video { -using bootproto::fb_layout; -using bootproto::fb_type; -using bootproto::module_flags; -using bootproto::module_framebuffer; +using bootproto::devices::fb_layout; using bootproto::module_type; static uefi::protos::graphics_output * @@ -70,7 +69,7 @@ pick_mode(uefi::boot_services *bs) .vertical = gop->mode->info->vertical_resolution, .horizontal = gop->mode->info->horizontal_resolution, .scanline = gop->mode->info->pixels_per_scanline, - .layout = layout::unknown, + .layout = fb_layout::unknown, }; s->framebuffer = { @@ -82,12 +81,12 @@ pick_mode(uefi::boot_services *bs) switch (info->pixel_format) { case uefi::pixel_format::rgb8: type = L"rgb8"; - s->mode.layout = layout::rgb8; + s->mode.layout = fb_layout::rgb8; break; case uefi::pixel_format::bgr8: type = L"bgr8"; - s->mode.layout = layout::bgr8; + s->mode.layout = fb_layout::bgr8; break; default: @@ -108,13 +107,22 @@ pick_mode(uefi::boot_services *bs) void make_module(screen *s) { - using bootproto::module_framebuffer; - module_framebuffer *modfb = g_alloc.allocate_module(); - modfb->mod_type = module_type::framebuffer; - modfb->type = fb_type::uefi; + using bootproto::module; + using bootproto::module_type; + using bootproto::device_type; + using bootproto::devices::uefi_fb; - modfb->framebuffer = s->framebuffer; - modfb->mode = s->mode; + uefi_fb *fb = new uefi_fb; + fb->framebuffer = s->framebuffer; + fb->mode = s->mode; + + module *mod = g_alloc.allocate_module(); + mod->type = module_type::device; + mod->subtype = static_cast(device_type::uefi_fb); + mod->data = { + .pointer = fb, + .count = sizeof(uefi_fb), + }; } } // namespace video diff --git a/src/boot/video.h b/src/boot/video.h index d3bc6bf..3873c47 100644 --- a/src/boot/video.h +++ b/src/boot/video.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include namespace uefi { @@ -15,13 +15,8 @@ namespace uefi { namespace boot { namespace video { -using bootproto::video_mode; -using layout = bootproto::fb_layout; - -struct screen { - util::buffer framebuffer; - video_mode mode; -}; +using layout = bootproto::devices::fb_layout; +using screen = bootproto::devices::uefi_fb; /// Pick the best video mode and set up the screen screen * pick_mode(uefi::boot_services *bs); diff --git a/src/libraries/bootproto/bootproto.module b/src/libraries/bootproto/bootproto.module index 6914858..1869fb5 100644 --- a/src/libraries/bootproto/bootproto.module +++ b/src/libraries/bootproto/bootproto.module @@ -4,6 +4,7 @@ bp = module("bootproto", kind = "lib", public_headers = [ "bootproto/bootconfig.h", + "bootproto/devices/framebuffer.h", "bootproto/init.h", "bootproto/kernel.h", "bootproto/memory.h.cog", diff --git a/src/libraries/bootproto/bootproto/bootconfig.h b/src/libraries/bootproto/bootproto/bootconfig.h index 89254fc..32721c7 100644 --- a/src/libraries/bootproto/bootproto/bootconfig.h +++ b/src/libraries/bootproto/bootproto/bootconfig.h @@ -8,9 +8,9 @@ namespace bootproto { enum class desc_flags : uint16_t { - graphical = 0x01, - panic = 0x02, - symbols = 0x04, + graphical = 0x0001, + panic = 0x0002, + symbols = 0x0004, }; is_bitfield(desc_flags); diff --git a/src/libraries/bootproto/bootproto/devices/framebuffer.h b/src/libraries/bootproto/bootproto/devices/framebuffer.h new file mode 100644 index 0000000..1df3f01 --- /dev/null +++ b/src/libraries/bootproto/bootproto/devices/framebuffer.h @@ -0,0 +1,28 @@ +#pragma once +/// \file bootproto/devices/uefi_fb.h +/// Data structures describing bootloader-passed framebuffer + +#include + +namespace bootproto { +namespace devices { + +enum class fb_layout : uint8_t { rgb8, bgr8, unknown = 0xff }; + +struct video_mode +{ + uint32_t vertical; + uint32_t horizontal; + uint32_t scanline; + fb_layout layout; +}; + +struct uefi_fb +{ + util::buffer framebuffer; + video_mode mode; +}; + + +} // namespace devices +} // namespace bootproto diff --git a/src/libraries/bootproto/bootproto/init.h b/src/libraries/bootproto/bootproto/init.h index 72061f9..46e429f 100644 --- a/src/libraries/bootproto/bootproto/init.h +++ b/src/libraries/bootproto/bootproto/init.h @@ -10,61 +10,30 @@ namespace bootproto { -enum class module_type : uint8_t { - none, - program, - framebuffer, -}; - -enum class module_flags : uint8_t { - none = 0x00, - - /// This module was already handled by the bootloader, - /// no action is needed. The module is included for - /// informational purposes only. - no_load = 0x01, -}; -is_bitfield(module_flags); +enum class module_type : uint8_t { none, initrd, device, }; +enum class initrd_format : uint8_t { none, zstd, }; +enum class device_type : uint16_t { none, uefi_fb, }; struct module { - module_type mod_type; - module_flags mod_flags; - uint32_t mod_length; + module_type type; + // 1 byte padding + uint16_t subtype; + // 4 bytes padding + util::buffer data; }; -struct module_program : - public module -{ - uintptr_t base_address; - size_t size; - char filename[]; -}; - -enum class fb_layout : uint8_t { rgb8, bgr8, unknown = 0xff }; -enum class fb_type : uint8_t { uefi }; - -struct video_mode -{ - uint32_t vertical; - uint32_t horizontal; - uint32_t scanline; - fb_layout layout; -}; - -struct module_framebuffer : - public module -{ - util::buffer framebuffer; - video_mode mode; - fb_type type; -}; - -struct modules_page +struct module_page_header { uint8_t count; - module *modules; uintptr_t next; }; +struct modules_page : + public module_page_header +{ + static constexpr unsigned per_page = (0x1000 - sizeof(module_page_header)) / sizeof(module); + module modules[per_page]; +}; + } // namespace bootproto diff --git a/src/user/drv.uart/uart.module b/src/user/drv.uart/uart.module index f9fbcb9..9f2562f 100644 --- a/src/user/drv.uart/uart.module +++ b/src/user/drv.uart/uart.module @@ -4,6 +4,7 @@ module("drv.uart", targets = [ "user" ], deps = [ "libc", "util" ], description = "UART driver", + drivers = [ "pc.uart" ], sources = [ "io.cpp", "main.cpp", diff --git a/src/user/drv.uefi_fb/uefi_fb.module b/src/user/drv.uefi_fb/uefi_fb.module index 3b3e25b..d747aab 100644 --- a/src/user/drv.uefi_fb/uefi_fb.module +++ b/src/user/drv.uefi_fb/uefi_fb.module @@ -4,6 +4,7 @@ module("drv.uefi_fb", targets = [ "user" ], deps = [ "libc" ], description = "UEFI framebuffer driver", + drivers = [ "uefi.fb" ], sources = [ "font.cpp", "main.cpp", diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index 8bc773a..4c1663d 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -9,8 +9,9 @@ #include #include -using bootproto::module_flags; -using bootproto::module_program; +#include "loader.h" + +using bootproto::module; extern j6_handle_t __handle_self; @@ -18,54 +19,62 @@ constexpr uintptr_t load_addr = 0xf8000000; constexpr size_t stack_size = 0x10000; constexpr uintptr_t stack_top = 0x80000000000; +j6_handle_t +map_phys(j6_handle_t sys, uintptr_t phys, size_t len, uintptr_t addr) +{ + j6_handle_t vma = j6_handle_invalid; + j6_status_t res = j6_system_map_phys(sys, &vma, phys, len, 0); + if (res != j6_status_ok) + return j6_handle_invalid; + + if (!addr) + addr = phys; + + res = j6_vma_map(vma, __handle_self, addr); + if (res != j6_status_ok) + return j6_handle_invalid; + + return vma; +} + bool load_program( - const module_program &prog, + const char *name, + uintptr_t base_address, + size_t size, j6_handle_t sys, j6_handle_t slp, char *err_msg) { - if (prog.mod_flags && module_flags::no_load) { - sprintf(err_msg, " skipping pre-loaded program module '%s' at %lx", prog.filename, prog.base_address); - return true; - } - - j6_handle_t elf_vma = j6_handle_invalid; - j6_status_t res = j6_system_map_phys(sys, &elf_vma, prog.base_address, prog.size, 0); - if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': creating physical vma: %lx", prog.filename, res); + j6_handle_t elf_vma = map_phys(sys, base_address, size); + if (elf_vma == j6_handle_invalid) { + sprintf(err_msg, " ** error loading program '%s': creating physical vma", name); return false; } - res = j6_vma_map(elf_vma, __handle_self, prog.base_address); - if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': mapping vma: %lx", prog.filename, res); - return false; - } - - const void *addr = reinterpret_cast(prog.base_address); - elf::file progelf {addr, prog.size}; + const void *addr = reinterpret_cast(base_address); + elf::file progelf {addr, size}; if (!progelf.valid()) { - sprintf(err_msg, " ** error loading program '%s': ELF is invalid", prog.filename); + sprintf(err_msg, " ** error loading program '%s': ELF is invalid", name); return false; } j6_handle_t proc = j6_handle_invalid; - res = j6_process_create(&proc); + j6_status_t res = j6_process_create(&proc); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': creating process: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': creating process: %lx", name, res); return false; } res = j6_process_give_handle(proc, sys); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': giving system handle: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': giving system handle: %lx", name, res); return false; } res = j6_process_give_handle(proc, slp); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': giving SLP handle: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': giving SLP handle: %lx", name, res); return false; } @@ -79,14 +88,14 @@ load_program( if (seg.flags && elf::segment_flags::exec) flags |= j6_vm_flag_exec; - uintptr_t start = prog.base_address + seg.offset; + uintptr_t start = base_address + seg.offset; size_t prologue = start & 0xfff; size_t epilogue = seg.mem_size - (prologue+seg.file_size); j6_handle_t sub_vma = j6_handle_invalid; res = j6_vma_create_map(&sub_vma, seg.mem_size+prologue, load_addr, flags); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': creating sub vma: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': creating sub vma: %lx", name, res); return false; } @@ -98,13 +107,13 @@ load_program( res = j6_vma_map(sub_vma, proc, seg.vaddr & ~0xfffull); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': mapping sub vma to child: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': mapping sub vma to child: %lx", name, res); return false; } res = j6_vma_unmap(sub_vma, __handle_self); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': unmapping sub vma: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': unmapping sub vma: %lx", name, res); return false; } } @@ -112,7 +121,7 @@ load_program( j6_handle_t stack_vma = j6_handle_invalid; res = j6_vma_create_map(&stack_vma, stack_size, load_addr, j6_vm_flag_write); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': creating stack vma: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': creating stack vma: %lx", name, res); return false; } @@ -121,26 +130,26 @@ load_program( res = j6_vma_map(stack_vma, proc, stack_top-stack_size); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': mapping stack vma: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': mapping stack vma: %lx", name, res); return false; } res = j6_vma_unmap(stack_vma, __handle_self); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': unmapping stack vma: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': unmapping stack vma: %lx", name, res); return false; } j6_handle_t thread = j6_handle_invalid; res = j6_thread_create(&thread, proc, stack_top - 6*sizeof(uint64_t), progelf.entrypoint()); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': creating thread: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': creating thread: %lx", name, res); return false; } res = j6_vma_unmap(elf_vma, __handle_self); if (res != j6_status_ok) { - sprintf(err_msg, " ** error loading program '%s': unmapping elf vma: %lx", prog.filename, res); + sprintf(err_msg, " ** error loading program '%s': unmapping elf vma: %lx", name, res); return false; } diff --git a/src/user/srv.init/loader.h b/src/user/srv.init/loader.h index 3f6b0f4..f9a5cdf 100644 --- a/src/user/srv.init/loader.h +++ b/src/user/srv.init/loader.h @@ -12,3 +12,9 @@ bool load_program( const bootproto::module_program &prog, j6_handle_t sys, j6_handle_t slp, char *err_msg); + +j6_handle_t map_phys(j6_handle_t sys, uintptr_t phys, size_t len, uintptr_t addr = 0); + +inline j6_handle_t map_phys(j6_handle_t sys, void *phys, size_t len, uintptr_t addr = 0) { + return map_phys(sys, reinterpret_cast(phys), len, addr); +} diff --git a/src/user/srv.init/main.cpp b/src/user/srv.init/main.cpp index 7020ab6..e0d1147 100644 --- a/src/user/srv.init/main.cpp +++ b/src/user/srv.init/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -10,11 +11,11 @@ #include "loader.h" #include "modules.h" +#include "ramdisk.h" #include "service_locator.h" using bootproto::module; using bootproto::module_type; -using bootproto::module_program; extern "C" { int main(int, const char **); @@ -61,19 +62,38 @@ main(int argc, const char **argv) modules mods = modules::load_modules(_arg_modules_phys, sys, __handle_self); - for (auto &mod : mods.of_type(module_type::program)) { - auto &prog = static_cast(mod); + module const *initrd_module; + std::vector devices; - char message[100]; - sprintf(message, " loading program module '%s' at %lx", prog.filename, prog.base_address); - j6_log(message); + for (auto &mod : mods) { + switch (mod.type) { + case module_type::initrd: + initrd_module = &mod; + break; - if (!load_program(prog, sys_child, slp_mb_child, message)) { - j6_log(message); - return 2; + case module_type::device: + devices.push_back(&mod); + break; + + default: + // Unknown module?? + break; } } + if (!initrd_module) + return 1; + + j6_handle_t initrd_vma = + map_phys(sys, initrd_module->data.pointer, initrd_module->data.count); + if (initrd_vma == j6_handle_invalid) { + j6_log(" ** error loading ramdisk: mapping physical vma"); + return 1; + } + + ramdisk initrd {initrd_module->data}; + util::buffer manifest = initrd.load_file("init.manifest"); + service_locator_start(slp_mb); return 0; } diff --git a/src/user/srv.init/modules.cpp b/src/user/srv.init/modules.cpp index 137c41f..41d375c 100644 --- a/src/user/srv.init/modules.cpp +++ b/src/user/srv.init/modules.cpp @@ -20,28 +20,24 @@ const module * module_iterator::operator++() { do { - m_mod = util::offset_pointer(m_mod, m_mod->mod_length); - - if (m_mod->mod_type == type::none) { + if (++m_idx >= modules_page::per_page) { // We've reached the end of a page, see if there's another - const modules_page *page = get_page(m_mod); - if (!page->next) { - m_mod = nullptr; + if (!m_page->next) { + m_page = nullptr; break; } - - m_mod = page->modules; + m_idx = 0; + m_page = reinterpret_cast(m_page->next); } } - while (m_type != type::none && m_type != m_mod->mod_type); - - return m_mod; + while (m_type != type::none && m_type != deref()->type); + return deref(); } const module * module_iterator::operator++(int) { - const module *tmp = m_mod; + const module *tmp = deref(); operator++(); return tmp; } @@ -64,7 +60,7 @@ load_page(uintptr_t address, j6_handle_t system, j6_handle_t self) modules modules::load_modules(uintptr_t address, j6_handle_t system, j6_handle_t self) { - const module *first = nullptr; + const modules_page *first = nullptr; while (address) { const modules_page *page = load_page(address, system, self); @@ -73,7 +69,7 @@ modules::load_modules(uintptr_t address, j6_handle_t system, j6_handle_t self) j6_log(message); if (!first) - first = page->modules; + first = page; address = page->next; } diff --git a/src/user/srv.init/modules.h b/src/user/srv.init/modules.h index 3e160fe..945660d 100644 --- a/src/user/srv.init/modules.h +++ b/src/user/srv.init/modules.h @@ -13,27 +13,32 @@ public: using type = bootproto::module_type; using module = bootproto::module; - module_iterator(const module *m, type t = type::none) : - m_mod {m}, m_type {t} {} + module_iterator(const bootproto::modules_page *p, unsigned i, type t = type::none) : + m_page {p}, m_idx {i}, m_type {t} { + if ( t != type::none && p && deref()->type != t ) operator++(); + } const module * operator++(); const module * operator++(int); - bool operator==(const module* m) const { return m == m_mod; } - bool operator!=(const module* m) const { return m != m_mod; } - bool operator==(const module_iterator &i) const { return i.m_mod == m_mod; } - bool operator!=(const module_iterator &i) const { return i.m_mod != m_mod; } + bool operator==(const module* m) const { return m == deref(); } + bool operator!=(const module* m) const { return m != deref(); } + bool operator==(const module_iterator &i) const { return i.deref() == deref(); } + bool operator!=(const module_iterator &i) const { return i.deref() != deref(); } - const module & operator*() const { return *m_mod; } - operator const module & () const { return *m_mod; } - const module * operator->() const { return m_mod; } + const module & operator*() const { return *deref(); } + operator const module & () const { return *deref(); } + const module * operator->() const { return deref(); } // Allow iterators to be used in for(:) statments module_iterator & begin() { return *this; } - module_iterator end() const { return nullptr; } + module_iterator end() const { return {nullptr, 0}; } private: - module const * m_mod; + inline const module * deref() const { return m_page ? &m_page->modules[m_idx] : nullptr; } + + unsigned m_idx; + bootproto::modules_page const *m_page; type m_type; }; @@ -48,15 +53,15 @@ public: j6_handle_t system, j6_handle_t self); - iterator of_type(type t) const { return iterator {m_root, t}; } + iterator of_type(type t) const { return iterator {m_root, 0, t}; } - iterator begin() const { return iterator {m_root}; } - iterator end() const { return nullptr; } + iterator begin() const { return iterator {m_root, 0}; } + iterator end() const { return {nullptr, 0}; } private: using module = bootproto::module; - modules(const module* root) : m_root {root} {} + modules(const bootproto::modules_page* root) : m_root {root} {} - const module *m_root; + const bootproto::modules_page *m_root; };