mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[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:
@@ -1,8 +1,12 @@
|
|||||||
---
|
---
|
||||||
|
location: jsix
|
||||||
init: srv.init
|
init: srv.init
|
||||||
programs:
|
initrd:
|
||||||
- name: panic.serial
|
name: initrd.dat
|
||||||
target: kernel
|
format: zstd
|
||||||
flags: panic
|
panic:
|
||||||
- name: srv.logger
|
- panic.serial
|
||||||
- name: drv.uart
|
services:
|
||||||
|
- srv.logger
|
||||||
|
drivers:
|
||||||
|
- drv.uart
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
---
|
---
|
||||||
|
location: jsix
|
||||||
init: srv.init
|
init: srv.init
|
||||||
|
initrd:
|
||||||
|
name: initrd.dat
|
||||||
|
format: zstd
|
||||||
flags: ["test"]
|
flags: ["test"]
|
||||||
programs:
|
panic:
|
||||||
- name: panic.serial
|
- panic.serial
|
||||||
target: kernel
|
services:
|
||||||
flags: panic
|
- test_runner
|
||||||
- name: drv.uart
|
drivers:
|
||||||
- name: test_runner
|
- drv.uart
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ from . import BonnibelError
|
|||||||
|
|
||||||
class Manifest:
|
class Manifest:
|
||||||
from collections import namedtuple
|
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 = {
|
flags = {
|
||||||
"graphical": 0x01,
|
"graphical": 0x01,
|
||||||
"panic": 0x02,
|
"symbols": 0x80,
|
||||||
"symbols": 0x04,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boot_flags = {
|
boot_flags = {
|
||||||
@@ -20,6 +24,8 @@ class Manifest:
|
|||||||
|
|
||||||
config = load_config(path)
|
config = load_config(path)
|
||||||
|
|
||||||
|
self.location = config.get("location", "jsix")
|
||||||
|
|
||||||
self.kernel = self.__build_entry(modules,
|
self.kernel = self.__build_entry(modules,
|
||||||
config.get("kernel", dict()),
|
config.get("kernel", dict()),
|
||||||
name="kernel", target="kernel")
|
name="kernel", target="kernel")
|
||||||
@@ -27,11 +33,24 @@ class Manifest:
|
|||||||
self.init = self.__build_entry(modules,
|
self.init = self.__build_entry(modules,
|
||||||
config.get("init", None))
|
config.get("init", None))
|
||||||
|
|
||||||
self.programs = [self.__build_entry(modules, i)
|
self.panics = [self.__build_entry(modules, i, target="kernel")
|
||||||
for i in config.get("programs", tuple())]
|
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())
|
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 = []
|
self.data = []
|
||||||
for d in config.get("data", tuple()):
|
for d in config.get("data", tuple()):
|
||||||
self.add_data(**d)
|
self.add_data(**d)
|
||||||
@@ -56,10 +75,10 @@ class Manifest:
|
|||||||
if not f in Manifest.flags:
|
if not f in Manifest.flags:
|
||||||
raise BonnibelError(f"Manifest specifies unknown flag '{f}'")
|
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()):
|
def add_data(self, output, desc, flags=tuple()):
|
||||||
e = Manifest.Entry(None, None, output, location, desc, flags)
|
e = Manifest.Entry(None, None, output, flags)
|
||||||
self.data.append(e)
|
self.data.append(e)
|
||||||
return e
|
return e
|
||||||
|
|
||||||
@@ -69,35 +88,83 @@ class Manifest:
|
|||||||
|
|
||||||
with open(path, 'wb') as outfile:
|
with open(path, 'wb') as outfile:
|
||||||
magic = "jsixboot".encode("utf-8") # magic string
|
magic = "jsixboot".encode("utf-8") # magic string
|
||||||
version = 0
|
version = 1
|
||||||
reserved = 0
|
reserved = 0
|
||||||
|
|
||||||
|
initrd_format = Manifest.formats.get(self.initrd_format, 0)
|
||||||
bootflags = sum([Manifest.boot_flags.get(s, 0) for s in self.flags])
|
bootflags = sum([Manifest.boot_flags.get(s, 0) for s in self.flags])
|
||||||
|
|
||||||
outfile.write(struct.pack("<8sBBHHH",
|
outfile.write(struct.pack("<8s BBH HH",
|
||||||
magic, version, reserved,
|
magic,
|
||||||
len(self.programs), len(self.data),
|
version, reserved, len(self.panics),
|
||||||
bootflags))
|
initrd_format, bootflags))
|
||||||
|
|
||||||
def write_str(s):
|
def write_str(s):
|
||||||
outfile.write(struct.pack("<H", (len(s)+1)*2))
|
data = s.encode("utf-16le")
|
||||||
outfile.write(s.encode("utf-16le"))
|
outfile.write(struct.pack("<H", len(data)+2))
|
||||||
|
outfile.write(data)
|
||||||
outfile.write(b"\0\0")
|
outfile.write(b"\0\0")
|
||||||
|
|
||||||
|
def write_path(name):
|
||||||
|
write_str(join(self.location, name).replace('/','\\'))
|
||||||
|
|
||||||
def write_ent(ent):
|
def write_ent(ent):
|
||||||
flags = 0
|
flags = 0
|
||||||
for f in ent.flags:
|
for f in ent.flags:
|
||||||
flags |= Manifest.flags[f]
|
flags |= Manifest.flags[f]
|
||||||
|
|
||||||
outfile.write(struct.pack("<H", flags))
|
outfile.write(struct.pack("<H", flags))
|
||||||
write_str(join(ent.location, ent.output).replace('/','\\'))
|
write_path(ent.output)
|
||||||
write_str(ent.description)
|
|
||||||
|
|
||||||
write_ent(self.kernel)
|
write_ent(self.kernel)
|
||||||
write_ent(self.init)
|
write_ent(self.init)
|
||||||
|
write_path(self.initrd)
|
||||||
|
|
||||||
for p in self.programs:
|
for p in self.panics:
|
||||||
write_ent(p)
|
write_ent(p)
|
||||||
|
|
||||||
for d in self.data:
|
def write_init_config(self, path, modules):
|
||||||
write_ent(d)
|
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))
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ class Module:
|
|||||||
"public_headers": (set, ()),
|
"public_headers": (set, ()),
|
||||||
"includes": (tuple, ()),
|
"includes": (tuple, ()),
|
||||||
"sources": (tuple, ()),
|
"sources": (tuple, ()),
|
||||||
|
"drivers": (tuple, ()),
|
||||||
"variables": (dict, ()),
|
"variables": (dict, ()),
|
||||||
"default": (bool, False),
|
"default": (bool, False),
|
||||||
"location": (str, "jsix"),
|
|
||||||
"description": (str, None),
|
"description": (str, None),
|
||||||
"no_libc": (bool, False),
|
"no_libc": (bool, False),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,9 +71,13 @@ class Project:
|
|||||||
fatroot.mkdir(exist_ok=True)
|
fatroot.mkdir(exist_ok=True)
|
||||||
|
|
||||||
fatroot_content = []
|
fatroot_content = []
|
||||||
|
initrd_content = []
|
||||||
|
|
||||||
|
from .manifest import Manifest
|
||||||
|
manifest = Manifest(manifest_file, modules)
|
||||||
|
|
||||||
def add_fatroot(source, entry):
|
def add_fatroot(source, entry):
|
||||||
output = join(entry.location, entry.output)
|
output = join(manifest.location, entry.output)
|
||||||
fatroot_output = f"${{build_root}}/fatroot/{output}"
|
fatroot_output = f"${{build_root}}/fatroot/{output}"
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
@@ -103,16 +107,30 @@ class Project:
|
|||||||
|
|
||||||
add_fatroot(intermediary, entry)
|
add_fatroot(intermediary, entry)
|
||||||
|
|
||||||
from .manifest import Manifest
|
def add_initrd_exe(entry):
|
||||||
manifest = Manifest(manifest_file, modules)
|
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.kernel)
|
||||||
add_fatroot_exe(manifest.init)
|
add_fatroot_exe(manifest.init)
|
||||||
for program in manifest.programs:
|
for program in manifest.panics: add_fatroot_exe(program)
|
||||||
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",
|
syms = manifest.add_data("symbol_table.dat",
|
||||||
manifest.kernel.location, "Symbol table", ("symbols",))
|
"Symbol table", ("symbols",))
|
||||||
|
|
||||||
sym_out = f"${{build_root}}/symbol_table.dat"
|
sym_out = f"${{build_root}}/symbol_table.dat"
|
||||||
build.build(
|
build.build(
|
||||||
@@ -120,7 +138,7 @@ class Project:
|
|||||||
outputs = [sym_out],
|
outputs = [sym_out],
|
||||||
inputs = [f"${{build_root}}/{modules['kernel'].output}"],
|
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"
|
bootloader = "${build_root}/fatroot/efi/boot/bootx64.efi"
|
||||||
build.build(
|
build.build(
|
||||||
@@ -132,8 +150,20 @@ class Project:
|
|||||||
})
|
})
|
||||||
build.newline()
|
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_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(
|
build.build(
|
||||||
rule = "makefat",
|
rule = "makefat",
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ allocator::add_modules()
|
|||||||
if (m_modules)
|
if (m_modules)
|
||||||
m_modules->next = reinterpret_cast<uintptr_t>(mods);
|
m_modules->next = reinterpret_cast<uintptr_t>(mods);
|
||||||
|
|
||||||
mods->modules = reinterpret_cast<module*>(mods + 1);
|
|
||||||
m_modules = mods;
|
m_modules = mods;
|
||||||
m_next_mod = mods->modules;
|
m_next_mod = mods->modules;
|
||||||
return;
|
return;
|
||||||
@@ -110,11 +109,13 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero)
|
|||||||
}
|
}
|
||||||
|
|
||||||
module *
|
module *
|
||||||
allocator::allocate_module_untyped(size_t size)
|
allocator::allocate_module()
|
||||||
{
|
{
|
||||||
|
static constexpr size_t size = sizeof(module);
|
||||||
|
|
||||||
size_t remaining =
|
size_t remaining =
|
||||||
reinterpret_cast<uintptr_t>(m_modules) + page_size
|
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)
|
if (size > remaining)
|
||||||
add_modules();
|
add_modules();
|
||||||
@@ -122,8 +123,6 @@ allocator::allocate_module_untyped(size_t size)
|
|||||||
++m_modules->count;
|
++m_modules->count;
|
||||||
module *m = m_next_mod;
|
module *m = m_next_mod;
|
||||||
m_next_mod = util::offset_pointer(m_next_mod, size);
|
m_next_mod = util::offset_pointer(m_next_mod, size);
|
||||||
|
|
||||||
m->mod_length = size;
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,10 +32,7 @@ public:
|
|||||||
|
|
||||||
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
||||||
|
|
||||||
template <typename M>
|
module * allocate_module();
|
||||||
M * allocate_module(size_t extra = 0) {
|
|
||||||
return static_cast<M*>(allocate_module_untyped(sizeof(M) + extra));
|
|
||||||
}
|
|
||||||
|
|
||||||
void memset(void *start, size_t size, uint8_t value);
|
void memset(void *start, size_t size, uint8_t value);
|
||||||
void copy(void *to, void *from, size_t size);
|
void copy(void *to, void *from, size_t size);
|
||||||
@@ -54,7 +51,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
void add_register();
|
void add_register();
|
||||||
void add_modules();
|
void add_modules();
|
||||||
module * allocate_module_untyped(size_t size);
|
|
||||||
|
|
||||||
uefi::boot_services &m_bs;
|
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.flags = static_cast<desc_flags>(*util::read<uint16_t>(data));
|
||||||
e.path = read_string(data);
|
e.path = read_string(data);
|
||||||
e.desc = read_string(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bootconfig::bootconfig(util::buffer data, uefi::boot_services *bs)
|
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");
|
error::raise(uefi::status::load_error, L"Bad header in jsix_boot.dat");
|
||||||
|
|
||||||
const uint8_t version = *util::read<uint8_t>(data);
|
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");
|
error::raise(uefi::status::incompatible_version, L"Bad version in jsix_boot.dat");
|
||||||
|
|
||||||
data += 1; // reserved byte
|
data += 1; // reserved byte
|
||||||
uint16_t num_programs = *util::read<uint16_t>(data);
|
uint16_t num_panics = *util::read<uint16_t>(data);
|
||||||
uint16_t num_data = *util::read<uint16_t>(data);
|
m_initrd_format = *util::read<uint16_t>(data);
|
||||||
|
|
||||||
m_flags = *util::read<uint16_t>(data);
|
m_flags = *util::read<uint16_t>(data);
|
||||||
|
|
||||||
read_descriptor(m_kernel, data);
|
read_descriptor(m_kernel, data);
|
||||||
read_descriptor(m_init, data);
|
read_descriptor(m_init, data);
|
||||||
|
m_initrd = read_string(data);
|
||||||
|
|
||||||
m_programs.count = num_programs;
|
m_panics.count = num_panics;
|
||||||
m_programs.pointer = new descriptor [num_programs];
|
m_panics.pointer = new descriptor [num_panics];
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_programs; ++i)
|
for (unsigned i = 0; i < num_panics; ++i)
|
||||||
read_descriptor(m_programs[i], data);
|
read_descriptor(m_panics[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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace boot
|
} // namespace boot
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ using desc_flags = bootproto::desc_flags;
|
|||||||
struct descriptor {
|
struct descriptor {
|
||||||
desc_flags flags;
|
desc_flags flags;
|
||||||
wchar_t const *path;
|
wchar_t const *path;
|
||||||
wchar_t const *desc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A bootconfig is a manifest of potential files.
|
/// A bootconfig is a manifest of potential files.
|
||||||
@@ -31,15 +30,17 @@ public:
|
|||||||
inline uint16_t flags() const { return m_flags; }
|
inline uint16_t flags() const { return m_flags; }
|
||||||
inline const descriptor & kernel() const { return m_kernel; }
|
inline const descriptor & kernel() const { return m_kernel; }
|
||||||
inline const descriptor & init() const { return m_init; }
|
inline const descriptor & init() const { return m_init; }
|
||||||
descriptors programs() { return m_programs; }
|
inline const wchar_t * initrd() const { return m_initrd; }
|
||||||
descriptors data() { return m_data; }
|
inline uint16_t initrd_format() const { return m_initrd_format; }
|
||||||
|
inline const descriptors & panics() { return m_panics; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t m_flags;
|
uint16_t m_flags;
|
||||||
|
uint16_t m_initrd_format;
|
||||||
descriptor m_kernel;
|
descriptor m_kernel;
|
||||||
descriptor m_init;
|
descriptor m_init;
|
||||||
descriptors m_programs;
|
descriptors m_panics;
|
||||||
descriptors m_data;
|
wchar_t const *m_initrd;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace boot
|
} // namespace boot
|
||||||
|
|||||||
@@ -24,52 +24,26 @@ using memory::alloc_type;
|
|||||||
util::buffer
|
util::buffer
|
||||||
load_file(
|
load_file(
|
||||||
fs::file &disk,
|
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();
|
util::buffer b = file.load();
|
||||||
|
|
||||||
//console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
//console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
||||||
return b;
|
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 *
|
bootproto::program *
|
||||||
load_program(
|
load_program(
|
||||||
fs::file &disk,
|
fs::file &disk,
|
||||||
const descriptor &desc,
|
const wchar_t *name,
|
||||||
bool add_module)
|
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);
|
util::buffer data = load_file(disk, desc.path);
|
||||||
|
|
||||||
if (add_module)
|
|
||||||
create_module(data, desc, true);
|
|
||||||
|
|
||||||
elf::file program(data.pointer, data.count);
|
elf::file program(data.pointer, data.count);
|
||||||
if (!program.valid()) {
|
if (!program.valid()) {
|
||||||
@@ -129,12 +103,17 @@ load_program(
|
|||||||
void
|
void
|
||||||
load_module(
|
load_module(
|
||||||
fs::file &disk,
|
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);
|
bootproto::module *mod = g_alloc.allocate_module();
|
||||||
create_module(data, desc, false);
|
mod->type = type;
|
||||||
|
mod->subtype = subtype;
|
||||||
|
mod->data = load_file(disk, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
/// Definitions for loading the kernel into memory
|
/// Definitions for loading the kernel into memory
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <bootproto/init.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
|
|
||||||
namespace bootproto {
|
namespace bootproto {
|
||||||
struct program;
|
struct program;
|
||||||
struct module;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
@@ -21,29 +21,35 @@ namespace loader {
|
|||||||
|
|
||||||
/// Load a file from disk into memory.
|
/// Load a file from disk into memory.
|
||||||
/// \arg disk The opened UEFI filesystem to load from
|
/// \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
|
util::buffer
|
||||||
load_file(
|
load_file(
|
||||||
fs::file &disk,
|
fs::file &disk,
|
||||||
const descriptor &desc);
|
const wchar_t *path);
|
||||||
|
|
||||||
/// Parse and load an ELF file in memory into a loaded image.
|
/// Parse and load an ELF file in memory into a loaded image.
|
||||||
/// \arg disk The opened UEFI filesystem to load from
|
/// \arg disk The opened UEFI filesystem to load from
|
||||||
/// \arg desc The descriptor identifying the program
|
/// \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 *
|
bootproto::program *
|
||||||
load_program(
|
load_program(
|
||||||
fs::file &disk,
|
fs::file &disk,
|
||||||
const descriptor &desc,
|
const wchar_t *name,
|
||||||
bool add_module = false);
|
const descriptor &desc);
|
||||||
|
|
||||||
/// Load a file from disk into memory, creating an init args module
|
/// Load a file from disk into memory, creating an init args module
|
||||||
/// \arg disk The opened UEFI filesystem to load from
|
/// \arg disk The opened UEFI filesystem to load from
|
||||||
/// \arg desc The program descriptor identifying the file
|
/// \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
|
void
|
||||||
load_module(
|
load_module(
|
||||||
fs::file &disk,
|
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
|
/// Verify that a loaded ELF has the j6 kernel header
|
||||||
/// \arg program The program to check for a 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");
|
fs::file bc_data = disk.open(L"jsix_boot.dat");
|
||||||
bootconfig bc {bc_data.load(), bs};
|
bootconfig bc {bc_data.load(), bs};
|
||||||
|
|
||||||
args->kernel = loader::load_program(disk, bc.kernel(), true);
|
args->kernel = loader::load_program(disk, L"kernel", bc.kernel());
|
||||||
args->init = loader::load_program(disk, bc.init());
|
args->init = loader::load_program(disk, L"init server", bc.init());
|
||||||
args->flags = static_cast<bootproto::boot_flags>(bc.flags());
|
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;
|
namespace bits = util::bits;
|
||||||
using bootproto::desc_flags;
|
using bootproto::desc_flags;
|
||||||
|
|
||||||
if (screen) {
|
if (screen) {
|
||||||
video::make_module(screen);
|
video::make_module(screen);
|
||||||
|
|
||||||
// Go through the screen-specific descriptors first to
|
// Find the screen-specific panic handler first to
|
||||||
// give them priority
|
// give it priority
|
||||||
for (const descriptor &d : bc.programs()) {
|
for (const descriptor &d : bc.panics()) {
|
||||||
if (!bits::has(d.flags, desc_flags::graphical))
|
if (bits::has(d.flags, desc_flags::graphical)) {
|
||||||
continue;
|
args->panic = loader::load_program(disk, L"panic handler", d);
|
||||||
|
break;
|
||||||
if (bits::has(d.flags, desc_flags::panic))
|
}
|
||||||
args->panic = loader::load_program(disk, d);
|
|
||||||
else
|
|
||||||
loader::load_module(disk, d);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the non-graphical descriptors
|
if (!args->panic) {
|
||||||
for (const descriptor &d : bc.programs()) {
|
for (const descriptor &d : bc.panics()) {
|
||||||
if (bits::has(d.flags, desc_flags::graphical))
|
if (!bits::has(d.flags, desc_flags::graphical)) {
|
||||||
continue;
|
args->panic = loader::load_program(disk, L"panic handler", d);
|
||||||
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loader::verify_kernel_header(*args->kernel);
|
loader::verify_kernel_header(*args->kernel);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <uefi/types.h>
|
#include <uefi/types.h>
|
||||||
|
#include "video.h"
|
||||||
|
|
||||||
namespace uefi {
|
namespace uefi {
|
||||||
struct boot_services;
|
struct boot_services;
|
||||||
@@ -11,10 +12,6 @@ namespace uefi {
|
|||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
|
|
||||||
namespace video {
|
|
||||||
struct screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abstract base class for status reporters.
|
// Abstract base class for status reporters.
|
||||||
class status
|
class status
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#include <uefi/graphics.h>
|
#include <uefi/graphics.h>
|
||||||
#include <uefi/protos/graphics_output.h>
|
#include <uefi/protos/graphics_output.h>
|
||||||
|
|
||||||
|
#include <bootproto/init.h>
|
||||||
|
|
||||||
#include "allocator.h"
|
#include "allocator.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
@@ -10,10 +12,7 @@
|
|||||||
namespace boot {
|
namespace boot {
|
||||||
namespace video {
|
namespace video {
|
||||||
|
|
||||||
using bootproto::fb_layout;
|
using bootproto::devices::fb_layout;
|
||||||
using bootproto::fb_type;
|
|
||||||
using bootproto::module_flags;
|
|
||||||
using bootproto::module_framebuffer;
|
|
||||||
using bootproto::module_type;
|
using bootproto::module_type;
|
||||||
|
|
||||||
static uefi::protos::graphics_output *
|
static uefi::protos::graphics_output *
|
||||||
@@ -70,7 +69,7 @@ pick_mode(uefi::boot_services *bs)
|
|||||||
.vertical = gop->mode->info->vertical_resolution,
|
.vertical = gop->mode->info->vertical_resolution,
|
||||||
.horizontal = gop->mode->info->horizontal_resolution,
|
.horizontal = gop->mode->info->horizontal_resolution,
|
||||||
.scanline = gop->mode->info->pixels_per_scanline,
|
.scanline = gop->mode->info->pixels_per_scanline,
|
||||||
.layout = layout::unknown,
|
.layout = fb_layout::unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
s->framebuffer = {
|
s->framebuffer = {
|
||||||
@@ -82,12 +81,12 @@ pick_mode(uefi::boot_services *bs)
|
|||||||
switch (info->pixel_format) {
|
switch (info->pixel_format) {
|
||||||
case uefi::pixel_format::rgb8:
|
case uefi::pixel_format::rgb8:
|
||||||
type = L"rgb8";
|
type = L"rgb8";
|
||||||
s->mode.layout = layout::rgb8;
|
s->mode.layout = fb_layout::rgb8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case uefi::pixel_format::bgr8:
|
case uefi::pixel_format::bgr8:
|
||||||
type = L"bgr8";
|
type = L"bgr8";
|
||||||
s->mode.layout = layout::bgr8;
|
s->mode.layout = fb_layout::bgr8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -108,13 +107,22 @@ pick_mode(uefi::boot_services *bs)
|
|||||||
void
|
void
|
||||||
make_module(screen *s)
|
make_module(screen *s)
|
||||||
{
|
{
|
||||||
using bootproto::module_framebuffer;
|
using bootproto::module;
|
||||||
module_framebuffer *modfb = g_alloc.allocate_module<module_framebuffer>();
|
using bootproto::module_type;
|
||||||
modfb->mod_type = module_type::framebuffer;
|
using bootproto::device_type;
|
||||||
modfb->type = fb_type::uefi;
|
using bootproto::devices::uefi_fb;
|
||||||
|
|
||||||
modfb->framebuffer = s->framebuffer;
|
uefi_fb *fb = new uefi_fb;
|
||||||
modfb->mode = s->mode;
|
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
|
} // namespace video
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <bootproto/init.h>
|
#include <bootproto/devices/framebuffer.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
|
|
||||||
namespace uefi {
|
namespace uefi {
|
||||||
@@ -15,13 +15,8 @@ namespace uefi {
|
|||||||
namespace boot {
|
namespace boot {
|
||||||
namespace video {
|
namespace video {
|
||||||
|
|
||||||
using bootproto::video_mode;
|
using layout = bootproto::devices::fb_layout;
|
||||||
using layout = bootproto::fb_layout;
|
using screen = bootproto::devices::uefi_fb;
|
||||||
|
|
||||||
struct screen {
|
|
||||||
util::buffer framebuffer;
|
|
||||||
video_mode mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Pick the best video mode and set up the screen
|
/// Pick the best video mode and set up the screen
|
||||||
screen * pick_mode(uefi::boot_services *bs);
|
screen * pick_mode(uefi::boot_services *bs);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ bp = module("bootproto",
|
|||||||
kind = "lib",
|
kind = "lib",
|
||||||
public_headers = [
|
public_headers = [
|
||||||
"bootproto/bootconfig.h",
|
"bootproto/bootconfig.h",
|
||||||
|
"bootproto/devices/framebuffer.h",
|
||||||
"bootproto/init.h",
|
"bootproto/init.h",
|
||||||
"bootproto/kernel.h",
|
"bootproto/kernel.h",
|
||||||
"bootproto/memory.h.cog",
|
"bootproto/memory.h.cog",
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
namespace bootproto {
|
namespace bootproto {
|
||||||
|
|
||||||
enum class desc_flags : uint16_t {
|
enum class desc_flags : uint16_t {
|
||||||
graphical = 0x01,
|
graphical = 0x0001,
|
||||||
panic = 0x02,
|
panic = 0x0002,
|
||||||
symbols = 0x04,
|
symbols = 0x0004,
|
||||||
};
|
};
|
||||||
is_bitfield(desc_flags);
|
is_bitfield(desc_flags);
|
||||||
|
|
||||||
|
|||||||
28
src/libraries/bootproto/bootproto/devices/framebuffer.h
Normal file
28
src/libraries/bootproto/bootproto/devices/framebuffer.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file bootproto/devices/uefi_fb.h
|
||||||
|
/// Data structures describing bootloader-passed framebuffer
|
||||||
|
|
||||||
|
#include <util/counted.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -10,61 +10,30 @@
|
|||||||
|
|
||||||
namespace bootproto {
|
namespace bootproto {
|
||||||
|
|
||||||
enum class module_type : uint8_t {
|
enum class module_type : uint8_t { none, initrd, device, };
|
||||||
none,
|
enum class initrd_format : uint8_t { none, zstd, };
|
||||||
program,
|
enum class device_type : uint16_t { none, uefi_fb, };
|
||||||
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);
|
|
||||||
|
|
||||||
struct module
|
struct module
|
||||||
{
|
{
|
||||||
module_type mod_type;
|
module_type type;
|
||||||
module_flags mod_flags;
|
// 1 byte padding
|
||||||
uint32_t mod_length;
|
uint16_t subtype;
|
||||||
|
// 4 bytes padding
|
||||||
|
util::buffer data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct module_program :
|
struct module_page_header
|
||||||
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
|
|
||||||
{
|
{
|
||||||
uint8_t count;
|
uint8_t count;
|
||||||
module *modules;
|
|
||||||
uintptr_t next;
|
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
|
} // namespace bootproto
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ module("drv.uart",
|
|||||||
targets = [ "user" ],
|
targets = [ "user" ],
|
||||||
deps = [ "libc", "util" ],
|
deps = [ "libc", "util" ],
|
||||||
description = "UART driver",
|
description = "UART driver",
|
||||||
|
drivers = [ "pc.uart" ],
|
||||||
sources = [
|
sources = [
|
||||||
"io.cpp",
|
"io.cpp",
|
||||||
"main.cpp",
|
"main.cpp",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ module("drv.uefi_fb",
|
|||||||
targets = [ "user" ],
|
targets = [ "user" ],
|
||||||
deps = [ "libc" ],
|
deps = [ "libc" ],
|
||||||
description = "UEFI framebuffer driver",
|
description = "UEFI framebuffer driver",
|
||||||
|
drivers = [ "uefi.fb" ],
|
||||||
sources = [
|
sources = [
|
||||||
"font.cpp",
|
"font.cpp",
|
||||||
"main.cpp",
|
"main.cpp",
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
#include <j6/syscalls.h>
|
#include <j6/syscalls.h>
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/enum_bitfields.h>
|
||||||
|
|
||||||
using bootproto::module_flags;
|
#include "loader.h"
|
||||||
using bootproto::module_program;
|
|
||||||
|
using bootproto::module;
|
||||||
|
|
||||||
extern j6_handle_t __handle_self;
|
extern j6_handle_t __handle_self;
|
||||||
|
|
||||||
@@ -18,54 +19,62 @@ constexpr uintptr_t load_addr = 0xf8000000;
|
|||||||
constexpr size_t stack_size = 0x10000;
|
constexpr size_t stack_size = 0x10000;
|
||||||
constexpr uintptr_t stack_top = 0x80000000000;
|
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
|
bool
|
||||||
load_program(
|
load_program(
|
||||||
const module_program &prog,
|
const char *name,
|
||||||
|
uintptr_t base_address,
|
||||||
|
size_t size,
|
||||||
j6_handle_t sys, j6_handle_t slp,
|
j6_handle_t sys, j6_handle_t slp,
|
||||||
char *err_msg)
|
char *err_msg)
|
||||||
{
|
{
|
||||||
if (prog.mod_flags && module_flags::no_load) {
|
j6_handle_t elf_vma = map_phys(sys, base_address, size);
|
||||||
sprintf(err_msg, " skipping pre-loaded program module '%s' at %lx", prog.filename, prog.base_address);
|
if (elf_vma == j6_handle_invalid) {
|
||||||
return true;
|
sprintf(err_msg, " ** error loading program '%s': creating physical vma", name);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = j6_vma_map(elf_vma, __handle_self, prog.base_address);
|
const void *addr = reinterpret_cast<const void *>(base_address);
|
||||||
if (res != j6_status_ok) {
|
elf::file progelf {addr, size};
|
||||||
sprintf(err_msg, " ** error loading program '%s': mapping vma: %lx", prog.filename, res);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const void *addr = reinterpret_cast<const void *>(prog.base_address);
|
|
||||||
elf::file progelf {addr, prog.size};
|
|
||||||
|
|
||||||
if (!progelf.valid()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_handle_t proc = j6_handle_invalid;
|
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) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = j6_process_give_handle(proc, sys);
|
res = j6_process_give_handle(proc, sys);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = j6_process_give_handle(proc, slp);
|
res = j6_process_give_handle(proc, slp);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,14 +88,14 @@ load_program(
|
|||||||
if (seg.flags && elf::segment_flags::exec)
|
if (seg.flags && elf::segment_flags::exec)
|
||||||
flags |= j6_vm_flag_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 prologue = start & 0xfff;
|
||||||
size_t epilogue = seg.mem_size - (prologue+seg.file_size);
|
size_t epilogue = seg.mem_size - (prologue+seg.file_size);
|
||||||
|
|
||||||
j6_handle_t sub_vma = j6_handle_invalid;
|
j6_handle_t sub_vma = j6_handle_invalid;
|
||||||
res = j6_vma_create_map(&sub_vma, seg.mem_size+prologue, load_addr, flags);
|
res = j6_vma_create_map(&sub_vma, seg.mem_size+prologue, load_addr, flags);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,13 +107,13 @@ load_program(
|
|||||||
|
|
||||||
res = j6_vma_map(sub_vma, proc, seg.vaddr & ~0xfffull);
|
res = j6_vma_map(sub_vma, proc, seg.vaddr & ~0xfffull);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = j6_vma_unmap(sub_vma, __handle_self);
|
res = j6_vma_unmap(sub_vma, __handle_self);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +121,7 @@ load_program(
|
|||||||
j6_handle_t stack_vma = j6_handle_invalid;
|
j6_handle_t stack_vma = j6_handle_invalid;
|
||||||
res = j6_vma_create_map(&stack_vma, stack_size, load_addr, j6_vm_flag_write);
|
res = j6_vma_create_map(&stack_vma, stack_size, load_addr, j6_vm_flag_write);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,26 +130,26 @@ load_program(
|
|||||||
|
|
||||||
res = j6_vma_map(stack_vma, proc, stack_top-stack_size);
|
res = j6_vma_map(stack_vma, proc, stack_top-stack_size);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = j6_vma_unmap(stack_vma, __handle_self);
|
res = j6_vma_unmap(stack_vma, __handle_self);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_handle_t thread = j6_handle_invalid;
|
j6_handle_t thread = j6_handle_invalid;
|
||||||
res = j6_thread_create(&thread, proc, stack_top - 6*sizeof(uint64_t), progelf.entrypoint());
|
res = j6_thread_create(&thread, proc, stack_top - 6*sizeof(uint64_t), progelf.entrypoint());
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = j6_vma_unmap(elf_vma, __handle_self);
|
res = j6_vma_unmap(elf_vma, __handle_self);
|
||||||
if (res != j6_status_ok) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,3 +12,9 @@ bool load_program(
|
|||||||
const bootproto::module_program &prog,
|
const bootproto::module_program &prog,
|
||||||
j6_handle_t sys, j6_handle_t slp,
|
j6_handle_t sys, j6_handle_t slp,
|
||||||
char *err_msg);
|
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<uintptr_t>(phys), len, addr);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <j6/cap_flags.h>
|
#include <j6/cap_flags.h>
|
||||||
#include <j6/errors.h>
|
#include <j6/errors.h>
|
||||||
@@ -10,11 +11,11 @@
|
|||||||
|
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
|
#include "ramdisk.h"
|
||||||
#include "service_locator.h"
|
#include "service_locator.h"
|
||||||
|
|
||||||
using bootproto::module;
|
using bootproto::module;
|
||||||
using bootproto::module_type;
|
using bootproto::module_type;
|
||||||
using bootproto::module_program;
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
int main(int, const char **);
|
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);
|
modules mods = modules::load_modules(_arg_modules_phys, sys, __handle_self);
|
||||||
|
|
||||||
for (auto &mod : mods.of_type(module_type::program)) {
|
module const *initrd_module;
|
||||||
auto &prog = static_cast<const module_program&>(mod);
|
std::vector<module const*> devices;
|
||||||
|
|
||||||
char message[100];
|
for (auto &mod : mods) {
|
||||||
sprintf(message, " loading program module '%s' at %lx", prog.filename, prog.base_address);
|
switch (mod.type) {
|
||||||
j6_log(message);
|
case module_type::initrd:
|
||||||
|
initrd_module = &mod;
|
||||||
|
break;
|
||||||
|
|
||||||
if (!load_program(prog, sys_child, slp_mb_child, message)) {
|
case module_type::device:
|
||||||
j6_log(message);
|
devices.push_back(&mod);
|
||||||
return 2;
|
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);
|
service_locator_start(slp_mb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,28 +20,24 @@ const module *
|
|||||||
module_iterator::operator++()
|
module_iterator::operator++()
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
m_mod = util::offset_pointer(m_mod, m_mod->mod_length);
|
if (++m_idx >= modules_page::per_page) {
|
||||||
|
|
||||||
if (m_mod->mod_type == type::none) {
|
|
||||||
// We've reached the end of a page, see if there's another
|
// We've reached the end of a page, see if there's another
|
||||||
const modules_page *page = get_page(m_mod);
|
if (!m_page->next) {
|
||||||
if (!page->next) {
|
m_page = nullptr;
|
||||||
m_mod = nullptr;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
m_idx = 0;
|
||||||
m_mod = page->modules;
|
m_page = reinterpret_cast<modules_page*>(m_page->next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (m_type != type::none && m_type != m_mod->mod_type);
|
while (m_type != type::none && m_type != deref()->type);
|
||||||
|
return deref();
|
||||||
return m_mod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const module *
|
const module *
|
||||||
module_iterator::operator++(int)
|
module_iterator::operator++(int)
|
||||||
{
|
{
|
||||||
const module *tmp = m_mod;
|
const module *tmp = deref();
|
||||||
operator++();
|
operator++();
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
@@ -64,7 +60,7 @@ load_page(uintptr_t address, j6_handle_t system, j6_handle_t self)
|
|||||||
modules
|
modules
|
||||||
modules::load_modules(uintptr_t address, j6_handle_t system, j6_handle_t self)
|
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) {
|
while (address) {
|
||||||
const modules_page *page = load_page(address, system, self);
|
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);
|
j6_log(message);
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
first = page->modules;
|
first = page;
|
||||||
address = page->next;
|
address = page->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,27 +13,32 @@ public:
|
|||||||
using type = bootproto::module_type;
|
using type = bootproto::module_type;
|
||||||
using module = bootproto::module;
|
using module = bootproto::module;
|
||||||
|
|
||||||
module_iterator(const module *m, type t = type::none) :
|
module_iterator(const bootproto::modules_page *p, unsigned i, type t = type::none) :
|
||||||
m_mod {m}, m_type {t} {}
|
m_page {p}, m_idx {i}, m_type {t} {
|
||||||
|
if ( t != type::none && p && deref()->type != t ) operator++();
|
||||||
|
}
|
||||||
|
|
||||||
const module * operator++();
|
const module * operator++();
|
||||||
const module * operator++(int);
|
const module * operator++(int);
|
||||||
|
|
||||||
bool operator==(const module* m) const { return m == m_mod; }
|
bool operator==(const module* m) const { return m == deref(); }
|
||||||
bool operator!=(const module* m) const { return m != m_mod; }
|
bool operator!=(const module* m) const { return m != deref(); }
|
||||||
bool operator==(const module_iterator &i) const { return i.m_mod == m_mod; }
|
bool operator==(const module_iterator &i) const { return i.deref() == deref(); }
|
||||||
bool operator!=(const module_iterator &i) const { return i.m_mod != m_mod; }
|
bool operator!=(const module_iterator &i) const { return i.deref() != deref(); }
|
||||||
|
|
||||||
const module & operator*() const { return *m_mod; }
|
const module & operator*() const { return *deref(); }
|
||||||
operator const module & () const { return *m_mod; }
|
operator const module & () const { return *deref(); }
|
||||||
const module * operator->() const { return m_mod; }
|
const module * operator->() const { return deref(); }
|
||||||
|
|
||||||
// Allow iterators to be used in for(:) statments
|
// Allow iterators to be used in for(:) statments
|
||||||
module_iterator & begin() { return *this; }
|
module_iterator & begin() { return *this; }
|
||||||
module_iterator end() const { return nullptr; }
|
module_iterator end() const { return {nullptr, 0}; }
|
||||||
|
|
||||||
private:
|
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;
|
type m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,15 +53,15 @@ public:
|
|||||||
j6_handle_t system,
|
j6_handle_t system,
|
||||||
j6_handle_t self);
|
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 begin() const { return iterator {m_root, 0}; }
|
||||||
iterator end() const { return nullptr; }
|
iterator end() const { return {nullptr, 0}; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using module = bootproto::module;
|
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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user