diff --git a/src/boot/elf.h b/src/boot/elf.h index 9743a96..a399f07 100644 --- a/src/boot/elf.h +++ b/src/boot/elf.h @@ -7,13 +7,13 @@ namespace elf { constexpr uint8_t version = 1; constexpr uint8_t word_size = 2; constexpr uint8_t endianness = 1; -constexpr uint8_t os_abi = 1; +constexpr uint8_t os_abi = 0; constexpr uint16_t machine = 0x3e; -const unsigned ELF_PT_LOAD = 1; -const unsigned ELF_ST_PROGBITS = 1; -const unsigned ELF_ST_NOBITS = 8; -const unsigned long ELF_SHF_ALLOC = 0x2; +const unsigned PT_LOAD = 1; +const unsigned ST_PROGBITS = 1; +const unsigned ST_NOBITS = 8; +const unsigned long SHF_ALLOC = 0x2; struct header { diff --git a/src/boot/fs.cpp b/src/boot/fs.cpp index c375b38..f5ee1c1 100644 --- a/src/boot/fs.cpp +++ b/src/boot/fs.cpp @@ -51,7 +51,7 @@ file::open(const wchar_t *path) } void * -file::load(size_t *out_size) +file::load(size_t *out_size, uefi::memory_type mem_type) { uint8_t buffer[sizeof(uefi::protos::file_info) + 100]; size_t size = sizeof(buffer); @@ -69,8 +69,7 @@ file::load(size_t *out_size) try_or_raise( m_bs->allocate_pages( uefi::allocate_type::any_pages, - uefi::memory_type::loader_data, - pages, &data), + mem_type, pages, &data), L"Could not allocate pages to load file"); size = info->file_size; diff --git a/src/boot/fs.h b/src/boot/fs.h index fcd87ab..c993579 100644 --- a/src/boot/fs.h +++ b/src/boot/fs.h @@ -15,7 +15,9 @@ public: ~file(); file open(const wchar_t *path); - void * load(size_t *out_size); + void * load( + size_t *out_size, + 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 5f2ce60..578e34c 100644 --- a/src/boot/loader.cpp +++ b/src/boot/loader.cpp @@ -5,87 +5,86 @@ #include "console.h" #include "elf.h" #include "error.h" +#include "memory.h" namespace boot { namespace loader { +using memory::offset_ptr; + static bool is_elfheader_valid(const elf::header *header) { - return false; + return + header->magic[0] == 0x7f && + header->magic[1] == 'E' && + header->magic[2] == 'L' && + header->magic[3] == 'F' && + header->word_size == elf::word_size && + header->endianness == elf::endianness && + header->os_abi == elf::os_abi && + header->machine == elf::machine && + header->header_version == elf::version; } -kernel::entrypoint -load_elf( +loaded_elf +load( const void *data, size_t size, uefi::boot_services *bs) { status_line status(L"Loading kernel ELF binary"); + const elf::header *header = reinterpret_cast(data); - if (size < sizeof(elf::header) || - !is_elfheader_valid(reinterpret_cast(data))) + if (size < sizeof(elf::header) || !is_elfheader_valid(header)) error::raise(uefi::status::load_error, L"Kernel ELF not valid"); - /* - struct elf_program_header prog_header; - for (int i = 0; i < header.ph_num; ++i) { + uintptr_t kernel_start = 0; + uintptr_t kernel_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); - status = file->SetPosition(file, header.ph_offset + i * header.ph_entsize); - CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); - - length = header.ph_entsize; - status = file->Read(file, &length, &prog_header); - CHECK_EFI_STATUS_OR_RETURN(status, L"Reading ELF program header"); - - if (prog_header.type != ELF_PT_LOAD) continue; - - length = prog_header.mem_size; - void *addr = (void *)(prog_header.vaddr - KERNEL_VIRT_ADDRESS); - status = loader_alloc_pages(bootsvc, memtype_kernel, &length, &addr); - CHECK_EFI_STATUS_OR_RETURN(status, L"Allocating kernel pages"); - - if (data->kernel == 0) - data->kernel = addr; - data->kernel_length = (uint64_t)addr + length - (uint64_t)data->kernel; - } - con_debug(L"Read %d ELF program headers", header.ph_num); - - struct elf_section_header sec_header; - for (int i = 0; i < header.sh_num; ++i) { - status = file->SetPosition(file, header.sh_offset + i * header.sh_entsize); - CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); - - length = header.sh_entsize; - status = file->Read(file, &length, &sec_header); - CHECK_EFI_STATUS_OR_RETURN(status, L"Reading ELF section header"); - - if ((sec_header.flags & ELF_SHF_ALLOC) == 0) { + if (pheader->type != elf::PT_LOAD) continue; - } - void *addr = (void *)(sec_header.addr - KERNEL_VIRT_ADDRESS); + if (kernel_start == 0 || pheader->vaddr < kernel_start) + kernel_start = pheader->vaddr; - if (sec_header.type == ELF_ST_PROGBITS) { - status = file->SetPosition(file, sec_header.offset); - CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); - - length = sec_header.size; - status = file->Read(file, &length, addr); - CHECK_EFI_STATUS_OR_RETURN(status, L"Reading file"); - } else if (sec_header.type == ELF_ST_NOBITS) { - bootsvc->SetMem(addr, sec_header.size, 0); - } + if (pheader->vaddr + pheader->mem_size > kernel_end) + kernel_end = pheader->vaddr + pheader->mem_size; } - con_debug(L"Read %d ELF section headers", header.ph_num); - status = file->Close(file); - CHECK_EFI_STATUS_OR_RETURN(status, L"Closing file handle"); + void *pages = nullptr; + size_t num_pages = memory::bytes_to_pages(kernel_end - kernel_start); + try_or_raise( + bs->allocate_pages(uefi::allocate_type::any_pages, + memory::kernel_type, num_pages, &pages), + L"Failed allocating space for kernel code"); - return reinterpret_cast(kernel.entrypoint()); - */ + 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); - return nullptr; + if (pheader->type != elf::PT_LOAD) + continue; + + void *data_start = offset_ptr(data, pheader->offset); + void *program_start = offset_ptr(pages, pheader->vaddr - kernel_start); + bs->copy_mem(program_start, data_start, pheader->mem_size); + } + + loaded_elf result; + result.data = pages; + result.vaddr = kernel_start; + result.entrypoint = header->entrypoint; + console::print(L" Kernel loaded at: 0x%lx\r\n", result.data); + console::print(L" Kernel virtual address: 0x%lx\r\n", result.vaddr); + console::print(L" Kernel entrypoint: 0x%lx\r\n", result.entrypoint); + + return result; } } // namespace loader diff --git a/src/boot/loader.h b/src/boot/loader.h index 9f923c5..c4d1d9c 100644 --- a/src/boot/loader.h +++ b/src/boot/loader.h @@ -1,11 +1,16 @@ #pragma once -#include "kernel_args.h" - namespace boot { namespace loader { -kernel::entrypoint load_elf(const void *data, size_t size, uefi::boot_services *bs); +struct loaded_elf +{ + void *data; + uintptr_t vaddr; + uintptr_t entrypoint; +}; + +loaded_elf load(const void *data, size_t size, uefi::boot_services *bs); } // namespace loader } // namespace boot diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 523d9c7..d10b152 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -91,20 +91,20 @@ load_module( kernel::args::header *args, const wchar_t *name, const wchar_t *path, - kernel::args::type type) + kernel::args::mod_type type) { 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); + 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; } -kernel::entrypoint +loader::loaded_elf bootloader_main_uefi(uefi::handle image, uefi::system_table *st, console &con) { error::uefi_handler handler(con); @@ -123,13 +123,17 @@ bootloader_main_uefi(uefi::handle image, uefi::system_table *st, console &con) args->acpi_table = hw::find_acpi_table(st); fs::file disk = fs::get_boot_volume(image, bs); - load_module(disk, args, L"initrd", L"initrd.img", kernel::args::type::initrd); + 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::type::kernel); + load_module(disk, args, L"kernel", L"jsix.elf", kernel::args::mod_type::kernel); - kernel::entrypoint entry = loader::load_elf(kernel->location, kernel->size, bs); - return entry; + + loader::loaded_elf kernel_elf = + loader::load(kernel->location, kernel->size, bs); + + memory::get_mappings(bs); + return kernel_elf; } /* @@ -242,7 +246,7 @@ 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 kernel_main = + loader::loaded_elf kernel = bootloader_main_uefi(image_handle, st, con); while(1); diff --git a/src/boot/memory.cpp b/src/boot/memory.cpp index b10c501..dafa734 100644 --- a/src/boot/memory.cpp +++ b/src/boot/memory.cpp @@ -8,53 +8,43 @@ namespace boot { namespace memory { -/* -const EFI_MEMORY_TYPE memtype_kernel = static_cast(0x80000000ul); -const EFI_MEMORY_TYPE memtype_data = static_cast(0x80000001ul); -const EFI_MEMORY_TYPE memtype_initrd = static_cast(0x80000002ul); -const EFI_MEMORY_TYPE memtype_scratch = static_cast(0x80000003ul); - -#define INCREMENT_DESC(p, b) (EFI_MEMORY_DESCRIPTOR*)(((uint8_t*)(p))+(b)) -*/ - size_t fixup_pointer_index = 0; void **fixup_pointers[64]; uint64_t *new_pml4 = 0; -/* -const wchar_t *memory_type_names[] = { - L"EfiReservedMemoryType", - L"EfiLoaderCode", - L"EfiLoaderData", - L"EfiBootServicesCode", - L"EfiBootServicesData", - L"EfiRuntimeServicesCode", - L"EfiRuntimeServicesData", - L"EfiConventionalMemory", - L"EfiUnusableMemory", - L"EfiACPIReclaimMemory", - L"EfiACPIMemoryNVS", - L"EfiMemoryMappedIO", - L"EfiMemoryMappedIOPortSpace", - L"EfiPalCode", - L"EfiPersistentMemory", +static const wchar_t *memory_type_names[] = { + L"reserved memory type", + L"loader code", + L"loader data", + L"boot services code", + L"boot services data", + L"runtime services code", + L"runtime services data", + L"conventional memory", + L"unusable memory", + L"acpi reclaim memory", + L"acpi memory nvs", + L"memory mapped io", + L"memory mapped io port space", + L"pal code", + L"persistent memory" }; static const wchar_t * -memory_type_name(UINT32 value) +memory_type_name(uefi::memory_type t) { - if (value >= (sizeof(memory_type_names) / sizeof(wchar_t *))) { - switch (value) { - case memtype_kernel: return L"Kernel Data"; - case memtype_data: return L"Kernel Data"; - case memtype_initrd: return L"Initial Ramdisk"; - case memtype_scratch: return L"Kernel Scratch Space"; - default: return L"Bad Type Value"; - } + if (t < uefi::memory_type::max_memory_type) { + return memory_type_names[static_cast(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 table_type: return L"jsix page tables"; + default: return L"Bad Type Value"; } - return memory_type_names[value]; } -*/ void update_marked_addresses(uefi::event, void *context) @@ -84,15 +74,13 @@ init_pointer_fixup(uefi::boot_services *bs, uefi::runtime_services *rs) &event), L"Error creating memory virtualization event"); - uefi::memory_type memtype = static_cast(0x80000003ul); - // Reserve a page for our replacement PML4, plus some pages for the kernel to use // as page tables while it gets started. void *addr = nullptr; try_or_raise( bs->allocate_pages( uefi::allocate_type::any_pages, - memtype, + table_type, 64, &addr), L"Error allocating page table pages."); @@ -111,81 +99,6 @@ mark_pointer_fixup(void **p) } /* -void -copy_desc(EFI_MEMORY_DESCRIPTOR *src, EFI_MEMORY_DESCRIPTOR *dst, size_t len) -{ - uint8_t *srcb = (uint8_t *)src; - uint8_t *dstb = (uint8_t *)dst; - uint8_t *endb = srcb + len; - while (srcb < endb) - *dstb++ = *srcb++; -} - -EFI_STATUS -memory_get_map_length(EFI_BOOT_SERVICES *bootsvc, size_t *size) -{ - if (size == NULL) - return EFI_INVALID_PARAMETER; - - EFI_STATUS status; - size_t key, desc_size; - uint32_t desc_version; - *size = 0; - status = bootsvc->GetMemoryMap(size, 0, &key, &desc_size, &desc_version); - if (status != EFI_BUFFER_TOO_SMALL) { - CHECK_EFI_STATUS_OR_RETURN(status, "Failed to get memory map size"); - } - return EFI_SUCCESS; -} - -EFI_STATUS -memory_get_map(EFI_BOOT_SERVICES *bootsvc, struct memory_map *map) -{ - EFI_STATUS status; - - if (map == NULL) - return EFI_INVALID_PARAMETER; - - size_t needs_size = 0; - status = memory_get_map_length(bootsvc, &needs_size); - if (EFI_ERROR(status)) return status; - - if (map->length < needs_size) - return EFI_BUFFER_TOO_SMALL; - - status = bootsvc->GetMemoryMap(&map->length, map->entries, &map->key, &map->size, &map->version); - CHECK_EFI_STATUS_OR_RETURN(status, "Failed to load memory map"); - return EFI_SUCCESS; -} - -EFI_STATUS -memory_dump_map(struct memory_map *map) -{ - if (map == NULL) - return EFI_INVALID_PARAMETER; - - const size_t count = map->length / map->size; - - console::print(L"Memory map:\n"); - console::print(L"\t Descriptor Count: %d (%d bytes)\n", count, map->length); - console::print(L"\t Descriptor Size: %d bytes\n", map->size); - console::print(L"\t Type offset: %d\n\n", offsetof(EFI_MEMORY_DESCRIPTOR, Type)); - - EFI_MEMORY_DESCRIPTOR *end = INCREMENT_DESC(map->entries, map->length); - EFI_MEMORY_DESCRIPTOR *d = map->entries; - while (d < end) { - int runtime = (d->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME; - console::print(L"%s%s ", memory_type_name(d->Type), runtime ? L"*" : L" "); - console::print(L"%lx ", d->PhysicalStart); - console::print(L"%lx ", d->VirtualStart); - console::print(L"[%4d]\n", d->NumberOfPages); - - d = INCREMENT_DESC(d, map->size); - } - - return EFI_SUCCESS; -} - void memory_virtualize(EFI_RUNTIME_SERVICES *runsvc, struct memory_map *map) { @@ -245,9 +158,7 @@ allocate_args_structure(uefi::boot_services *bs, size_t max_modules) max_modules * sizeof(kernel::args::module); // The module structures try_or_raise( - bs->allocate_pool( - uefi::memory_type::loader_data, - args_size, + bs->allocate_pool(args_type, args_size, reinterpret_cast(&args)), L"Could not allocate argument memory"); @@ -260,6 +171,51 @@ allocate_args_structure(uefi::boot_services *bs, size_t max_modules) return args; } +efi_mem_map +get_mappings(uefi::boot_services *bs) +{ + size_t needs_size = 0; + size_t map_key = 0; + size_t desc_size = 0; + uint32_t desc_version = 0; + + uefi::status status = bs->get_memory_map( + &needs_size, nullptr, &map_key, &desc_size, &desc_version); + + if (status != uefi::status::buffer_too_small) + error::raise(status, L"Error getting memory map size"); + + console::print(L"memory map needs %lu bytes\r\n", needs_size); + + size_t buffer_size = needs_size + 10*desc_size; + uefi::memory_descriptor *buffer = nullptr; + try_or_raise( + bs->allocate_pool( + uefi::memory_type::loader_data, buffer_size, + reinterpret_cast(&buffer)), + L"Allocating space for memory map"); + + try_or_raise( + bs->get_memory_map(&buffer_size, buffer, &map_key, &desc_size, &desc_version), + L"Getting UEFI memory map"); + + efi_mem_map map; + map.length = buffer_size; + map.size = desc_size; + map.key = map_key; + map.version = desc_version; + map.entries = buffer; + + for (auto desc : map) { + //for(size_t i = 0; i < map.num_entries(); ++i) { + //uefi::memory_descriptor *desc = map[i]; + console::print(L" Range %lx (%lx) %x(%s) [%lu]\r\n", + desc->physical_start, desc->attribute, desc->type, memory_type_name(desc->type), desc->number_of_pages); + } + + return map; +} + } // namespace boot } // namespace memory diff --git a/src/boot/memory.h b/src/boot/memory.h index f6436e2..e1d202e 100644 --- a/src/boot/memory.h +++ b/src/boot/memory.h @@ -9,6 +9,16 @@ namespace memory { constexpr size_t page_size = 0x1000; +constexpr uefi::memory_type args_type = static_cast(0x80000000); +constexpr uefi::memory_type module_type = static_cast(0x80000001); +constexpr uefi::memory_type kernel_type = static_cast(0x80000002); +constexpr uefi::memory_type table_type = static_cast(0x80000003); + +template +static T* offset_ptr(S* input, ptrdiff_t offset) { + return reinterpret_cast(reinterpret_cast(input) + offset); +} + inline constexpr size_t bytes_to_pages(size_t bytes) { return ((bytes - 1) / page_size) + 1; } @@ -21,20 +31,52 @@ void mark_pointer_fixup(void **p); kernel::args::header * allocate_args_structure(uefi::boot_services *bs, size_t max_modules); -/* -extern const EFI_MEMORY_TYPE memtype_kernel; -extern const EFI_MEMORY_TYPE memtype_data; -extern const EFI_MEMORY_TYPE memtype_initrd; -extern const EFI_MEMORY_TYPE memtype_scratch; +template +class offset_iterator +{ + T* m_t; + size_t m_off; +public: + offset_iterator(T* t, size_t offset=0) : m_t(t), m_off(offset) {} -struct memory_map { + T* operator++() { m_t = offset_ptr(m_t, m_off); return m_t; } + T* operator++(int) { T* tmp = m_t; operator++(); return tmp; } + bool operator==(T* p) { return p == m_t; } + + T* operator*() const { return m_t; } + operator T*() const { return m_t; } + T* operator->() const { return m_t; } +}; + +struct efi_mem_map { size_t length; size_t size; size_t key; uint32_t version; - EFI_MEMORY_DESCRIPTOR *entries; + uefi::memory_descriptor *entries; + + inline size_t num_entries() const { return length / size; } + + inline uefi::memory_descriptor * operator[](size_t i) { + size_t offset = i * size; + if (offset > length) return nullptr; + return offset_ptr(entries, offset); + } + + offset_iterator begin() { return offset_iterator(entries, size); } + offset_iterator end() { return offset_ptr(entries, length); } }; +efi_mem_map get_mappings(uefi::boot_services *bs); + +enum class memory_type +{ + free, + loader_used, + system_used +}; + +/* EFI_STATUS memory_get_map_length(EFI_BOOT_SERVICES *bootsvc, size_t *size); EFI_STATUS memory_get_map(EFI_BOOT_SERVICES *bootsvc, struct memory_map *map); EFI_STATUS memory_dump_map(struct memory_map *map); diff --git a/src/include/kernel_args.h b/src/include/kernel_args.h index 267aaaa..1edf511 100644 --- a/src/include/kernel_args.h +++ b/src/include/kernel_args.h @@ -10,12 +10,12 @@ namespace args { constexpr uint32_t magic = 0x600dda7a; constexpr uint16_t version = 1; -enum class flags : uint32_t +enum class mod_flags : uint32_t { debug = 0x00000001 }; -enum class type : uint32_t { +enum class mod_type : uint32_t { unknown, kernel, @@ -36,8 +36,8 @@ enum class mode : uint8_t { struct module { void *location; size_t size; - type type; - flags flags; + mod_type type; + mod_flags flags; }; struct header {