[srv.init] Iterate and load drivers and services from initrd

Previously we were hard-coding loading specific files (the UART driver
and logging server) from the initrd. Now j6romfs has a for_each() method
to allow iterating all files in a directory, and init loads all programs
from /jsix/drivers and /jsix/services. Eventually this will need more
dynamic loading decisions for drivers but for now it's fine.
This commit is contained in:
Justin C. Miller
2023-02-07 01:05:38 -08:00
parent 6a6b75b418
commit e8ba12ccb0
4 changed files with 105 additions and 58 deletions

View File

@@ -1,7 +1,9 @@
#include <assert.h>
#include <string.h>
#include <util/hash.h>
#include <zstd.h>
#include <zstd_errors.h>
#include "j6romfs.h"
@@ -37,31 +39,13 @@ fs::fs(util::const_buffer data) :
util::const_buffer
fs::load_simple(char const *path) const
{
if (!path)
const inode *in = lookup_inode(path);
if (!in || in->type != inode_type::file)
return {0, 0};
char element [buf_size];
inode const *in = m_root;
while (*path) {
path = copy_path_element(path, element);
in = lookup_inode_in_dir(in, element);
if (!in) {
// entry was not found
break;
} else if (*path && in->type == inode_type::file) {
// a directory was expected
break;
} else if (in->type == inode_type::file) {
// load the file
uint8_t *data = new uint8_t [in->size];
size_t total = load_inode_data(in, util::buffer::from(data, in->size));
return util::buffer::from(data, total);
}
}
return {0, 0};
}
size_t
@@ -80,10 +64,43 @@ fs::load_inode_data(const inode *in, util::buffer dest) const
size_t decom = ZSTD_decompress(dest.pointer, dest.count,
src.pointer, in->compressed);
assert(!ZSTD_isError(decom) && "Error decompressing");
if (ZSTD_isError(decom)) {
ZSTD_ErrorCode err = ZSTD_getErrorCode(decom);
const char *name = ZSTD_getErrorString(err);
assert(!name);
}
return decom;
}
const inode *
fs::lookup_inode(const char *path) const
{
if (!path)
return nullptr;
char element [buf_size];
inode const *in = m_root;
while (*path) {
path = copy_path_element(path, element);
in = lookup_inode_in_dir(in, element);
if (!in) {
// entry was not found
break;
} else if (!*path) {
// found it
return in;
} else if (*path && in->type == inode_type::file) {
// a directory was expected
break;
}
}
return nullptr;
}
const inode *
fs::lookup_inode_in_dir(const inode *dir, const char *name) const
{

View File

@@ -50,9 +50,36 @@ public:
fs(util::const_buffer data);
util::const_buffer load_simple(char const *path) const;
size_t load_inode_data(const inode *in, util::buffer dest) const;
template <typename callback>
size_t for_each(const char *root, callback &&cb) const
{
const inode *in = lookup_inode(root);
if (!in || in->type != inode_type::directory)
return 0;
uint8_t *dir_data = new uint8_t [in->size];
load_inode_data(in, util::buffer::from(dir_data, in->size));
const dirent *entries = reinterpret_cast<const dirent*>(dir_data);
size_t i = 0, max = in->size / sizeof(dirent);
for (; i < max; ++i) {
const dirent &e = entries[i];
const char *name = reinterpret_cast<const char*>(dir_data + e.name_offset);
cb(&m_inodes[e.inode], name);
size_t new_max = e.name_offset / sizeof(dirent);
if (new_max < max) max = new_max;
}
delete [] dir_data;
return i;
}
private:
size_t load_inode_data(const inode *in, util::buffer dest) const;
const inode * lookup_inode(const char *path) const;
const inode * lookup_inode_in_dir(const inode *in, const char *name) const;
util::const_buffer m_data;

View File

@@ -141,7 +141,6 @@ load_program(
return false;
}
delete [] reinterpret_cast<const uint8_t*>(data.pointer);
return true;
}

View File

@@ -25,24 +25,6 @@ uintptr_t _arg_modules_phys; // This gets filled in in _start
extern j6_handle_t __handle_self;
util::const_buffer
load_driver_for(const char *name, const j6romfs::fs &initrd)
{
char driver[256];
snprintf(driver, sizeof(driver), "/jsix/drivers/drv.%s.elf", name);
return initrd.load_simple(driver);
}
util::const_buffer
load_service(const char *name, const j6romfs::fs &initrd)
{
char service[256];
snprintf(service, sizeof(service), "/jsix/services/srv.%s.elf", name);
return initrd.load_simple(service);
}
int
main(int argc, const char **argv)
{
@@ -113,24 +95,46 @@ main(int argc, const char **argv)
// have driver_source objects..
j6romfs::fs initrd {initrd_module->data};
char err_msg [128];
char message[256];
util::const_buffer uart_elf = load_driver_for("uart", initrd);
if (uart_elf.pointer) {
if (!load_program("UART driver", uart_elf, sys_child, slp_mb_child, err_msg)) {
j6_log(err_msg);
return 1;
}
initrd.for_each("/jsix/drivers",
[=, &message](const j6romfs::inode *in, const char *name) {
if (in->type != j6romfs::inode_type::file)
return;
sprintf(message, "Loading driver: %s", name);
j6_log(message);
uint8_t *data = new uint8_t [in->size];
util::buffer program {data, in->size};
initrd.load_inode_data(in, program);
if (!load_program(name, program, sys_child, slp_mb_child, message)) {
j6_log(message);
}
util::const_buffer logger_elf = load_service("logger", initrd);
if (uart_elf.pointer) {
if (!load_program("logger service", logger_elf, sys_child, slp_mb_child, err_msg)) {
j6_log(err_msg);
return 1;
}
delete [] data;
});
initrd.for_each("/jsix/services",
[=, &message](const j6romfs::inode *in, const char *name) {
if (in->type != j6romfs::inode_type::file)
return;
sprintf(message, "Loading service: %s", name);
j6_log(message);
uint8_t *data = new uint8_t [in->size];
util::buffer program {data, in->size};
initrd.load_inode_data(in, program);
if (!load_program(name, program, sys_child, slp_mb_child, message)) {
j6_log(message);
}
delete [] data;
});
service_locator_start(slp_mb);
return 0;
}