diff --git a/modules.yaml b/modules.yaml index b9c5e37..9797a2f 100644 --- a/modules.yaml +++ b/modules.yaml @@ -6,8 +6,6 @@ modules: output: jsix.elf target: host deps: - - elf - - initrd - kutil includes: - src/kernel @@ -81,33 +79,13 @@ modules: nulldrv: kind: exe target: user - output: nulldrv + output: nulldrv.elf deps: - libc source: - src/drivers/nulldrv/main.cpp - src/drivers/nulldrv/main.s - elf: - kind: lib - output: libelf.a - deps: - - kutil - includes: - - src/libraries/elf/include - source: - - src/libraries/elf/elf.cpp - - initrd: - kind: lib - output: libinitrd.a - deps: - - kutil - includes: - - src/libraries/initrd/include - source: - - src/libraries/initrd/initrd.cpp - kutil: kind: lib output: libkutil.a @@ -298,16 +276,6 @@ modules: - src/libraries/libc/time/time.c - src/libraries/libc/time/timespec_get.c - makerd: - kind: exe - target: native - output: makerd - deps: - - initrd - source: - - src/tools/makerd/entry.cpp - - src/tools/makerd/main.cpp - tests: kind: exe target: native diff --git a/scripts/templates/build.ninja.j2 b/scripts/templates/build.ninja.j2 index aae17e6..44d6d6b 100644 --- a/scripts/templates/build.ninja.j2 +++ b/scripts/templates/build.ninja.j2 @@ -119,10 +119,6 @@ rule dump description = Dumping decompiled $name command = objdump -DSC -M intel $in > $out -rule makerd - description = Making init ramdisk - command = $builddir/native/makerd $in $out - rule makest description = Making symbol table command = nm $in | ${srcroot}/scripts/build_symbol_table.py $out @@ -191,15 +187,18 @@ build $builddir/fatroot/jsix.elf : cp $builddir/jsix.elf build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi name = bootloader to FAT image -build ${builddir}/symbol_table.dat : makest ${builddir}/jsix.elf +build $builddir/fatroot/nulldrv.elf : cp $builddir/user/nulldrv.elf + name = null driver to FAT image -build $builddir/fatroot/initrd.img : makerd ${srcroot}/assets/initrd.toml | $ - ${builddir}/native/makerd $ - ${builddir}/user/nulldrv $ - ${builddir}/symbol_table.dat +build $builddir/fatroot/terminal.elf : cp $builddir/user/nulldrv.elf + name = terminal driver to FAT image + +build ${builddir}/fatroot/symbol_table.dat : makest ${builddir}/jsix.elf build $builddir/jsix.img : makefat | $ - $builddir/fatroot/initrd.img $ + $builddir/fatroot/symbol_table.dat $ + $builddir/fatroot/nulldrv.elf $ + $builddir/fatroot/terminal.elf $ $builddir/fatroot/jsix.elf $ $builddir/fatroot/efi/boot/bootx64.efi name = jsix.img diff --git a/src/boot/fs.cpp b/src/boot/fs.cpp index f5ee1c1..ad4d874 100644 --- a/src/boot/fs.cpp +++ b/src/boot/fs.cpp @@ -50,19 +50,19 @@ file::open(const wchar_t *path) return file(fh, m_bs); } -void * -file::load(size_t *out_size, uefi::memory_type mem_type) +buffer +file::load(uefi::memory_type mem_type) { - uint8_t buffer[sizeof(uefi::protos::file_info) + 100]; - size_t size = sizeof(buffer); + uint8_t info_buf[sizeof(uefi::protos::file_info) + 100]; + size_t size = sizeof(info_buf); uefi::guid info_guid = uefi::protos::file_info::guid; try_or_raise( - m_file->get_info(&info_guid, &size, &buffer), + m_file->get_info(&info_guid, &size, &info_buf), L"Could not get file info"); uefi::protos::file_info *info = - reinterpret_cast(&buffer); + reinterpret_cast(&info_buf); size_t pages = memory::bytes_to_pages(info->file_size); void *data = nullptr; @@ -77,8 +77,7 @@ file::load(size_t *out_size, uefi::memory_type mem_type) m_file->read(&size, data), L"Could not read from file"); - *out_size = size; - return data; + return { .data = data, .size = size }; } file diff --git a/src/boot/fs.h b/src/boot/fs.h index bd1af87..11e3fc2 100644 --- a/src/boot/fs.h +++ b/src/boot/fs.h @@ -5,6 +5,7 @@ #include #include #include +#include "types.h" namespace boot { namespace fs { @@ -22,13 +23,10 @@ public: file open(const wchar_t *path); /// Load the contents of this file into memory. - /// \arg out_size _out:_ The number of bytes loaded /// \arg mem_type The UEFI memory type to use for allocation - /// \returns A pointer to the loaded memory. Memory will be - /// page-aligned. - void * load( - size_t *out_size, - uefi::memory_type mem_type = uefi::memory_type::loader_data); + /// \returns A buffer describing the loaded memory. The + /// memory will be page-aligned. + buffer load(uefi::memory_type mem_type = uefi::memory_type::loader_data); private: friend file get_boot_volume(uefi::handle, uefi::boot_services*); diff --git a/src/boot/loader.cpp b/src/boot/loader.cpp index fc859b3..6d64972 100644 --- a/src/boot/loader.cpp +++ b/src/boot/loader.cpp @@ -5,12 +5,32 @@ #include "console.h" #include "elf.h" #include "error.h" +#include "fs.h" #include "memory.h" #include "paging.h" +namespace args = kernel::args; + namespace boot { namespace loader { +buffer +load_file( + fs::file &disk, + const wchar_t *name, + const wchar_t *path, + uefi::memory_type type) +{ + status_line status(L"Loading file", name); + + fs::file file = disk.open(path); + buffer b = file.load(type); + + console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size); + return b; +} + + static bool is_elfheader_valid(const elf::header *header) { @@ -26,54 +46,68 @@ is_elfheader_valid(const elf::header *header) header->header_version == elf::version; } -kernel::entrypoint -load( - const void *data, size_t size, - kernel::args::header *args, +void +load_program( + args::program &program, + const wchar_t *name, + buffer data, uefi::boot_services *bs) { - status_line status(L"Loading kernel ELF binary"); - const elf::header *header = reinterpret_cast(data); + status_line status(L"Loading program:", name); + const elf::header *header = reinterpret_cast(data.data); - if (size < sizeof(elf::header) || !is_elfheader_valid(header)) - error::raise(uefi::status::load_error, L"Kernel ELF not valid"); + if (data.size < sizeof(elf::header) || !is_elfheader_valid(header)) + error::raise(uefi::status::load_error, L"ELF file not valid"); - paging::page_table *pml4 = reinterpret_cast(args->pml4); + uintptr_t prog_base = uintptr_t(-1); + uintptr_t prog_end = 0; for (int i = 0; i < header->ph_num; ++i) { ptrdiff_t offset = header->ph_offset + i * header->ph_entsize; const elf::program_header *pheader = - offset_ptr(data, offset); + offset_ptr(data.data, offset); if (pheader->type != elf::PT_LOAD) continue; - size_t num_pages = memory::bytes_to_pages(pheader->mem_size); - void *pages = nullptr; + uintptr_t end = pheader->vaddr + pheader->mem_size; + if (pheader->vaddr < prog_base) prog_base = pheader->vaddr; + if (end > prog_end) prog_end = end; + } - try_or_raise( - bs->allocate_pages(uefi::allocate_type::any_pages, - memory::kernel_type, num_pages, &pages), - L"Failed allocating space for kernel code"); + size_t total_size = prog_end - prog_base; + size_t num_pages = memory::bytes_to_pages(total_size); + void *pages = nullptr; - void *data_start = offset_ptr(data, pheader->offset); - bs->copy_mem(pages, data_start, pheader->file_size); + try_or_raise( + bs->allocate_pages(uefi::allocate_type::any_pages, + memory::program_type, num_pages, &pages), + L"Failed allocating space for program"); - if (pheader->mem_size > pheader->file_size) { - void *extra = offset_ptr(pages, pheader->file_size); - size_t size = pheader->mem_size - pheader->file_size; - bs->set_mem(extra, size, 0); - } + bs->set_mem(pages, total_size, 0); + + for (int i = 0; i < header->ph_num; ++i) { + ptrdiff_t offset = header->ph_offset + i * header->ph_entsize; + const elf::program_header *pheader = + offset_ptr(data.data, offset); + + if (pheader->type != elf::PT_LOAD) + continue; + + void *src_start = offset_ptr(data.data, pheader->offset); + void *dest_start = offset_ptr(pages, pheader->vaddr - prog_base); + bs->copy_mem(dest_start, src_start, pheader->file_size); console::print(L" section %d phys: 0x%lx\r\n", i, pages); console::print(L" section %d virt: 0x%lx\r\n", i, pheader->vaddr); - - // TODO: set appropriate RWX permissions - paging::map_pages(pml4, args, reinterpret_cast(pages), pheader->vaddr, pheader->mem_size); } console::print(L" entrypoint: 0x%lx\r\n", header->entrypoint); - return reinterpret_cast(header->entrypoint); + + program.phys_addr = reinterpret_cast(pages); + program.size = total_size; + program.virt_addr = prog_base; + program.entrypoint = header->entrypoint; } } // namespace loader diff --git a/src/boot/loader.h b/src/boot/loader.h index 8c4833f..bc319ec 100644 --- a/src/boot/loader.h +++ b/src/boot/loader.h @@ -5,18 +5,36 @@ #include #include "kernel_args.h" +#include "memory.h" +#include "types.h" namespace boot { + +namespace fs { class file; } + namespace loader { +/// 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 type Memory type to use for allocation +buffer +load_file( + fs::file &disk, + const wchar_t *name, + const wchar_t *path, + uefi::memory_type type = uefi::memory_type::loader_data); + /// Parse and load an ELF file in memory into a loaded image. -/// \arg data The start of the ELF file in memory -/// \arg size The size of the ELF file in memory -/// \arg args The kernel args, used for modifying page tables -/// \returns A descriptor defining the loaded image -kernel::entrypoint load( - const void *data, size_t size, - kernel::args::header *args, +/// \arg program The program structure to fill +/// \arg data Buffer of the ELF file in memory +/// \arg bs Boot services +void +load_program( + kernel::args::program &program, + const wchar_t *name, + buffer data, uefi::boot_services *bs); } // namespace loader diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 7a923c2..832691f 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -21,9 +21,24 @@ namespace kernel { #include "kernel_memory.h" } +namespace args = kernel::args; + namespace boot { -constexpr int max_modules = 10; // Max modules to allocate room for +constexpr int max_modules = 5; // Max modules to allocate room for +constexpr int max_programs = 5; // Max programs to allocate room for + +struct program_desc +{ + const wchar_t *name; + const wchar_t *path; +}; + +const program_desc program_list[] = { + {L"kernel", L"jsix.elf"}, + {L"null driver", L"nulldrv.elf"}, + {L"terminal driver", L"terminal.elf"}, +}; /// Change a pointer to point to the higher-half linear-offset version /// of the address it points to. @@ -34,19 +49,21 @@ void change_pointer(T *&pointer) } /// Allocate space for kernel args. Allocates enough space from pool -/// memory for the args header and `max_modules` module headers. -kernel::args::header * +/// memory for the args header and the module and program headers. +args::header * allocate_args_structure( uefi::boot_services *bs, - size_t max_modules) + size_t max_modules, + size_t max_programs) { status_line status(L"Setting up kernel args memory"); - kernel::args::header *args = nullptr; + args::header *args = nullptr; size_t args_size = - sizeof(kernel::args::header) + // The header itself - max_modules * sizeof(kernel::args::module); // The module structures + sizeof(args::header) + // The header itself + max_modules * sizeof(args::module) + // The module structures + max_programs * sizeof(args::program); // The program structures try_or_raise( bs->allocate_pool(memory::args_type, args_size, @@ -56,47 +73,34 @@ allocate_args_structure( bs->set_mem(args, args_size, 0); args->modules = - reinterpret_cast(args + 1); + reinterpret_cast(args + 1); args->num_modules = 0; + args->programs = + reinterpret_cast(args->modules + max_modules); + args->num_programs = 0; + return args; } -/// Load a file from disk into memory. Also adds an entry to the kernel -/// args module headers pointing at the loaded data. -/// \arg disk The opened UEFI filesystem to load from -/// \arg args The kernel args header to update with module information -/// \arg name Name of the module (informational only) -/// \arg path Path on `disk` of the file to load -/// \arg type Type specifier of this module (eg, initrd or kernel) -kernel::args::module * -load_module( - fs::file &disk, - kernel::args::header *args, - const wchar_t *name, - const wchar_t *path, - kernel::args::mod_type type) +/// Add a module to the kernel args list +inline void +add_module(args::header *args, args::mod_type type, buffer &data) { - status_line status(L"Loading module", name); - - fs::file file = disk.open(path); - kernel::args::module &module = args->modules[args->num_modules++]; - module.type = type; - module.location = file.load(&module.size, memory::module_type); - - console::print(L" Loaded at: 0x%lx, %d bytes\r\n", module.location, module.size); - return &module; + args::module &m = args->modules[args->num_modules++]; + m.type = type; + m.location = data.data; + m.size = data.size; } /// 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. -kernel::args::header * +args::header * bootloader_main_uefi( uefi::handle image, uefi::system_table *st, - console &con, - kernel::entrypoint *kentry) + console &con) { error::uefi_handler handler(con); status_line status(L"Performing UEFI pre-boot"); @@ -105,27 +109,32 @@ bootloader_main_uefi( uefi::runtime_services *rs = st->runtime_services; memory::init_pointer_fixup(bs, rs); - kernel::args::header *args = - allocate_args_structure(bs, max_modules); + args::header *args = + allocate_args_structure(bs, max_modules, max_programs); - args->magic = kernel::args::magic; - args->version = kernel::args::version; + args->magic = args::magic; + args->version = args::version; args->runtime_services = rs; args->acpi_table = hw::find_acpi_table(st); + paging::allocate_tables(args, bs); memory::mark_pointer_fixup(&args->runtime_services); fs::file disk = fs::get_boot_volume(image, bs); - load_module(disk, args, L"initrd", L"initrd.img", kernel::args::mod_type::initrd); - kernel::args::module *kernel = - load_module(disk, args, L"kernel", L"jsix.elf", kernel::args::mod_type::kernel); + const uefi::memory_type mod_type = memory::module_type; + buffer symbols = loader::load_file(disk, L"symbol table", L"symbol_table.dat", + memory::module_type); + add_module(args, args::mod_type::symbol_table, symbols); - paging::allocate_tables(args, bs); - *kentry = loader::load(kernel->location, kernel->size, args, bs); + for (auto &desc : program_list) { + buffer buf = loader::load_file(disk, desc.name, desc.path); + args::program &program = args->programs[args->num_programs++]; + loader::load_program(program, desc.name, buf, bs); + } for (unsigned i = 0; i < args->num_modules; ++i) { - kernel::args::module &mod = args->modules[i]; + args::module &mod = args->modules[i]; change_pointer(mod.location); } @@ -143,9 +152,13 @@ efi_main(uefi::handle image_handle, uefi::system_table *st) error::cpu_assert_handler handler; console con(st->boot_services, st->con_out); - kernel::entrypoint kentry = nullptr; - kernel::args::header *args = - bootloader_main_uefi(image_handle, st, con, &kentry); + args::header *args = + bootloader_main_uefi(image_handle, st, con); + + args::program &kernel = args->programs[0]; + paging::map_pages(args, kernel.phys_addr, kernel.virt_addr, kernel.size); + kernel::entrypoint kentry = + reinterpret_cast(kernel.entrypoint); memory::efi_mem_map map = memory::build_kernel_mem_map(args, st->boot_services); diff --git a/src/boot/memory.cpp b/src/boot/memory.cpp index ddb6d20..7784bf2 100644 --- a/src/boot/memory.cpp +++ b/src/boot/memory.cpp @@ -45,7 +45,7 @@ memory_type_name(uefi::memory_type t) switch(t) { case args_type: return L"jsix kernel args"; case module_type: return L"jsix bootloader module"; - case kernel_type: return L"jsix kernel code"; + case program_type: return L"jsix kernel or program code"; case table_type: return L"jsix page tables"; default: return L"Bad Type Value"; } @@ -195,8 +195,8 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs) type = mem_type::module; break; - case kernel_type: - type = mem_type::kernel; + case program_type: + type = mem_type::program; break; case table_type: @@ -233,21 +233,7 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs) // Give just the actually-set entries in the header args->mem_map = kernel_map; - args->num_map_entries = i; - - // But pass the entire allocated area in a module as well - kernel::args::module &module = args->modules[args->num_modules++]; - module.location = reinterpret_cast(kernel_map); - module.size = map_size; - module.type = kernel::args::mod_type::memory_map; - - /* - for (size_t i = 0; imap_count = i; return efi_map; } diff --git a/src/boot/memory.h b/src/boot/memory.h index 2a51688..e1c5715 100644 --- a/src/boot/memory.h +++ b/src/boot/memory.h @@ -30,8 +30,8 @@ constexpr uefi::memory_type args_type = constexpr uefi::memory_type module_type = static_cast(0x80000001); -/// Memory containing loaded kernel code and data sections -constexpr uefi::memory_type kernel_type = +/// Memory containing loaded kernel or program code and data sections +constexpr uefi::memory_type program_type = static_cast(0x80000002); /// Memory containing page tables set up by the loader diff --git a/src/boot/paging.cpp b/src/boot/paging.cpp index fab4c38..948ff22 100644 --- a/src/boot/paging.cpp +++ b/src/boot/paging.cpp @@ -67,7 +67,7 @@ public: uintptr_t virt, page_table *pml4, void *&page_cache, - uint32_t &cache_count) : + size_t &cache_count) : m_page_cache(page_cache), m_cache_count(cache_count) { @@ -130,14 +130,14 @@ private: } void *&m_page_cache; - uint32_t &m_cache_count; + size_t &m_cache_count; page_table *m_table[D]; uint16_t m_index[D]; }; static void -add_offset_mappings(page_table *pml4, void *&page_cache, uint32_t &num_pages) +add_offset_mappings(page_table *pml4, void *&page_cache, size_t &num_pages) { uintptr_t phys = 0; uintptr_t virt = ::memory::page_offset; // Start of offset-mapped area @@ -160,7 +160,7 @@ add_offset_mappings(page_table *pml4, void *&page_cache, uint32_t &num_pages) } static void -add_kernel_pds(page_table *pml4, void *&page_cache, uint32_t &num_pages) +add_kernel_pds(page_table *pml4, void *&page_cache, size_t &num_pages) { for (unsigned i = pml4e_kernel; i < table_entries; ++i) { pml4->set(i, page_cache, table_flags); @@ -208,34 +208,31 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs) bs->set_mem(addr, tables_needed*page_size, 0); - kernel::args::module &mod = args->modules[++args->num_modules]; - mod.type = kernel::args::mod_type::page_tables; - mod.location = addr; - mod.size = tables_needed*page_size; - args->pml4 = addr; - args->num_free_tables = tables_needed - 1; - args->page_table_cache = offset_ptr(addr, page_size); + args->table_count = tables_needed - 1; + args->page_tables = offset_ptr(addr, page_size); page_table *pml4 = reinterpret_cast(addr); - add_kernel_pds(pml4, args->page_table_cache, args->num_free_tables); - add_offset_mappings(pml4, args->page_table_cache, args->num_free_tables); + add_kernel_pds(pml4, args->page_tables, args->table_count); + add_offset_mappings(pml4, args->page_tables, args->table_count); - console::print(L" Set up initial mappings, %d spare tables.\r\n", args->num_free_tables); + console::print(L" Set up initial mappings, %d spare tables.\r\n", args->table_count); } void map_pages( - page_table *pml4, kernel::args::header *args, uintptr_t phys, uintptr_t virt, size_t size) { + paging::page_table *pml4 = + reinterpret_cast(args->pml4); + size_t pages = memory::bytes_to_pages(size); page_entry_iterator<4> iterator{ virt, pml4, - args->page_table_cache, - args->num_free_tables}; + args->page_tables, + args->table_count}; while (true) { *iterator = phys | page_flags; diff --git a/src/boot/paging.h b/src/boot/paging.h index c47af99..437d41c 100644 --- a/src/boot/paging.h +++ b/src/boot/paging.h @@ -39,13 +39,11 @@ void allocate_tables( void add_current_mappings(page_table *new_pml4); /// Map a physical address to a virtual address in the given page tables. -/// \arg pml4 The root of the set of page tables to be updated -/// \arg args The kernel args header, used for the page table cache +/// \arg args The kernel args header, used for the page table cache and pml4 /// \arg phys The phyiscal address to map in /// \arg virt The virtual address to map in /// \arg size The size in bytes of the mapping void map_pages( - page_table *pml4, kernel::args::header *args, uintptr_t phys, uintptr_t virt, size_t bytes); diff --git a/src/boot/types.h b/src/boot/types.h new file mode 100644 index 0000000..23a9291 --- /dev/null +++ b/src/boot/types.h @@ -0,0 +1,13 @@ +/// \file types.h +/// Definitions of shared types used throughout the bootloader +#pragma once + +namespace boot { + +struct buffer +{ + size_t size; + void *data; +}; + +} // namespace boot diff --git a/src/include/kernel_args.h b/src/include/kernel_args.h index dcdedf9..c02f0b4 100644 --- a/src/include/kernel_args.h +++ b/src/include/kernel_args.h @@ -10,42 +10,28 @@ namespace args { constexpr uint32_t magic = 0x600dda7a; constexpr uint16_t version = 1; -enum class mod_flags : uint32_t -{ - debug = 0x00000001 -}; - enum class mod_type : uint32_t { - unknown, - - kernel, - initrd, - - memory_map, - page_tables, - framebuffer, - - max -}; - -enum class mode : uint8_t { - normal, - debug + symbol_table, + framebuffer }; struct module { void *location; size_t size; mod_type type; - mod_flags flags; -} -__attribute__((packed)); +}; +struct program { + uintptr_t phys_addr; + uintptr_t virt_addr; + uintptr_t entrypoint; + size_t size; +}; enum class mem_type : uint32_t { free, args, - kernel, + program, module, table, acpi, @@ -61,33 +47,35 @@ struct mem_entry size_t pages; mem_type type; uint32_t attr; -} -__attribute__((packed)); +}; +enum class boot_flags : uint16_t { + none = 0x0000, + debug = 0x0001 +}; struct header { uint32_t magic; uint16_t version; - - mode mode; - - uint8_t _reserved0; + boot_flags flags; void *pml4; - void *page_table_cache; - uint32_t num_free_tables; + void *page_tables; + size_t table_count; + + program *programs; + size_t num_programs; - uint32_t num_modules; module *modules; + size_t num_modules; mem_entry *mem_map; - size_t num_map_entries; + size_t map_count; void *runtime_services; void *acpi_table; } __attribute__((aligned(alignof(max_align_t)))); -#pragma pack(pop) } // namespace args diff --git a/src/kernel/loader.s b/src/kernel/loader.s index 8720435..761231d 100644 --- a/src/kernel/loader.s +++ b/src/kernel/loader.s @@ -2,21 +2,20 @@ extern load_process_image -global ramdisk_process_loader -ramdisk_process_loader: +global preloaded_process_init +preloaded_process_init: - ; create_process already pushed a cpu_state onto the stack for us, this - ; acts both as the cpu_state parameter to load_process_image, and the - ; saved state for the following iretq + ; create_process already pushed the arguments for load_process_image and + ; the following iretq onto the stack for us - pop rdi ; the address of the program image - pop rsi ; the size of the program image - pop rdx ; the address of this thread's TCB + pop rdi ; the physical address of the program image + pop rsi ; the virtual address of the program image + pop rdx ; the size in bytes of the program image + pop rcx ; the address of this thread's TCB call load_process_image - push rax ; load_process_image returns the process entrypoint - + ; the entrypoint should already be on the stack swapgs iretq diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index bb8f0f2..28188e7 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -3,7 +3,6 @@ #include "j6/signals.h" -#include "initrd/initrd.h" #include "kutil/assert.h" #include "apic.h" #include "block_device.h" @@ -117,56 +116,31 @@ kernel_main(args::header *header) cpu_id cpu; cpu.validate(); - /* - if (header->frame_buffer && header->frame_buffer_length) { - page_manager::get()->map_offset_pointer( - &header->frame_buffer, - header->frame_buffer_length); + for (size_t i = 0; i < header->num_modules; ++i) { + args::module &mod = header->modules[i]; + switch (mod.type) { + case args::mod_type::symbol_table: + new symbol_table {mod.location, mod.size}; + break; + + default: + break; + } } - */ log::debug(logs::boot, " jsix header is at: %016lx", header); log::debug(logs::boot, " Memory map is at: %016lx", header->mem_map); log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table); log::debug(logs::boot, "Runtime service is at: %016lx", header->runtime_services); - // Load the module tagged as initrd - kutil::vector initrds; - for (unsigned i = 0; i < header->num_modules; ++i) { - args::module &mod = header->modules[i]; - if (mod.type != args::mod_type::initrd) - continue; - - initrd::disk &ird = initrds.emplace(mod.location); - log::info(logs::boot, "initrd loaded with %d files.", ird.files().count()); - for (auto &f : ird.files()) { - char type = f.executable() ? '*' : - f.symbols() ? '+' : ' '; - log::info(logs::boot, " %c%s (%d bytes).", type, f.name(), f.size()); - } - } - - /* - page_manager::get()->dump_pml4(nullptr, 0); - page_manager::get()->dump_blocks(true); - */ - device_manager &devices = device_manager::get(); devices.parse_acpi(header->acpi_table); interrupts_enable(); - - /* - auto r = cpu.get(0x15); - log::info(logs::boot, "CPU Crystal: %dHz", r.ecx); - - uintptr_t cr4 = 0; - __asm__ __volatile__ ( "mov %%cr4, %0" : "=r" (cr4) ); - log::info(logs::boot, "cr4: %016x", cr4); - */ - devices.init_drivers(); + devices.get_lapic()->calibrate_timer(); + /* block_device *disk = devices->get_block_device(0); if (disk) { @@ -191,22 +165,15 @@ kernel_main(args::header *header) } */ - devices.get_lapic()->calibrate_timer(); - devices.init_drivers(); - syscall_enable(); scheduler *sched = new scheduler(devices.get_lapic()); std_out = new channel; - for (auto &ird : initrds) { - for (auto &f : ird.files()) { - if (f.executable()) { - sched->load_process(f.name(), f.data(), f.size()); - } else if (f.symbols()) { - new symbol_table {f.data(), f.size()}; - } - } + // Skip program 0, which is the kernel itself + for (size_t i = 1; i < header->num_programs; ++i) { + args::program &prog = header->programs[i]; + sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint); } sched->create_kernel_task(logger_task, scheduler::max_priority-1, true); diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index a3c4129..4d621aa 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -103,20 +103,19 @@ void walk_page_table( void memory_initialize_pre_ctors(args::header *kargs) { - args::mem_entry *entries = kargs->mem_map; - size_t entry_count = kargs->num_map_entries; - page_table *kpml4 = reinterpret_cast(kargs->pml4); - new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap}; - new (&g_frame_allocator) frame_allocator; - for (unsigned i = 0; i < entry_count; ++i) { + + args::mem_entry *entries = kargs->mem_map; + const size_t count = kargs->map_count; + for (unsigned i = 0; i < count; ++i) { // TODO: use entry attributes args::mem_entry &e = entries[i]; if (e.type == args::mem_type::free) g_frame_allocator.free(e.start, e.pages); } + page_table *kpml4 = reinterpret_cast(kargs->pml4); process *kp = process::create_kernel_process(kpml4); vm_space &vm = kp->space(); @@ -153,7 +152,7 @@ memory_initialize_post_ctors(args::header *kargs) vm.add(memory::buffers_start, &g_kernel_buffers); g_frame_allocator.free( - reinterpret_cast(kargs->page_table_cache), - kargs->num_free_tables); + reinterpret_cast(kargs->page_tables), + kargs->table_count); } diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index 8979136..b0cdb5a 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -16,7 +16,6 @@ #include "objects/vm_area.h" #include "scheduler.h" -#include "elf/elf.h" #include "kutil/assert.h" @@ -26,8 +25,8 @@ const uint64_t rflags_noint = 0x002; const uint64_t rflags_int = 0x202; extern "C" { - void ramdisk_process_loader(); - uintptr_t load_process_image(const void *image_start, size_t bytes, TCB *tcb); + void preloaded_process_init(); + void load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb); }; extern uint64_t idle_stack_end; @@ -60,8 +59,8 @@ scheduler::scheduler(lapic *apic) : bsp_cpu_data.t = idle; } -uintptr_t -load_process_image(const void *image_start, size_t bytes, TCB *tcb) +void +load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb) { using memory::page_align_down; using memory::page_align_up; @@ -71,53 +70,9 @@ load_process_image(const void *image_start, size_t bytes, TCB *tcb) process &proc = process::current(); vm_space &space = proc.space(); - log::debug(logs::loader, "Loading task! ELF: %016lx [%d]", image_start, bytes); - - // TODO: Handle bad images gracefully - elf::elf image(image_start, bytes); - kassert(image.valid(), "Invalid ELF passed to load_process_image"); - - uintptr_t vma_base = -1; - uintptr_t vma_end = 0; - - const unsigned program_count = image.program_count(); - for (unsigned i = 0; i < program_count; ++i) { - const elf::program_header *header = image.program(i); - - if (header->type != elf::segment_type::load) - continue; - - uintptr_t base = page_align_down(header->vaddr); - uintptr_t end = page_align_up(header->vaddr + header->mem_size); - if (base < vma_base) vma_base = base; - if (end > vma_end) vma_end = end; - - log::debug(logs::loader, " Loadable segment %02u: vaddr %016lx size %016lx", - i, header->vaddr, header->mem_size); - - log::debug(logs::loader, " - aligned to: vaddr %016lx pages %d", - base, memory::page_count(end-base)); - } - - vm_area *vma = new vm_area_open(vma_end - vma_base, space, - vm_flags::zero|vm_flags::write); - space.add(vma_base, vma); - - const unsigned section_count = image.section_count(); - for (unsigned i = 0; i < section_count; ++i) { - const elf::section_header *header = image.section(i); - - if (header->type != elf::section_type::progbits || - !bitfield_has(header->flags, elf::section_flags::alloc)) - continue; - - log::debug(logs::loader, " Loadable section %02u: vaddr %016lx size %016lx", - i, header->addr, header->size); - - void *dest = reinterpret_cast(header->addr); - const void *src = kutil::offset_pointer(image_start, header->offset); - kutil::memcpy(dest, src, header->size); - } + vm_area *vma = new vm_area_open(bytes, space, vm_flags::zero|vm_flags::write); + space.add(virt, vma); + vma->commit(phys, 0, memory::page_count(bytes)); tcb->rsp3 -= 2 * sizeof(uint64_t); uint64_t *sentinel = reinterpret_cast(tcb->rsp3); @@ -130,10 +85,6 @@ load_process_image(const void *image_start, size_t bytes, TCB *tcb) init->output = proc.add_handle(std_out); thread::current().clear_state(thread::state::loading); - - uintptr_t entrypoint = image.entrypoint(); - log::debug(logs::loader, " Loaded! New thread rip: %016lx", entrypoint); - return entrypoint; } thread * @@ -153,7 +104,7 @@ scheduler::create_process(bool user) } void -scheduler::load_process(const char *name, const void *data, size_t size) +scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry) { uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0 @@ -166,25 +117,27 @@ scheduler::load_process(const char *name, const void *data, size_t size) auto *tcb = th->tcb(); // Create an initial kernel stack space - uintptr_t *stack = reinterpret_cast(tcb->rsp0) - 7; + uintptr_t *stack = reinterpret_cast(tcb->rsp0) - 9; - // Pass args to ramdisk_process_loader on the stack - stack[0] = reinterpret_cast(data); - stack[1] = reinterpret_cast(size); - stack[2] = reinterpret_cast(tcb); + // Pass args to preloaded_process_init on the stack + stack[0] = reinterpret_cast(phys); + stack[1] = reinterpret_cast(virt); + stack[2] = reinterpret_cast(size); + stack[3] = reinterpret_cast(tcb); tcb->rsp = reinterpret_cast(stack); - th->add_thunk_kernel(reinterpret_cast(ramdisk_process_loader)); + th->add_thunk_kernel(reinterpret_cast(preloaded_process_init)); // Arguments for iret - rip will be pushed on before these - stack[3] = cs; - stack[4] = rflags_int; - stack[5] = process::stacks_top; - stack[6] = ss; + stack[4] = reinterpret_cast(entry); + stack[5] = cs; + stack[6] = rflags_int; + stack[7] = process::stacks_top; + stack[8] = ss; tcb->rsp3 = process::stacks_top; - log::debug(logs::task, "Loading thread %s: koid %llx pri %d", name, th->koid(), tcb->priority); + log::debug(logs::task, "Loading thread %llx pri %d", th->koid(), tcb->priority); log::debug(logs::task, " RSP %016lx", tcb->rsp); log::debug(logs::task, " RSP0 %016lx", tcb->rsp0); log::debug(logs::task, " PML4 %016lx", tcb->pml4); diff --git a/src/kernel/scheduler.h b/src/kernel/scheduler.h index c6fa4b6..9718fd1 100644 --- a/src/kernel/scheduler.h +++ b/src/kernel/scheduler.h @@ -41,10 +41,11 @@ public: scheduler(lapic *apic); /// Create a new process from a program image in memory. - /// \arg name Name of the program image - /// \arg data Pointer to the image data + /// \arg phys Physical address of the loaded program image + /// \arg virt Virtual address of the loaded program image /// \arg size Size of the program image, in bytes - void load_process(const char *name, const void *data, size_t size); + /// \arg entry Virtual address of the program entrypoint + void load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry); /// Create a new kernel task /// \arg proc Function to run as a kernel task diff --git a/src/libraries/kutil/printf.c b/src/libraries/kutil/printf.c index e4572d2..c2055d7 100644 --- a/src/libraries/kutil/printf.c +++ b/src/libraries/kutil/printf.c @@ -35,6 +35,7 @@ #include "kutil/printf.h" +#define PRINTF_DISABLE_SUPPORT_FLOAT // define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the // printf_config.h header file