mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[init] Load uart and logger from initrd
Load drv.uart.elf and srv.logger.elf from the initrd and start them. It's extremely manual and hard-coded at the moment, but it works and they run, getting us back to where we were pre-initrd branch.
This commit is contained in:
@@ -5,10 +5,10 @@ init = module("srv.init",
|
||||
deps = [ "libc", "elf", "bootproto", "zstd" ],
|
||||
description = "Init server",
|
||||
sources = [
|
||||
"j6romfs.cpp",
|
||||
"loader.cpp",
|
||||
"main.cpp",
|
||||
"modules.cpp",
|
||||
"ramdisk.cpp",
|
||||
"service_locator.cpp",
|
||||
"start.s",
|
||||
])
|
||||
|
||||
115
src/user/srv.init/j6romfs.cpp
Normal file
115
src/user/srv.init/j6romfs.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <util/hash.h>
|
||||
#include <zstd.h>
|
||||
|
||||
#include "j6romfs.h"
|
||||
|
||||
namespace j6romfs {
|
||||
namespace {
|
||||
|
||||
static constexpr unsigned buf_size = max_path + 1;
|
||||
|
||||
const char *
|
||||
copy_path_element(const char *path, char buf[buf_size])
|
||||
{
|
||||
if (*path == '/') path++;
|
||||
|
||||
unsigned i = 0;
|
||||
while (*path && *path != '/' && i < max_path)
|
||||
buf[i++] = *path++;
|
||||
|
||||
buf[i] = 0;
|
||||
return path;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
fs::fs(util::const_buffer data) :
|
||||
m_data {data}
|
||||
{
|
||||
const superblock *sb = reinterpret_cast<const superblock*>(data.pointer);
|
||||
m_inodes = reinterpret_cast<const inode*>(
|
||||
util::offset_pointer(data.pointer, sb->inode_offset));
|
||||
m_root = &m_inodes[sb->root_inode];
|
||||
}
|
||||
|
||||
util::const_buffer
|
||||
fs::load_simple(char const *path) const
|
||||
{
|
||||
if (!path)
|
||||
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
|
||||
fs::load_inode_data(const inode *in, util::buffer dest) const
|
||||
{
|
||||
util::const_buffer src = m_data + in->offset;
|
||||
|
||||
assert(dest.count >= in->size && "Dest buffer not big enough");
|
||||
assert(src.count >= in->compressed && "Source buffer not big enough");
|
||||
|
||||
if (in->size == in->compressed) {
|
||||
// If the sizes are equal, no compression happened
|
||||
memcpy(dest.pointer, src.pointer, in->size);
|
||||
return in->size;
|
||||
}
|
||||
|
||||
size_t decom = ZSTD_decompress(dest.pointer, dest.count,
|
||||
src.pointer, in->compressed);
|
||||
assert(!ZSTD_isError(decom) && "Error decompressing");
|
||||
return decom;
|
||||
}
|
||||
|
||||
const inode *
|
||||
fs::lookup_inode_in_dir(const inode *dir, const char *name) const
|
||||
{
|
||||
uint8_t *dirdata = new uint8_t [dir->size];
|
||||
load_inode_data(dir, util::buffer::from(dirdata, dir->size));
|
||||
|
||||
const dirent *entries = reinterpret_cast<const dirent*>(dirdata);
|
||||
|
||||
inode const *found = nullptr;
|
||||
uint64_t hash = util::fnv1a::hash64_string(name);
|
||||
|
||||
unsigned max = dir->size / sizeof(dirent);
|
||||
for (unsigned i = 0; i < max; ++i) {
|
||||
const dirent &e = entries[i];
|
||||
if (e.name_hash == hash) {
|
||||
found = &m_inodes[e.inode];
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned new_max = e.name_offset / sizeof(dirent);
|
||||
if (new_max < max)
|
||||
max = new_max;
|
||||
}
|
||||
|
||||
delete [] dirdata;
|
||||
return found;
|
||||
}
|
||||
|
||||
} // namespace j6romfs
|
||||
63
src/user/srv.init/j6romfs.h
Normal file
63
src/user/srv.init/j6romfs.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
/// \file j6romfs.h
|
||||
/// Data structure for dealing with j6romfs images
|
||||
|
||||
#include <util/counted.h>
|
||||
#include <util/enum_bitfields.h>
|
||||
|
||||
namespace j6romfs
|
||||
{
|
||||
|
||||
inline constexpr unsigned max_path = 0xff;
|
||||
|
||||
enum class compressor : uint8_t { none, zstd };
|
||||
|
||||
struct superblock
|
||||
{
|
||||
uint64_t magic;
|
||||
uint64_t inode_offset;
|
||||
|
||||
uint32_t inode_count;
|
||||
uint32_t root_inode;
|
||||
|
||||
compressor compressor;
|
||||
|
||||
uint8_t reserved[7];
|
||||
};
|
||||
|
||||
enum class inode_type : uint8_t { none, directory, file, symlink, };
|
||||
|
||||
struct inode
|
||||
{
|
||||
uint32_t size;
|
||||
uint32_t compressed : 24;
|
||||
inode_type type : 8;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct dirent
|
||||
{
|
||||
uint32_t inode;
|
||||
uint16_t name_offset;
|
||||
inode_type type;
|
||||
uint8_t name_len;
|
||||
uint64_t name_hash;
|
||||
};
|
||||
|
||||
class fs
|
||||
{
|
||||
public:
|
||||
fs(util::const_buffer data);
|
||||
|
||||
util::const_buffer load_simple(char const *path) const;
|
||||
|
||||
private:
|
||||
size_t load_inode_data(const inode *in, util::buffer dest) const;
|
||||
const inode * lookup_inode_in_dir(const inode *in, const char *name) const;
|
||||
|
||||
util::const_buffer m_data;
|
||||
inode const *m_inodes;
|
||||
inode const *m_root;
|
||||
};
|
||||
|
||||
} // namespace j6romfs
|
||||
@@ -40,19 +40,13 @@ map_phys(j6_handle_t sys, uintptr_t phys, size_t len, uintptr_t addr)
|
||||
bool
|
||||
load_program(
|
||||
const char *name,
|
||||
uintptr_t base_address,
|
||||
size_t size,
|
||||
util::const_buffer data,
|
||||
j6_handle_t sys, j6_handle_t slp,
|
||||
char *err_msg)
|
||||
{
|
||||
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;
|
||||
}
|
||||
uintptr_t base_address = reinterpret_cast<uintptr_t>(data.pointer);
|
||||
|
||||
const void *addr = reinterpret_cast<const void *>(base_address);
|
||||
elf::file progelf {addr, size};
|
||||
elf::file progelf {data.pointer, data.count};
|
||||
|
||||
if (!progelf.valid()) {
|
||||
sprintf(err_msg, " ** error loading program '%s': ELF is invalid", name);
|
||||
@@ -89,7 +83,7 @@ load_program(
|
||||
flags |= j6_vm_flag_exec;
|
||||
|
||||
uintptr_t start = base_address + seg.offset;
|
||||
size_t prologue = start & 0xfff;
|
||||
size_t prologue = seg.vaddr & 0xfff;
|
||||
size_t epilogue = seg.mem_size - (prologue+seg.file_size);
|
||||
|
||||
j6_handle_t sub_vma = j6_handle_invalid;
|
||||
@@ -147,12 +141,7 @@ load_program(
|
||||
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", name, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
delete [] reinterpret_cast<const uint8_t*>(data.pointer);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,13 @@ namespace bootproto {
|
||||
}
|
||||
|
||||
bool load_program(
|
||||
const bootproto::module_program &prog,
|
||||
const char *name,
|
||||
util::const_buffer data,
|
||||
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) {
|
||||
inline j6_handle_t map_phys(j6_handle_t sys, const void *phys, size_t len, uintptr_t addr = 0) {
|
||||
return map_phys(sys, reinterpret_cast<uintptr_t>(phys), len, addr);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
#include <j6/types.h>
|
||||
#include <bootproto/init.h>
|
||||
|
||||
#include "j6romfs.h"
|
||||
#include "loader.h"
|
||||
#include "modules.h"
|
||||
#include "ramdisk.h"
|
||||
#include "service_locator.h"
|
||||
|
||||
using bootproto::module;
|
||||
@@ -25,6 +25,24 @@ 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)
|
||||
{
|
||||
@@ -91,8 +109,27 @@ main(int argc, const char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ramdisk initrd {initrd_module->data};
|
||||
util::buffer manifest = initrd.load_file("init.manifest");
|
||||
// TODO: encapsulate this all in a driver_manager, or maybe
|
||||
// have driver_source objects..
|
||||
j6romfs::fs initrd {initrd_module->data};
|
||||
|
||||
char err_msg [128];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
service_locator_start(slp_mb);
|
||||
return 0;
|
||||
|
||||
@@ -35,7 +35,14 @@ public:
|
||||
module_iterator end() const { return {nullptr, 0}; }
|
||||
|
||||
private:
|
||||
inline const module * deref() const { return m_page ? &m_page->modules[m_idx] : nullptr; }
|
||||
inline const module * deref() const {
|
||||
if (m_page) {
|
||||
const module &m = m_page->modules[m_idx];
|
||||
if (m.type != type::none)
|
||||
return &m;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned m_idx;
|
||||
bootproto::modules_page const *m_page;
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <util/cdb.h>
|
||||
#include <zstd.h>
|
||||
|
||||
#include "ramdisk.h"
|
||||
|
||||
inline constexpr uint64_t manifest_magic = 0x74696e697869736a; // "jsixinit"
|
||||
inline constexpr size_t manifest_min = 18;
|
||||
inline constexpr size_t manifest_version = 1;
|
||||
|
||||
using util::read;
|
||||
|
||||
ramdisk::ramdisk(util::buffer data) : m_data {data} {}
|
||||
|
||||
util::buffer
|
||||
ramdisk::load_file(const char *name)
|
||||
{
|
||||
util::cdb cdb {m_data};
|
||||
util::buffer c = cdb.retrieve(name);
|
||||
if (!c.count)
|
||||
return c;
|
||||
|
||||
size_t size = ZSTD_getFrameContentSize(c.pointer, c.count);
|
||||
|
||||
util::buffer d {malloc(size), size};
|
||||
size_t out = ZSTD_decompress(
|
||||
d.pointer, d.count,
|
||||
c.pointer, c.count);
|
||||
|
||||
if (out != size) {
|
||||
free(d.pointer);
|
||||
return {0,0};
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
manifest::manifest(util::buffer data)
|
||||
{
|
||||
if (data.count < manifest_min)
|
||||
return;
|
||||
|
||||
char const *base = reinterpret_cast<char const *>(data.pointer);
|
||||
|
||||
if (*read<uint64_t>(data) != manifest_magic)
|
||||
return;
|
||||
|
||||
uint8_t version = *read<uint8_t>(data);
|
||||
if (version != manifest_version)
|
||||
return;
|
||||
|
||||
read<uint8_t>(data); // reserved byte
|
||||
uint16_t services_len = *read<uint16_t>(data);
|
||||
uint16_t drivers_len = *read<uint16_t>(data);
|
||||
|
||||
base += *read<uint16_t>(data); // start of the string section
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
/// \file loader.h
|
||||
/// Data structure for a ramdisk archive, based on djb's CDB format
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <j6/types.h>
|
||||
#include <util/counted.h>
|
||||
|
||||
class ramdisk
|
||||
{
|
||||
public:
|
||||
ramdisk(util::buffer data);
|
||||
|
||||
util::buffer load_file(const char *name);
|
||||
|
||||
private:
|
||||
util::buffer m_data;
|
||||
};
|
||||
|
||||
class manifest
|
||||
{
|
||||
public:
|
||||
manifest(util::buffer data);
|
||||
|
||||
private:
|
||||
std::vector<const char*> m_services;
|
||||
std::unordered_map<const char*, const char*> m_drivers;
|
||||
};
|
||||
Reference in New Issue
Block a user