[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:
@@ -73,7 +73,6 @@ allocator::add_modules()
|
||||
if (m_modules)
|
||||
m_modules->next = reinterpret_cast<uintptr_t>(mods);
|
||||
|
||||
mods->modules = reinterpret_cast<module*>(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<uintptr_t>(m_modules) + page_size
|
||||
- reinterpret_cast<uintptr_t>(m_next_mod);
|
||||
- reinterpret_cast<uintptr_t>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,10 +32,7 @@ public:
|
||||
|
||||
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
||||
|
||||
template <typename M>
|
||||
M * allocate_module(size_t extra = 0) {
|
||||
return static_cast<M*>(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;
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ read_descriptor(descriptor &e, util::buffer &data)
|
||||
{
|
||||
e.flags = static_cast<desc_flags>(*util::read<uint16_t>(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<uint8_t>(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<uint16_t>(data);
|
||||
uint16_t num_data = *util::read<uint16_t>(data);
|
||||
|
||||
uint16_t num_panics = *util::read<uint16_t>(data);
|
||||
m_initrd_format = *util::read<uint16_t>(data);
|
||||
m_flags = *util::read<uint16_t>(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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<bootproto::module_program>(path_len);
|
||||
mod->mod_type = bootproto::module_type::program;
|
||||
mod->base_address = reinterpret_cast<uintptr_t>(data.pointer);
|
||||
mod->size = data.count;
|
||||
if (loaded)
|
||||
mod->mod_flags = static_cast<bootproto::module_flags>(
|
||||
static_cast<uint8_t>(mod->mod_flags) |
|
||||
static_cast<uint8_t>(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
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
/// Definitions for loading the kernel into memory
|
||||
#pragma once
|
||||
|
||||
#include <bootproto/init.h>
|
||||
#include <util/counted.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -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<bootproto::boot_flags>(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);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <uefi/types.h>
|
||||
#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
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include <uefi/graphics.h>
|
||||
#include <uefi/protos/graphics_output.h>
|
||||
|
||||
#include <bootproto/init.h>
|
||||
|
||||
#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<module_framebuffer>();
|
||||
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<uint16_t>(device_type::uefi_fb);
|
||||
mod->data = {
|
||||
.pointer = fb,
|
||||
.count = sizeof(uefi_fb),
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace video
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <bootproto/init.h>
|
||||
#include <bootproto/devices/framebuffer.h>
|
||||
#include <util/counted.h>
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user