diff --git a/configs/custom.ninja b/configs/custom.ninja index 95dbfad..e9cad24 100644 --- a/configs/custom.ninja +++ b/configs/custom.ninja @@ -45,12 +45,16 @@ build ${build_root}/fatroot/testapp.elf : cp ${build_root}/user/testapp.elf build ${build_root}/fatroot/drv.uefi_fb.elf : cp ${build_root}/user/drv.uefi_fb.elf name = UEFI framebuffer driver to FAT image +build ${build_root}/fatroot/srv.init.elf : cp ${build_root}/user/srv.init.elf + name = Init server to FAT image + build ${build_root}/fatroot/symbol_table.dat : makest ${build_root}/jsix.elf build ${build_root}/jsix.img : makefat | $ ${build_root}/fatroot/symbol_table.dat $ ${build_root}/fatroot/testapp.elf $ ${build_root}/fatroot/drv.uefi_fb.elf $ + ${build_root}/fatroot/srv.init.elf $ ${build_root}/fatroot/jsix.elf $ ${build_root}/fatroot/efi/boot/bootx64.efi name = jsix.img diff --git a/configs/debug.toml b/configs/debug.toml index 1e58f7f..d4a57dc 100644 --- a/configs/debug.toml +++ b/configs/debug.toml @@ -7,32 +7,32 @@ nasm = "nasm" objcopy = "objcopy" ccflags = [ - "${ccflags}", + "${ccflags}", "-I${source_root}/external", "--target=x86_64-unknown-windows", - "-ffreestanding", - "-mno-red-zone", - "-fshort-wchar", - "-fno-omit-frame-pointer", - "-ggdb", + "-ffreestanding", + "-mno-red-zone", + "-fshort-wchar", + "-fno-omit-frame-pointer", + "-ggdb", "-g3", '-DKERNEL_FILENAME=L"jsix.elf"', ] cxxflags = [ - "${cxxflags}", + "${cxxflags}", "-fno-exceptions", "-fno-rtti", ] ldflags = [ - "${ldflags}", + "${ldflags}", "--target=x86_64-unknown-windows", - "-nostdlib", + "-nostdlib", "-Wl,-entry:efi_main", "-Wl,-subsystem:efi_application", "-fuse-ld=lld-link", - "-g" + "-g" ] @@ -45,14 +45,14 @@ nasm = "nasm" objcopy = "objcopy" asflags = [ - "${asflags}", - "-I${source_root}/src/kernel/", + "${asflags}", + "-I${source_root}/src/kernel/", ] ccflags = [ - "${ccflags}", + "${ccflags}", "--target=x86_64-unknown-elf", - "-I${source_root}/external", + "-I${source_root}/external", "-nostdlib", "-ffreestanding", "-nodefaultlibs", @@ -64,27 +64,28 @@ ccflags = [ "-mcmodel=large", "-D__ELF__", "-D__JSIX__", - "-D_LIBCPP_HAS_THREAD_API_EXTERNAL", "-isystem${source_root}/sysroot/include", "-isystem${source_root}/src/libraries/libc/include", - "--sysroot='${source_root}/sysroot'" + "--sysroot='${source_root}/sysroot'", + "-U__linux", + "-U__linux__", ] cxxflags = [ - "${cxxflags}", + "${cxxflags}", "-fno-exceptions", "-fno-rtti", "-isystem${source_root}/sysroot/include/c++/v1" ] ldflags = [ - "${ldflags}", - "-T", "${source_root}/src/kernel/kernel.ld", + "${ldflags}", + "-T", "${source_root}/src/kernel/kernel.ld", "-g", "-nostdlib", "-Bstatic", - "-z", "norelro", - "-z", "separate-code", + "-z", "norelro", + "-z", "separate-code", ] @@ -97,42 +98,36 @@ nasm = "nasm" objcopy = "objcopy" asflags = [ - "${asflags}", - "-I${source_root}/src/kernel/", + "${asflags}", + "-I${source_root}/src/kernel/", ] ccflags = [ - "${ccflags}", - "-nostdlib", - "-ffreestanding", - "-nodefaultlibs", - "-fno-builtin", + "${ccflags}", "-mno-sse", "-fno-omit-frame-pointer", - "-mno-red-zone", "-g", - "-mcmodel=large", "-D__ELF__", "-D__JSIX__", - "-D_LIBCPP_HAS_THREAD_API_EXTERNAL", "-isystem${source_root}/sysroot/include", "-isystem${source_root}/src/libraries/libc/include", - "--sysroot='${source_root}/sysroot'" + "--sysroot='${source_root}/sysroot'", + "-U__linux", + "-U__linux__", ] cxxflags = [ - "${cxxflags}", + "${cxxflags}", "-fno-exceptions", "-fno-rtti", "-isystem${source_root}/sysroot/include/c++/v1" ] ldflags = [ - "${ldflags}", + "${ldflags}", "-g", - "-nostdlib", "-Bstatic", "--sysroot='${source_root}/sysroot'", - "-L", "${source_root}/sysroot/lib", - "-z", "separate-code", + "-L", "${source_root}/sysroot/lib", + "-z", "separate-code", ] diff --git a/src/boot/allocator.cpp b/src/boot/allocator.cpp index 91787aa..41f6d39 100644 --- a/src/boot/allocator.cpp +++ b/src/boot/allocator.cpp @@ -4,6 +4,7 @@ #include "kutil/no_construct.h" #include "allocator.h" #include "error.h" +#include "init_args.h" #include "kernel_args.h" #include "memory.h" @@ -15,23 +16,32 @@ memory::allocator &g_alloc = __g_alloc_storage.value; namespace memory { using kernel::init::allocation_register; +using kernel::init::module; using kernel::init::page_allocation; static_assert(sizeof(allocation_register) == page_size); void -init_allocator(uefi::boot_services *bs) +allocator::init( + allocation_register *&allocs, + modules_page *&modules, + uefi::boot_services *bs) { new (&g_alloc) allocator(*bs); + allocs = g_alloc.m_register; + modules = g_alloc.m_modules; } allocator::allocator(uefi::boot_services &bs) : m_bs(bs), m_register(nullptr), - m_current(nullptr) -{} + m_modules(nullptr) +{ + add_register(); + add_modules(); +} void allocator::add_register() @@ -45,13 +55,25 @@ allocator::add_register() m_bs.set_mem(reg, sizeof(allocation_register), 0); - if (!m_register) { - m_register = m_current = reg; - return; - } + if (m_register) + m_register->next = reg; - m_current->next = reg; - m_current = reg; + m_register = reg; + return; +} + +void +allocator::add_modules() +{ + modules_page *mods = reinterpret_cast( + allocate_pages(1, alloc_type::init_args, true)); + + if (m_modules) + m_modules->next = reinterpret_cast(mods); + + mods->modules = reinterpret_cast(mods + 1); + m_modules = mods; + m_next_mod = mods->modules; return; } @@ -64,7 +86,7 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero) __LINE__); } - if (!m_current || m_current->count == 0xff) + if (!m_register || m_register->count == 0xff) add_register(); void *pages = nullptr; @@ -74,7 +96,7 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero) uefi::memory_type::loader_data, count, &pages), L"Failed allocating usable pages"); - page_allocation &ent = m_current->entries[m_current->count++]; + page_allocation &ent = m_register->entries[m_register->count++]; ent.address = reinterpret_cast(pages); ent.count = count; ent.type = type; @@ -85,6 +107,24 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero) return pages; } +module * +allocator::allocate_module_untyped(size_t size) +{ + size_t remaining = + reinterpret_cast(m_modules) + page_size + - reinterpret_cast(m_next_mod); + + if (size > remaining) + add_modules(); + + ++m_modules->count; + module *m = m_next_mod; + m_next_mod = offset_ptr(m_next_mod, size); + + m->mod_length = size; + return m; +} + void * allocator::allocate(size_t size, bool zero) { diff --git a/src/boot/allocator.h b/src/boot/allocator.h index 0ce27a4..8b2ce1e 100644 --- a/src/boot/allocator.h +++ b/src/boot/allocator.h @@ -2,12 +2,18 @@ /// \file allocator.h /// Page allocator class definition -#include "kernel_args.h" - namespace uefi { class boot_services; } +namespace kernel { +namespace init { + enum class allocation_type : uint8_t; + struct allocation_register; + struct module; + struct modules_page; +}} + namespace boot { namespace memory { @@ -17,6 +23,8 @@ class allocator { public: using allocation_register = kernel::init::allocation_register; + using module = kernel::init::module; + using modules_page = kernel::init::modules_page; allocator(uefi::boot_services &bs); @@ -25,25 +33,37 @@ public: void * allocate_pages(size_t count, alloc_type type, bool zero = false); + template + M * allocate_module(size_t extra = 0) { + return static_cast(allocate_module_untyped(sizeof(M) + extra)); + } + void memset(void *start, size_t size, uint8_t value); void copy(void *to, void *from, size_t size); inline void zero(void *start, size_t size) { memset(start, size, 0); } - allocation_register * get_register() { return m_register; } + /// Initialize the global allocator + /// \arg allocs [out] Poiinter to the initial allocation register + /// \arg modules [out] Pointer to the initial modules_page + /// \arg bs UEFI boot services + static void init( + allocation_register *&allocs, + modules_page *&modules, + uefi::boot_services *bs); private: void add_register(); + void add_modules(); + module * allocate_module_untyped(size_t size); uefi::boot_services &m_bs; allocation_register *m_register; - allocation_register *m_current; + modules_page *m_modules; + module *m_next_mod; }; -/// Initialize the global allocator -void init_allocator(uefi::boot_services *bs); - } // namespace memory extern memory::allocator &g_alloc; diff --git a/src/boot/console.cpp b/src/boot/console.cpp index 570d73c..14e8e0e 100644 --- a/src/boot/console.cpp +++ b/src/boot/console.cpp @@ -22,7 +22,7 @@ static const wchar_t digits[] = {u'0', u'1', u'2', u'3', u'4', u'5', u'6', u'7', u'8', u'9', u'a', u'b', u'c', u'd', u'e', u'f'}; -static size_t +size_t wstrlen(const wchar_t *s) { size_t count = 0; diff --git a/src/boot/console.h b/src/boot/console.h index 48a6bb5..9012d45 100644 --- a/src/boot/console.h +++ b/src/boot/console.h @@ -4,6 +4,7 @@ #include #include +#include namespace uefi { namespace protos { @@ -40,4 +41,6 @@ private: static console *s_console; }; +size_t wstrlen(const wchar_t *s); + } // namespace boot diff --git a/src/boot/fs.cpp b/src/boot/fs.cpp index b5fc24e..4b6f1e0 100644 --- a/src/boot/fs.cpp +++ b/src/boot/fs.cpp @@ -9,6 +9,7 @@ #include "console.h" #include "error.h" #include "fs.h" +#include "kernel_args.h" #include "memory.h" #include "status.h" diff --git a/src/boot/hardware.cpp b/src/boot/hardware.cpp index c1be166..f6eb0c3 100644 --- a/src/boot/hardware.cpp +++ b/src/boot/hardware.cpp @@ -1,6 +1,7 @@ -#include "hardware.h" #include "console.h" +#include "cpu/cpu_id.h" #include "error.h" +#include "hardware.h" #include "status.h" namespace boot { @@ -53,7 +54,6 @@ wrmsr(uint32_t addr, uint64_t value) __asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high)); } - void setup_control_regs() { @@ -77,5 +77,27 @@ setup_control_regs() wrmsr(IA32_EFER, efer); } +void +check_cpu_supported() +{ + status_line status {L"Checking CPU features"}; + + cpu::cpu_id cpu; + uint64_t missing = cpu.missing(); + if (missing) { +#define CPU_FEATURE_OPT(...) +#define CPU_FEATURE_REQ(name, ...) \ + if (!cpu.has_feature(cpu::feature::name)) { \ + status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \ + } +#include "cpu/features.inc" +#undef CPU_FEATURE_REQ +#undef CPU_FEATURE_OPT + + error::raise(uefi::status::unsupported, L"CPU not supported"); + } +} + + } // namespace hw } // namespace boot diff --git a/src/boot/hardware.h b/src/boot/hardware.h index 8d90947..784503c 100644 --- a/src/boot/hardware.h +++ b/src/boot/hardware.h @@ -16,5 +16,8 @@ void * find_acpi_table(uefi::system_table *st); /// Enable CPU options in CR4 etc for the kernel starting state. void setup_control_regs(); +/// Check that all required cpu features are supported +void check_cpu_supported(); + } // namespace hw } // namespace boot diff --git a/src/boot/loader.cpp b/src/boot/loader.cpp index 260faae..c1c9286 100644 --- a/src/boot/loader.cpp +++ b/src/boot/loader.cpp @@ -6,6 +6,7 @@ #include "elf.h" #include "error.h" #include "fs.h" +#include "init_args.h" #include "loader.h" #include "memory.h" #include "paging.h" @@ -22,12 +23,11 @@ using memory::alloc_type; buffer load_file( fs::file &disk, - const wchar_t *name, - const wchar_t *path) + const program_desc &desc) { - status_line status(L"Loading file", name); + status_line status(L"Loading file", desc.path); - fs::file file = disk.open(path); + fs::file file = disk.open(desc.path); buffer b = file.load(); //console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size); @@ -50,13 +50,37 @@ is_elfheader_valid(const elf::header *header) header->header_version == elf::version; } -void -load_program( - init::program &program, - const wchar_t *name, - buffer data) +static void +create_module(buffer data, const program_desc &desc, bool loaded) { - status_line status(L"Loading program:", name); + size_t path_len = wstrlen(desc.path); + init::module_program *mod = g_alloc.allocate_module(path_len); + mod->mod_type = init::module_type::program; + mod->base_address = reinterpret_cast(data.pointer); + if (loaded) + mod->mod_flags = static_cast( + static_cast(mod->mod_flags) | + static_cast(init::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) + mod->filename[i] = desc.path[i]; + mod->filename[path_len] = 0; +} + +init::program * +load_program( + fs::file &disk, + const program_desc &desc, + bool add_module) +{ + status_line status(L"Loading program", desc.name); + + buffer data = load_file(disk, desc); + + if (add_module) + create_module(data, desc, true); const elf::header *header = reinterpret_cast(data.pointer); uintptr_t program_base = reinterpret_cast(data.pointer); @@ -103,9 +127,22 @@ load_program( section.type = static_cast(pheader->flags); } - program.sections = { .pointer = sections, .count = num_sections }; - program.phys_base = program_base; - program.entrypoint = header->entrypoint; + init::program *prog = new init::program; + prog->sections = { .pointer = sections, .count = num_sections }; + prog->phys_base = program_base; + prog->entrypoint = header->entrypoint; + return prog; +} + +void +load_module( + fs::file &disk, + const program_desc &desc) +{ + status_line status(L"Loading module", desc.name); + + buffer data = load_file(disk, desc); + create_module(data, desc, false); } void diff --git a/src/boot/loader.h b/src/boot/loader.h index f316a0c..625062b 100644 --- a/src/boot/loader.h +++ b/src/boot/loader.h @@ -7,6 +7,7 @@ namespace kernel { namespace init { struct program; + struct module; }} namespace boot { @@ -17,25 +18,37 @@ namespace fs { namespace loader { +struct program_desc +{ + const wchar_t *name; + const wchar_t *path; +}; + /// Load a file from disk into memory. /// \arg disk The opened UEFI filesystem to load from -/// \arg name Name of the module (informational only) -/// \arg path Path on `disk` of the file to load +/// \arg desc The program descriptor identifying the file buffer load_file( fs::file &disk, - const wchar_t *name, - const wchar_t *path); + const program_desc &desc); /// Parse and load an ELF file in memory into a loaded image. -/// \arg program The program structure to fill -/// \arg name The name of the program being loaded -/// \arg data Buffer of the ELF file in memory -void +/// \arg disk The opened UEFI filesystem to load from +/// \arg desc The program descriptor identifying the program +/// \arg add_module Also create a module for this loaded program +kernel::init::program * load_program( - kernel::init::program &program, - const wchar_t *name, - buffer data); + fs::file &disk, + const program_desc &desc, + bool add_module = false); + +/// 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 +void +load_module( + fs::file &disk, + const program_desc &desc); /// Verify that a loaded ELF has the j6 kernel header /// \arg program The program to check for a header diff --git a/src/boot/main.cpp b/src/boot/main.cpp index e448ca2..d56638a 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -9,7 +9,6 @@ #include "allocator.h" #include "console.h" -#include "cpu/cpu_id.h" #include "error.h" #include "fs.h" #include "hardware.h" @@ -30,19 +29,12 @@ namespace init = kernel::init; namespace boot { -constexpr int max_modules = 5; // Max modules to allocate room for -constexpr int max_programs = 5; // Max programs to allocate room for +const loader::program_desc kern_desc = {L"kernel", L"jsix.elf"}; +const loader::program_desc init_desc = {L"init server", L"srv.init.elf"}; +const loader::program_desc fb_driver = {L"UEFI framebuffer driver", L"drv.uefi_fb.elf"}; -struct program_desc -{ - const wchar_t *name; - const wchar_t *path; -}; - -const program_desc program_list[] = { - {L"kernel", L"jsix.elf"}, +const loader::program_desc extra_programs[] = { {L"test application", L"testapp.elf"}, - {L"UEFI framebuffer driver", L"drv.uefi_fb.elf"}, }; /// Change a pointer to point to the higher-half linear-offset version @@ -53,40 +45,6 @@ void change_pointer(T *&pointer) pointer = offset_ptr(pointer, kernel::memory::page_offset); } -/// Add a module to the kernel args list -inline void -add_module(init::args *args, init::mod_type type, buffer &data) -{ - init::module &m = args->modules[args->modules.count++]; - m.type = type; - m.location = data.pointer; - m.size = data.count; - - change_pointer(m.location); -} - -/// Check that all required cpu features are supported -void -check_cpu_supported() -{ - status_line status {L"Checking CPU features"}; - - cpu::cpu_id cpu; - uint64_t missing = cpu.missing(); - if (missing) { -#define CPU_FEATURE_OPT(...) -#define CPU_FEATURE_REQ(name, ...) \ - if (!cpu.has_feature(cpu::feature::name)) { \ - status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \ - } -#include "cpu/features.inc" -#undef CPU_FEATURE_REQ -#undef CPU_FEATURE_OPT - - error::raise(uefi::status::unsupported, L"CPU not supported"); - } -} - /// The main procedure for the portion of the loader that runs while /// UEFI is still in control of the machine. (ie, while the loader still /// has access to boot services.) @@ -98,13 +56,11 @@ uefi_preboot(uefi::handle image, uefi::system_table *st) status_line status {L"Performing UEFI pre-boot"}; - check_cpu_supported(); + hw::check_cpu_supported(); memory::init_pointer_fixup(bs, rs); init::args *args = new init::args; g_alloc.zero(args, sizeof(init::args)); - args->programs.pointer = new init::program[5]; - args->modules.pointer = new init::module[5]; args->magic = init::args_magic; args->version = init::args_version; @@ -114,21 +70,32 @@ uefi_preboot(uefi::handle image, uefi::system_table *st) paging::allocate_tables(args); + return args; +} + +/// Load the kernel and other programs from disk +void +load_resources(init::args *args, video::screen *screen, uefi::handle image, uefi::boot_services *bs) +{ + status_line status {L"Loading programs"}; + fs::file disk = fs::get_boot_volume(image, bs); - buffer symbols = loader::load_file(disk, L"symbol table", L"symbol_table.dat"); - add_module(args, init::mod_type::symbol_table, symbols); - - for (auto &desc : program_list) { - buffer buf = loader::load_file(disk, desc.name, desc.path); - init::program &program = args->programs[args->programs.count++]; - loader::load_program(program, desc.name, buf); + if (screen) { + video::make_module(screen); + loader::load_module(disk, fb_driver); } - // First program *must* be the kernel - loader::verify_kernel_header(args->programs[0]); + args->symbol_table = loader::load_file(disk, {L"symbol table", L"symbol_table.dat"}); + + args->kernel = loader::load_program(disk, kern_desc, true); + args->init = loader::load_program(disk, init_desc); + + for (auto &desc : extra_programs) + loader::load_module(disk, desc); + + loader::verify_kernel_header(*args->kernel); - return args; } memory::efi_mem_map @@ -141,7 +108,6 @@ uefi_exit(init::args *args, uefi::handle image, uefi::boot_services *bs) args->mem_map = memory::build_kernel_map(map); args->frame_blocks = memory::build_frame_blocks(args->mem_map); - args->allocations = g_alloc.get_register(); map.update(*bs); try_or_raise( @@ -162,17 +128,24 @@ efi_main(uefi::handle image, uefi::system_table *st) uefi::boot_services *bs = st->boot_services; console con(st->con_out); - memory::init_allocator(bs); + init::allocation_register *allocs = nullptr; + init::modules_page *modules = nullptr; + memory::allocator::init(allocs, modules, bs); + video::screen *screen = video::pick_mode(bs); con.announce(); init::args *args = uefi_preboot(image, st); + load_resources(args, screen, image, bs); memory::efi_mem_map map = uefi_exit(args, image, st->boot_services); + args->allocations = allocs; + args->modules = reinterpret_cast(modules); + status_bar status {screen}; // Switch to fb status display // Map the kernel to the appropriate address - init::program &kernel = args->programs[0]; + init::program &kernel = *args->kernel; for (auto §ion : kernel.sections) paging::map_section(args, section); @@ -180,20 +153,22 @@ efi_main(uefi::handle image, uefi::system_table *st) init::entrypoint kentry = reinterpret_cast(kernel.entrypoint); - status.next(); + //status.next(); hw::setup_control_regs(); memory::virtualize(args->pml4, map, st->runtime_services); - status.next(); + //status.next(); change_pointer(args); change_pointer(args->pml4); - change_pointer(args->modules.pointer); - change_pointer(args->programs.pointer); - for (auto &program : args->programs) - change_pointer(program.sections.pointer); + change_pointer(args->symbol_table.pointer); - status.next(); + change_pointer(args->kernel); + change_pointer(args->kernel->sections.pointer); + change_pointer(args->init); + change_pointer(args->init->sections.pointer); + + //status.next(); kentry(args); debug_break(); diff --git a/src/boot/video.cpp b/src/boot/video.cpp index 32de8c0..a3c1469 100644 --- a/src/boot/video.cpp +++ b/src/boot/video.cpp @@ -2,6 +2,7 @@ #include #include +#include "allocator.h" #include "console.h" #include "error.h" #include "init_args.h" @@ -106,15 +107,15 @@ pick_mode(uefi::boot_services *bs) } void -make_module(screen *s, module_framebuffer *mod) +make_module(screen *s) { - mod->mod_type = module_type::framebuffer; - mod->mod_flags = module_flags::none; - mod->mod_length = sizeof(module_framebuffer); - mod->type = fb_type::uefi; + using kernel::init::module_framebuffer; + module_framebuffer *modfb = g_alloc.allocate_module(); + modfb->mod_type = module_type::framebuffer; + modfb->type = fb_type::uefi; - mod->framebuffer = s->framebuffer; - mod->mode = s->mode; + modfb->framebuffer = s->framebuffer; + modfb->mode = s->mode; } } // namespace video diff --git a/src/boot/video.h b/src/boot/video.h index a4503bb..97a7eca 100644 --- a/src/boot/video.h +++ b/src/boot/video.h @@ -26,7 +26,7 @@ struct screen { screen * pick_mode(uefi::boot_services *bs); /// Make an init arg module from the video mode -void make_module(screen *s, kernel::init::module_framebuffer *mod); +void make_module(screen *s); } // namespace video } // namespace boot diff --git a/src/include/init_args.h b/src/include/init_args.h index 3aa1443..46ce0b3 100644 --- a/src/include/init_args.h +++ b/src/include/init_args.h @@ -9,11 +9,19 @@ namespace kernel { namespace init { enum class module_type : uint8_t { + none, program, framebuffer, }; -enum class module_flags : uint8_t { none = 0 }; +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, +}; struct module { @@ -52,7 +60,7 @@ struct modules_page { uint8_t count; module *modules; - modules_page *next; + uintptr_t next; }; } // namespace init diff --git a/src/include/j6/tables/syscalls.inc b/src/include/j6/tables/syscalls.inc index 69badcb..0f14bea 100644 --- a/src/include/j6/tables/syscalls.inc +++ b/src/include/j6/tables/syscalls.inc @@ -2,7 +2,7 @@ SYSCALL(0x00, system_log, const char *) SYSCALL(0x01, system_noop, void) SYSCALL(0x02, system_get_log, j6_handle_t, void *, size_t *) SYSCALL(0x03, system_bind_irq, j6_handle_t, j6_handle_t, unsigned) -SYSCALL(0x04, system_map_mmio, j6_handle_t, j6_handle_t *, uintptr_t, size_t, uint32_t) +SYSCALL(0x04, system_map_phys, j6_handle_t, j6_handle_t *, uintptr_t, size_t, uint32_t) SYSCALL(0x08, object_koid, j6_handle_t, j6_koid_t *) SYSCALL(0x09, object_wait, j6_handle_t, j6_signal_t, j6_signal_t *) diff --git a/src/include/kernel_args.h b/src/include/kernel_args.h index 823ca05..54c2387 100644 --- a/src/include/kernel_args.h +++ b/src/include/kernel_args.h @@ -15,16 +15,6 @@ constexpr uint64_t header_magic = 0x4c454e52454b366aull; // 'j6KERNEL' constexpr uint16_t header_version = 2; constexpr uint16_t min_header_version = 2; -enum class mod_type : uint32_t { - symbol_table -}; - -struct module { - void *location; - size_t size; - mod_type type; -}; - enum class section_flags : uint32_t { none = 0, execute = 1, @@ -64,7 +54,7 @@ struct mem_entry }; enum class allocation_type : uint8_t { - none, page_table, mem_map, frame_map, file, program, + none, page_table, mem_map, frame_map, file, program, init_args, }; /// A single contiguous allocation of pages @@ -131,13 +121,14 @@ struct args void *pml4; counted page_tables; - - counted programs; - counted modules; counted mem_map; counted frame_blocks; + program *kernel; + program *init; + counted symbol_table; allocation_register *allocations; + uintptr_t modules; void *runtime_services; void *acpi_table; diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 4676530..92bbcbb 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -53,7 +53,7 @@ static bool scheduler_ready = false; /// Bootstrap the memory managers. void memory_initialize_pre_ctors(init::args &kargs); void memory_initialize_post_ctors(init::args &kargs); -process * load_simple_process(init::program &program); +void load_init_server(init::program &program, uintptr_t modules_address); unsigned start_aps(lapic &apic, const kutil::vector &ids, void *kpml4); @@ -128,17 +128,8 @@ kernel_main(init::args *args) cpu->tss->create_ist_stacks(cpu->idt->used_ist_entries()); - for (size_t i = 0; i < args->modules.count; ++i) { - init::module &mod = args->modules[i]; - - switch (mod.type) { - case init::mod_type::symbol_table: - new symbol_table {mod.location, mod.size}; - break; - - default: - break; - } + if (args->symbol_table.count) { + new symbol_table {args->symbol_table.pointer, args->symbol_table.count}; } syscall_initialize(); @@ -193,10 +184,8 @@ kernel_main(init::args *args) scheduler *sched = new scheduler {num_cpus}; scheduler_ready = true; - // Skip program 0, which is the kernel itself - for (unsigned i = 1; i < args->programs.count; ++i) - load_simple_process(args->programs[i]); - + // Load the init server + load_init_server(*args->init, args->modules); sched->create_kernel_task(logger_task, scheduler::max_priority/2, true); sched->start(); diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index 9016fe9..286cbcb 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -181,12 +181,13 @@ log_mtrrs() } -process * -load_simple_process(init::program &program) +void +load_init_server(init::program &program, uintptr_t modules_address) { process *p = new process; - vm_space &space = p->space(); + p->add_handle(&system::get()); + vm_space &space = p->space(); for (const auto § : program.sections) { vm_flags flags = ((sect.type && section_flags::execute) ? vm_flags::exec : vm_flags::none) | @@ -197,64 +198,14 @@ load_simple_process(init::program &program) } uint64_t iopl = (3ull << 12); - uintptr_t trampoline = reinterpret_cast(initialize_main_thread); thread *main = p->create_thread(); - main->add_thunk_user(program.entrypoint, trampoline, iopl); + main->add_thunk_user(program.entrypoint, 0, iopl); main->set_state(thread::state::ready); - return p; -} - -template -inline T * push(uintptr_t &rsp, size_t size = sizeof(T)) { - rsp -= size; - T *p = reinterpret_cast(rsp); - rsp &= ~(sizeof(uint64_t)-1); // Align the stack - return p; -} - -uintptr_t -initialize_main_user_stack() -{ - process &proc = process::current(); - thread &th = thread::current(); - TCB *tcb = th.tcb(); - - const char message[] = "Hello from the kernel!"; - char *message_arg = push(tcb->rsp3, sizeof(message)); - kutil::memcpy(message_arg, message, sizeof(message)); - - j6_init_value *initv = nullptr; - unsigned n = 0; - - initv = push(tcb->rsp3); - initv->type = j6_init_handle_other; - initv->handle.type = j6_object_type_system; - initv->handle.handle = proc.add_handle(&system::get()); - ++n; - - initv = push(tcb->rsp3); - initv->type = j6_init_handle_self; - initv->handle.type = j6_object_type_process; - initv->handle.handle = proc.self_handle(); - ++n; - - initv = push(tcb->rsp3); - initv->type = j6_init_handle_self; - initv->handle.type = j6_object_type_thread; - initv->handle.handle = th.self_handle(); - ++n; - - uint64_t *initc = push(tcb->rsp3); - *initc = n; - - char **argv0 = push(tcb->rsp3); - *argv0 = message_arg; - - uint64_t *argc = push(tcb->rsp3); - *argc = 1; - - th.clear_state(thread::state::loading); - return tcb->rsp3; + // Hacky: No process exists to have created a stack for init; it needs to create + // its own stack. We take advantage of that to use rsp to pass it the init modules + // address. + auto *tcb = main->tcb(); + tcb->rsp3 = modules_address; } diff --git a/src/kernel/objects/vm_area.h b/src/kernel/objects/vm_area.h index 0153f19..8753aeb 100644 --- a/src/kernel/objects/vm_area.h +++ b/src/kernel/objects/vm_area.h @@ -20,7 +20,8 @@ enum class vm_flags : uint32_t #define VM_FLAG(name, v) name = v, #include "j6/tables/vm_flags.inc" #undef VM_FLAG - user_mask = 0x0000ffff ///< flags allowed via syscall + driver_mask = 0x000fffff, ///< flags allowed via syscall for drivers + user_mask = 0x0000ffff, ///< flags allowed via syscall for non-drivers }; diff --git a/src/kernel/syscalls/system.cpp b/src/kernel/syscalls/system.cpp index 97f443d..a889125 100644 --- a/src/kernel/syscalls/system.cpp +++ b/src/kernel/syscalls/system.cpp @@ -2,6 +2,7 @@ #include "j6/types.h" #include "device_manager.h" +#include "frame_allocator.h" #include "log.h" #include "objects/endpoint.h" #include "objects/thread.h" @@ -60,12 +61,17 @@ system_bind_irq(j6_handle_t sys, j6_handle_t endp, unsigned irq) } j6_status_t -system_map_mmio(j6_handle_t sys, j6_handle_t *vma_handle, uintptr_t phys_addr, size_t size, uint32_t flags) +system_map_phys(j6_handle_t sys, j6_handle_t *vma_handle, uintptr_t phys_addr, size_t size, uint32_t flags) { // TODO: check capabilities on sys handle if (!vma_handle) return j6_err_invalid_arg; - vm_flags vmf = vm_flags::mmio | (static_cast(flags) & vm_flags::user_mask); + // TODO: check to see if frames are already used? How would that collide with + // the bootloader's allocated pages already being marked used? + if (!(flags & vm_flags::mmio)) + frame_allocator::get().used(phys_addr, memory::page_count(size)); + + vm_flags vmf = (static_cast(flags) & vm_flags::driver_mask); construct_handle(vma_handle, phys_addr, size, vmf); return j6_status_ok; diff --git a/src/kernel/task.s b/src/kernel/task.s index 2f3bbc4..88ba926 100644 --- a/src/kernel/task.s +++ b/src/kernel/task.s @@ -53,20 +53,6 @@ task_switch: pop rbp ret - -extern initialize_main_user_stack -extern kernel_to_user_trampoline -global initialize_main_thread -initialize_main_thread: - call initialize_main_user_stack - - ; user rsp is now in rax, put it in the right place for sysret - mov [rsp + 0x30], rax - mov [gs:CPU_DATA.rsp3], rax - - ; the entrypoint should already be on the stack - jmp kernel_to_user_trampoline - global _current_gsbase _current_gsbase: mov rax, [gs:CPU_DATA.self] diff --git a/src/user/drv.uefi_fb/main.cpp b/src/user/drv.uefi_fb/main.cpp index 49defb0..196b90f 100644 --- a/src/user/drv.uefi_fb/main.cpp +++ b/src/user/drv.uefi_fb/main.cpp @@ -55,8 +55,9 @@ main(int argc, const char **argv) j6_handle_t fb_handle = j6_handle_invalid; uint32_t flags = j6_vm_flag_write | - j6_vm_flag_write_combine; - j6_status_t s = j6_system_map_mmio(__handle_sys, &fb_handle, fb->addr, fb->size, flags); + j6_vm_flag_write_combine | + j6_vm_flag_mmio; + j6_status_t s = j6_system_map_phys(__handle_sys, &fb_handle, fb->addr, fb->size, flags); if (s != j6_status_ok) { return s; } diff --git a/src/user/srv.init/main.cpp b/src/user/srv.init/main.cpp new file mode 100644 index 0000000..ece29a0 --- /dev/null +++ b/src/user/srv.init/main.cpp @@ -0,0 +1,20 @@ +#include "j6/syscalls.h" +#include "modules.h" + +extern "C" { + int main(int, const char **); +} + +uintptr_t _arg_modules_phys; // This gets filled in in _start + +j6_handle_t handle_self = 1; // Self program handle is always 1 +j6_handle_t handle_system = 2; // boot protocol is that init gets the system as handle 2 + +int +main(int argc, const char **argv) +{ + j6_system_log("srv.init starting"); + modules::load_all(_arg_modules_phys); + + return 0; +} diff --git a/src/user/srv.init/module.toml b/src/user/srv.init/module.toml new file mode 100644 index 0000000..d889647 --- /dev/null +++ b/src/user/srv.init/module.toml @@ -0,0 +1,8 @@ +name = "srv.init" +targets = ["user"] +deps = ["libc"] +sources = [ + "main.cpp", + "modules.cpp", + "start.s", +] diff --git a/src/user/srv.init/modules.cpp b/src/user/srv.init/modules.cpp new file mode 100644 index 0000000..a61bdfb --- /dev/null +++ b/src/user/srv.init/modules.cpp @@ -0,0 +1,70 @@ +#include +#include + +#include "j6/errors.h" +#include "j6/syscalls.h" +#include "init_args.h" +#include "pointer_manipulation.h" + +#include "modules.h" + +using namespace kernel::init; + +extern j6_handle_t handle_self; +extern j6_handle_t handle_system; + +namespace modules { + +static const modules_page * +load_page(uintptr_t address) +{ + j6_handle_t mods_vma = j6_handle_invalid; + j6_status_t s = j6_system_map_phys(handle_system, &mods_vma, address, 0x1000, 0); + if (s != j6_status_ok) + exit(s); + + s = j6_vma_map(mods_vma, handle_self, address); + if (s != j6_status_ok) + exit(s); + + return reinterpret_cast(address); +} + +void +load_all(uintptr_t address) +{ + module_framebuffer const *framebuffer = nullptr; + + while (address) { + const modules_page *page = load_page(address); + + char message[100]; + sprintf(message, "srv.init loading %d modules from page at 0x%lx", page->count, address); + j6_system_log(message); + + module *mod = page->modules; + size_t count = page->count; + while (count--) { + switch (mod->mod_type) { + case module_type::framebuffer: + framebuffer = reinterpret_cast(mod); + break; + + case module_type::program: + if (mod->mod_flags == module_flags::no_load) + j6_system_log("Loaded program module"); + else + j6_system_log("Non-loaded program module"); + break; + + default: + j6_system_log("Unknown module"); + } + mod = offset_ptr(mod, mod->mod_length); + } + + address = page->next; + } +} + +} // namespace modules diff --git a/src/user/srv.init/modules.h b/src/user/srv.init/modules.h new file mode 100644 index 0000000..9f0e1fb --- /dev/null +++ b/src/user/srv.init/modules.h @@ -0,0 +1,11 @@ +#pragma once +/// \file modules.h +/// Routines for loading initial argument modules + +namespace modules { + +/// Load all modules +/// \arg address The physical address of the first page of modules +void load_all(uintptr_t address); + +} // namespace modules diff --git a/src/user/srv.init/start.s b/src/user/srv.init/start.s new file mode 100644 index 0000000..58dc7eb --- /dev/null +++ b/src/user/srv.init/start.s @@ -0,0 +1,38 @@ +extern main +extern exit +extern _init_libj6 +extern _arg_modules_phys + +section .bss +align 0x100 +init_stack_start: + resb 0x8000 ; 16KiB stack space +init_stack_top: + +section .text + +global _start:function (_start.end - _start) +_start: + + ; No parent process exists to have created init's stack, so we override + ; _start to deal with that in two ways: + + ; 1. We create a stack in BSS and assign that to be init's first stack + ; 2. We take advantage of the fact that rsp is useless here as a way + ; for the kernel to tell init where its initial modules page is. + mov [_arg_modules_phys], rsp + mov rsp, init_stack_top + push 0 + push 0 + + mov rbp, rsp + mov rdi, rsp + call _init_libj6 + + pop rdi + mov rsi, rsp + call main + + mov rdi, rax + call exit +.end: