diff --git a/src/user/srv.init/init.module b/src/user/srv.init/init.module index aafbd89..fcf98de 100644 --- a/src/user/srv.init/init.module +++ b/src/user/srv.init/init.module @@ -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", ]) diff --git a/src/user/srv.init/j6romfs.cpp b/src/user/srv.init/j6romfs.cpp new file mode 100644 index 0000000..45020c7 --- /dev/null +++ b/src/user/srv.init/j6romfs.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include + +#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(data.pointer); + m_inodes = reinterpret_cast( + 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(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 diff --git a/src/user/srv.init/j6romfs.h b/src/user/srv.init/j6romfs.h new file mode 100644 index 0000000..3b4b213 --- /dev/null +++ b/src/user/srv.init/j6romfs.h @@ -0,0 +1,63 @@ +#pragma once +/// \file j6romfs.h +/// Data structure for dealing with j6romfs images + +#include +#include + +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 diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index 4c1663d..fbb2b3d 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -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(data.pointer); - const void *addr = reinterpret_cast(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(data.pointer); return true; } diff --git a/src/user/srv.init/loader.h b/src/user/srv.init/loader.h index f9a5cdf..dae253b 100644 --- a/src/user/srv.init/loader.h +++ b/src/user/srv.init/loader.h @@ -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(phys), len, addr); } diff --git a/src/user/srv.init/main.cpp b/src/user/srv.init/main.cpp index e0d1147..d2f04cc 100644 --- a/src/user/srv.init/main.cpp +++ b/src/user/srv.init/main.cpp @@ -9,9 +9,9 @@ #include #include +#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; diff --git a/src/user/srv.init/modules.h b/src/user/srv.init/modules.h index 945660d..a30d529 100644 --- a/src/user/srv.init/modules.h +++ b/src/user/srv.init/modules.h @@ -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; diff --git a/src/user/srv.init/ramdisk.cpp b/src/user/srv.init/ramdisk.cpp deleted file mode 100644 index fcee532..0000000 --- a/src/user/srv.init/ramdisk.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include - -#include -#include - -#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(data.pointer); - - if (*read(data) != manifest_magic) - return; - - uint8_t version = *read(data); - if (version != manifest_version) - return; - - read(data); // reserved byte - uint16_t services_len = *read(data); - uint16_t drivers_len = *read(data); - - base += *read(data); // start of the string section - -} diff --git a/src/user/srv.init/ramdisk.h b/src/user/srv.init/ramdisk.h deleted file mode 100644 index 1711d70..0000000 --- a/src/user/srv.init/ramdisk.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -/// \file loader.h -/// Data structure for a ramdisk archive, based on djb's CDB format - -#include -#include - -#include -#include - -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 m_services; - std::unordered_map m_drivers; -};