From b9af081a4499911e2d4a6abe51fdbf77f5473e0e Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Fri, 8 Jan 2021 22:40:30 -0800 Subject: [PATCH 1/9] [boot] Don't use custom UEFI memory types The UEFI spec specifically calls out memory types with the high bit set as being available for OS loaders' custom use. However, it seems many UEFI firmware implementations don't handle this well. (Virtualbox, and the firmware on my Intel NUC and Dell XPS laptop to name a few.) So sadly since we can't rely on this feature of UEFI in all cases, we can't use it at all. Instead, treat _all_ memory tagged as EfiLoaderData as possibly containing data that's been passed to the OS by the bootloader and don't free it yet. This will need to be followed up with a change that copies anything we need to save and frees this memory. See: https://github.com/kiznit/rainbow-os/blob/master/boot/machine/efi/README.md --- src/boot/loader.cpp | 2 +- src/boot/main.cpp | 5 ++--- src/boot/memory.cpp | 38 ++++++--------------------------- src/boot/memory.h | 22 ------------------- src/boot/paging.cpp | 2 +- src/include/kernel_args.h | 5 +---- src/kernel/memory_bootstrap.cpp | 1 + 7 files changed, 13 insertions(+), 62 deletions(-) diff --git a/src/boot/loader.cpp b/src/boot/loader.cpp index 1418d0c..3b5d748 100644 --- a/src/boot/loader.cpp +++ b/src/boot/loader.cpp @@ -82,7 +82,7 @@ load_program( try_or_raise( bs->allocate_pages(uefi::allocate_type::any_pages, - memory::program_type, num_pages, &pages), + uefi::memory_type::loader_data, num_pages, &pages), L"Failed allocating space for program"); bs->set_mem(pages, total_size, 0); diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 004087a..3f74ee4 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -67,7 +67,7 @@ allocate_args_structure( max_programs * sizeof(args::program); // The program structures try_or_raise( - bs->allocate_pool(memory::args_type, args_size, + bs->allocate_pool(uefi::memory_type::loader_data, args_size, reinterpret_cast(&args)), L"Could not allocate argument memory"); @@ -119,9 +119,8 @@ uefi_preboot(uefi::handle image, uefi::system_table *st) fs::file disk = fs::get_boot_volume(image, bs); - 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); + uefi::memory_type::loader_data); add_module(args, args::mod_type::symbol_table, symbols); for (auto &desc : program_list) { diff --git a/src/boot/memory.cpp b/src/boot/memory.cpp index 4e3c3e3..e0732b2 100644 --- a/src/boot/memory.cpp +++ b/src/boot/memory.cpp @@ -39,19 +39,10 @@ static const wchar_t *memory_type_names[] = { static const wchar_t * memory_type_name(uefi::memory_type t) { - if (t < uefi::memory_type::max_memory_type) { + 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 program_type: return L"jsix kernel or program code"; - case table_type: return L"jsix page tables"; - */ - default: return L"Bad Type Value"; - } + return L"Bad Type Value"; } void @@ -141,7 +132,7 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs) try_or_raise( bs->allocate_pages( uefi::allocate_type::any_pages, - module_type, + uefi::memory_type::loader_data, bytes_to_pages(map_size), reinterpret_cast(&kernel_map)), L"Error allocating kernel memory map module space"); @@ -166,13 +157,16 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs) continue; case uefi::memory_type::loader_code: - case uefi::memory_type::loader_data: case uefi::memory_type::boot_services_code: case uefi::memory_type::boot_services_data: case uefi::memory_type::conventional_memory: type = mem_type::free; break; + case uefi::memory_type::loader_data: + type = mem_type::pending; + break; + case uefi::memory_type::runtime_services_code: case uefi::memory_type::runtime_services_data: type = mem_type::uefi_runtime; @@ -191,24 +185,6 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs) type = mem_type::persistent; break; - /* - case args_type: - type = mem_type::args; - break; - - case module_type: - type = mem_type::module; - break; - - case program_type: - type = mem_type::program; - break; - - case table_type: - type = mem_type::table; - break; - */ - default: error::raise( uefi::status::invalid_parameter, diff --git a/src/boot/memory.h b/src/boot/memory.h index e1c5715..d8b8ed0 100644 --- a/src/boot/memory.h +++ b/src/boot/memory.h @@ -18,28 +18,6 @@ inline constexpr size_t bytes_to_pages(size_t bytes) { return ((bytes - 1) / page_size) + 1; } -/// \defgroup memory_types -/// Custom UEFI memory type values used for data being passed to the kernel -/// @{ - -/// Memory containing the kernel args structure -constexpr uefi::memory_type args_type = - static_cast(0x80000000); - -/// Memory containing any loaded modules to be passed to the kernel -constexpr uefi::memory_type module_type = - static_cast(0x80000001); - -/// 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 -constexpr uefi::memory_type table_type = - static_cast(0x80000003); - -/// @} - /// \defgroup pointer_fixup /// Memory virtualization pointer fixup functions. Handles changing affected pointers /// when calling UEFI's `set_virtual_address_map` function to change the location of diff --git a/src/boot/paging.cpp b/src/boot/paging.cpp index 475b88a..21f693d 100644 --- a/src/boot/paging.cpp +++ b/src/boot/paging.cpp @@ -202,7 +202,7 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs) try_or_raise( bs->allocate_pages( uefi::allocate_type::any_pages, - memory::table_type, + uefi::memory_type::loader_data, tables_needed, &addr), L"Error allocating page table pages."); diff --git a/src/include/kernel_args.h b/src/include/kernel_args.h index b793edd..36c81c6 100644 --- a/src/include/kernel_args.h +++ b/src/include/kernel_args.h @@ -44,10 +44,7 @@ struct program { enum class mem_type : uint32_t { free, - args, - program, - module, - table, + pending, acpi, uefi_runtime, mmio, diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index 4d621aa..114a5ce 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -110,6 +110,7 @@ memory_initialize_pre_ctors(args::header *kargs) const size_t count = kargs->map_count; for (unsigned i = 0; i < count; ++i) { // TODO: use entry attributes + // TODO: copy anything we need from "pending" memory and free it args::mem_entry &e = entries[i]; if (e.type == args::mem_type::free) g_frame_allocator.free(e.start, e.pages); From 45b52633bb4efd0ff33670b499299d90d4449d50 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 17 Jan 2021 10:28:54 -0800 Subject: [PATCH 2/9] [boot] Add scanline size to fb boot message Scanline size can differ from horizontal resolution in some framebuffers. This isn't currently handled, but at least log it so it's visible if this lack of handling is a potential error. --- src/boot/console.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/boot/console.cpp b/src/boot/console.cpp index b679735..02c9181 100644 --- a/src/boot/console.cpp +++ b/src/boot/console.cpp @@ -70,8 +70,8 @@ console::console(uefi::boot_services *bs, uefi::protos::simple_text_output *out) type = L"unknown"; } - printf(L"Found framebuffer: %dx%d type %s @0x%x\r\n", - m_fb.horizontal, m_fb.vertical, type, m_fb.phys_addr); + printf(L"Found framebuffer: %dx%d[%d] type %s @0x%x\r\n", + m_fb.horizontal, m_fb.vertical, m_fb.scanline, type, m_fb.phys_addr); } else { printf(L"No framebuffer found.\r\n"); } From cfeeba440064bd5ccab1e1e520ab64198cec54fa Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 17 Jan 2021 10:35:19 -0800 Subject: [PATCH 3/9] [kenrel] Ensure page tables are zeroed before use I forgot to zero out pages used for page tables, which didn't come back to bite me until testing on physical hardware.. --- src/kernel/page_table.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/page_table.cpp b/src/kernel/page_table.cpp index 5753e09..915493d 100644 --- a/src/kernel/page_table.cpp +++ b/src/kernel/page_table.cpp @@ -181,6 +181,7 @@ page_table::get_table_page() s_page_cache = s_page_cache->next; --s_cache_count; + kutil::memset(page, 0, memory::frame_size); return reinterpret_cast(page); } From 03b2d0dac713b9c9cd3a969c2ef5db785c557e3b Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 17 Jan 2021 20:49:47 -0800 Subject: [PATCH 4/9] [kernel] Set framebuffer to write-combining Several changes were needed to make this work: - Update the page_table::flags to understand memory caching types - Set up the PAT MSR to add the WC option - Make page-offset area mapped as WT - Add all the MTRR and PAT MSRs, and log the MTRRs for verification - Add a vm_area flag for write_combining --- src/boot/paging.cpp | 7 ++-- src/kernel/cpu_features.inc | 3 +- src/kernel/main.cpp | 43 ++++++++++++--------- src/kernel/memory_bootstrap.cpp | 66 +++++++++++++++++++++++++++++++++ src/kernel/msr.cpp | 6 +++ src/kernel/msr.h | 44 +++++++++++++++++----- src/kernel/objects/vm_area.h | 1 + src/kernel/page_table.h | 15 ++++++-- src/kernel/scheduler.cpp | 2 +- src/kernel/vm_space.cpp | 3 +- 10 files changed, 152 insertions(+), 38 deletions(-) diff --git a/src/boot/paging.cpp b/src/boot/paging.cpp index 21f693d..de61509 100644 --- a/src/boot/paging.cpp +++ b/src/boot/paging.cpp @@ -28,7 +28,7 @@ using ::memory::table_entries; /// Page table entry flags for entries pointing at a page constexpr uint16_t page_flags = 0x103; -// Flags: 0 0 0 0 1 1 0 0 0 0 0 1 1 = 0x0183 +// Flags: 0 0 0 0 1 1 0 0 0 1 0 1 1 = 0x018b // | IGN | | | | | | | | +- Present // | | | | | | | | +--- Writeable // | | | | | | | +----- Supervisor only @@ -209,11 +209,12 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs) bs->set_mem(addr, tables_needed*page_size, 0); - args->pml4 = addr; + page_table *pml4 = reinterpret_cast(addr); + + args->pml4 = pml4; 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_tables, args->table_count); add_offset_mappings(pml4, args->page_tables, args->table_count); diff --git a/src/kernel/cpu_features.inc b/src/kernel/cpu_features.inc index b455f53..34d3f54 100644 --- a/src/kernel/cpu_features.inc +++ b/src/kernel/cpu_features.inc @@ -7,8 +7,9 @@ CPU_FEATURE_REQ(pse, 0x00000001, 0, edx, 3) CPU_FEATURE_OPT(tsc, 0x00000001, 0, edx, 4) CPU_FEATURE_REQ(msr, 0x00000001, 0, edx, 5) CPU_FEATURE_REQ(apic, 0x00000001, 0, edx, 9) +CPU_FEATURE_REQ(mtrr, 0x00000001, 0, edx, 12) CPU_FEATURE_REQ(pge, 0x00000001, 0, edx, 13) -CPU_FEATURE_OPT(pat, 0x00000001, 0, edx, 16) +CPU_FEATURE_REQ(pat, 0x00000001, 0, edx, 16) CPU_FEATURE_REQ(fxsr, 0x00000001, 0, edx, 24) CPU_FEATURE_OPT(fsgsbase, 0x00000007, 0, ebx, 0) diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 6cd52f2..120a2b2 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -33,19 +33,10 @@ extern "C" { void (*__ctors_end)(void); } -void -run_constructors() -{ - void (**p)(void) = &__ctors; - while (p < &__ctors_end) { - void (*ctor)(void) = *p++; - ctor(); - } -} - extern void __kernel_assert(const char *, unsigned, const char *); /// Bootstrap the memory managers. +void setup_pat(); void memory_initialize_pre_ctors(kernel::args::header *kargs); void memory_initialize_post_ctors(kernel::args::header *kargs); @@ -66,6 +57,16 @@ init_console() cons->puts(GIT_VERSION " booting...\n"); } +void +run_constructors() +{ + void (**p)(void) = &__ctors; + while (p < &__ctors_end) { + void (*ctor)(void) = *p++; + ctor(); + } +} + channel *std_out = nullptr; void @@ -110,9 +111,23 @@ void kernel_main(args::header *header) { kutil::assert_set_callback(__kernel_assert); + init_console(); logger_init(); + setup_pat(); + + bool has_video = false; + if (header->video.size > 0) { + has_video = true; + fb = memory::to_virtual(reinterpret_cast(&header->video)); + + const args::framebuffer &video = header->video; + log::debug(logs::boot, "Framebuffer: %dx%d[%d] type %s @ %016llx", + video.horizontal, video.vertical, video.scanline, video.type, video.phys_addr); + logger_clear_immediate(); + } + gdt_init(); interrupts_init(); @@ -135,13 +150,6 @@ kernel_main(args::header *header) } } - bool has_video = false; - if (header->video.size > 0) { - fb = memory::to_virtual(reinterpret_cast(&header->video)); - has_video = true; - logger_clear_immediate(); - } - 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); @@ -152,7 +160,6 @@ kernel_main(args::header *header) interrupts_enable(); devices.init_drivers(); - devices.get_lapic()->calibrate_timer(); /* diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index 114a5ce..df8d726 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -9,6 +9,7 @@ #include "frame_allocator.h" #include "io.h" #include "log.h" +#include "msr.h" #include "objects/process.h" #include "objects/vm_area.h" #include "vm_space.h" @@ -100,6 +101,71 @@ void walk_page_table( } */ +static void +log_mtrrs() +{ + uint64_t mtrrcap = rdmsr(msr::ia32_mtrrcap); + uint64_t mtrrdeftype = rdmsr(msr::ia32_mtrrdeftype); + unsigned vcap = mtrrcap & 0xff; + log::debug(logs::boot, "MTRRs: vcap=%d %s %s def=%02x %s %s", + vcap, + (mtrrcap & (1<< 8)) ? "fix" : "", + (mtrrcap & (1<<10)) ? "wc" : "", + mtrrdeftype & 0xff, + (mtrrdeftype & (1<<10)) ? "fe" : "", + (mtrrdeftype & (1<<11)) ? "enabled" : "" + ); + + for (unsigned i = 0; i < vcap; ++i) { + uint64_t base = rdmsr(find_mtrr(msr::ia32_mtrrphysbase, i)); + uint64_t mask = rdmsr(find_mtrr(msr::ia32_mtrrphysmask, i)); + log::debug(logs::boot, " vcap[%2d] base:%016llx mask:%016llx type:%02x %s", i, + (base & ~0xfffull), + (mask & ~0xfffull), + (base & 0xff), + (mask & (1<<11)) ? "valid" : ""); + } + + msr mtrr_fixed[] = { + msr::ia32_mtrrfix64k_00000, + msr::ia32_mtrrfix16k_80000, + msr::ia32_mtrrfix16k_a0000, + msr::ia32_mtrrfix4k_c0000, + msr::ia32_mtrrfix4k_c8000, + msr::ia32_mtrrfix4k_d0000, + msr::ia32_mtrrfix4k_d8000, + msr::ia32_mtrrfix4k_e0000, + msr::ia32_mtrrfix4k_e8000, + msr::ia32_mtrrfix4k_f0000, + msr::ia32_mtrrfix4k_f8000, + }; + + for (int i = 0; i < 11; ++i) { + uint64_t v = rdmsr(mtrr_fixed[i]); + log::debug(logs::boot, " fixed[%2d] %02x %02x %02x %02x %02x %02x %02x %02x", i, + ((v << 0) & 0xff), ((v << 8) & 0xff), ((v << 16) & 0xff), ((v << 24) & 0xff), + ((v << 32) & 0xff), ((v << 40) & 0xff), ((v << 48) & 0xff), ((v << 56) & 0xff)); + } + + uint64_t pat = rdmsr(msr::ia32_pat); + static const char *pat_names[] = {"UC ","WC ","XX ","XX ","WT ","WP ","WB ","UC-"}; + log::debug(logs::boot, " PAT: 0:%s 1:%s 2:%s 3:%s 4:%s 5:%s 6:%s 7:%s", + pat_names[(pat >> (0*8)) & 7], pat_names[(pat >> (1*8)) & 7], + pat_names[(pat >> (2*8)) & 7], pat_names[(pat >> (3*8)) & 7], + pat_names[(pat >> (4*8)) & 7], pat_names[(pat >> (5*8)) & 7], + pat_names[(pat >> (6*8)) & 7], pat_names[(pat >> (7*8)) & 7]); +} + +void +setup_pat() +{ + uint64_t pat = rdmsr(msr::ia32_pat); + pat = (pat & 0x00ffffffffffffffull) | (0x01ull << 56); // set PAT 7 to WC + wrmsr(msr::ia32_pat, pat); + log_mtrrs(); +} + + void memory_initialize_pre_ctors(args::header *kargs) { diff --git a/src/kernel/msr.cpp b/src/kernel/msr.cpp index d43c1fc..4efb175 100644 --- a/src/kernel/msr.cpp +++ b/src/kernel/msr.cpp @@ -1,5 +1,11 @@ #include "msr.h" +msr +find_mtrr(msr type, unsigned index) +{ + return static_cast(static_cast(type) + (2 * index)); +} + uint64_t rdmsr(msr addr) { diff --git a/src/kernel/msr.h b/src/kernel/msr.h index 4d26425..ee02d45 100644 --- a/src/kernel/msr.h +++ b/src/kernel/msr.h @@ -6,22 +6,46 @@ enum class msr : uint32_t { - ia32_efer = 0xc0000080, - ia32_star = 0xc0000081, - ia32_lstar = 0xc0000082, - ia32_fmask = 0xc0000084, + ia32_mtrrcap = 0x000000fe, + ia32_mtrrdeftype = 0x000002ff, - ia32_gs_base = 0xc0000101, - ia32_kernel_gs_base = 0xc0000102 + ia32_mtrrphysbase = 0x00000200, + ia32_mtrrphysmask = 0x00000201, + + ia32_mtrrfix64k_00000 = 0x00000250, + + ia32_mtrrfix16k_80000 = 0x00000258, + ia32_mtrrfix16k_a0000 = 0x00000259, + + ia32_mtrrfix4k_c0000 = 0x00000268, + ia32_mtrrfix4k_c8000 = 0x00000269, + ia32_mtrrfix4k_d0000 = 0x0000026A, + ia32_mtrrfix4k_d8000 = 0x0000026B, + ia32_mtrrfix4k_e0000 = 0x0000026C, + ia32_mtrrfix4k_e8000 = 0x0000026D, + ia32_mtrrfix4k_f0000 = 0x0000026E, + ia32_mtrrfix4k_f8000 = 0x0000026F, + + ia32_pat = 0x00000277, + ia32_efer = 0xc0000080, + ia32_star = 0xc0000081, + ia32_lstar = 0xc0000082, + ia32_fmask = 0xc0000084, + + ia32_gs_base = 0xc0000101, + ia32_kernel_gs_base = 0xc0000102 }; +/// Find the msr for MTRR physical base or mask +msr find_mtrr(msr type, unsigned index); + /// Read the value of a MSR -/// \arg addr The MSR address -/// \returns The current value of the MSR +/// \arg addr The MSR address +/// \returns The current value of the MSR uint64_t rdmsr(msr addr); /// Write to a MSR -/// \arg addr The MSR address -/// \arg value The value to write +/// \arg addr The MSR address +/// \arg value The value to write void wrmsr(msr addr, uint64_t value); diff --git a/src/kernel/objects/vm_area.h b/src/kernel/objects/vm_area.h index e8b34c2..dbeb18d 100644 --- a/src/kernel/objects/vm_area.h +++ b/src/kernel/objects/vm_area.h @@ -29,6 +29,7 @@ enum class vm_flags : uint32_t huge_pages = 0x00000200, mmio = 0x00010000, + write_combine = 0x00020000, user_mask = 0x0000ffff ///< flags allowed via syscall }; diff --git a/src/kernel/page_table.h b/src/kernel/page_table.h index 5e3f010..8114f36 100644 --- a/src/kernel/page_table.h +++ b/src/kernel/page_table.h @@ -21,14 +21,21 @@ struct page_table present = 0x0001, /// Entry is present in the table write = 0x0002, /// Section may be written user = 0x0004, /// User-accessible - mtrr0 = 0x0008, /// MTRR selector bit 0 - mtrr1 = 0x0010, /// MTRR selector bit 1 + pat0 = 0x0008, /// PAT selector bit 0 + pat1 = 0x0010, /// PAT selector bit 1 accessed = 0x0020, /// Entry has been accessed dirty = 0x0040, /// Page has been written to page = 0x0080, /// Entry is a large page - pte_mtrr2 = 0x0080, /// MTRR selector bit 2 on PT entries + pat2 = 0x0080, /// PAT selector bit 2 on PT entries global = 0x0100, /// Entry is not PCID-specific - mtrr2 = 0x1000 /// MTRR selector bit 2 on PD and PDP entries + pat2_lg = 0x1000, /// PAT selector bit 2 on large/huge pages + + wb = none, + wt = pat0, + uc_ = pat1, + uc = pat0 | pat1, + wc = pat0 | pat1 | pat2, + wc_lg = pat0 | pat1 | pat2_lg, }; /// Helper for getting the next level value diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index b8e203f..6ce2183 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -141,7 +141,7 @@ load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb) // Crazypants framebuffer part if (fb) { - vma = new vm_area_open(fb->size, space, vm_flags::write|vm_flags::mmio); + vma = new vm_area_open(fb->size, space, vm_flags::write|vm_flags::mmio|vm_flags::write_combine); space.add(0x100000000, vma); vma->commit(fb->phys_addr, 0, memory::page_count(fb->size)); } diff --git a/src/kernel/vm_space.cpp b/src/kernel/vm_space.cpp index fd14f30..98fd6c9 100644 --- a/src/kernel/vm_space.cpp +++ b/src/kernel/vm_space.cpp @@ -170,7 +170,8 @@ vm_space::page_in(const vm_area &vma, uintptr_t offset, uintptr_t phys, size_t c page_table::flag flags = page_table::flag::present | (m_kernel ? page_table::flag::none : page_table::flag::user) | - ((vma.flags() && vm_flags::write) ? page_table::flag::write : page_table::flag::none); + ((vma.flags() && vm_flags::write) ? page_table::flag::write : page_table::flag::none) | + ((vma.flags() && vm_flags::write_combine) ? page_table::flag::wc : page_table::flag::none); page_table::iterator it {virt, m_pml4}; From a97073848cd62ea3e1f4c55b24de28cadcfca643 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 17 Jan 2021 20:53:41 -0800 Subject: [PATCH 5/9] [fb] Use double-buffering in fb driver Allocate and use a back buffer, so that draws to the screen are always a single memcpy() --- src/drivers/fb/main.cpp | 3 +++ src/drivers/fb/screen.cpp | 13 +++++++++++-- src/drivers/fb/screen.h | 4 +++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/drivers/fb/main.cpp b/src/drivers/fb/main.cpp index 2f02053..efedc50 100644 --- a/src/drivers/fb/main.cpp +++ b/src/drivers/fb/main.cpp @@ -60,6 +60,7 @@ main(int argc, const char **argv) screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0); screen::pixel_t bg = scr.color(49, 79, 128); scr.fill(bg); + scr.update(); constexpr int margin = 2; const unsigned xstride = (margin + fnt.width()); @@ -85,11 +86,13 @@ main(int argc, const char **argv) scroll.add_line(e->message, eom); if (++pending > pending_threshold) { scroll.render(scr, fnt); + scr.update(); pending = 0; } } else { if (pending) { scroll.render(scr, fnt); + scr.update(); pending = 0; } } diff --git a/src/drivers/fb/screen.cpp b/src/drivers/fb/screen.cpp index a01823b..d7862f9 100644 --- a/src/drivers/fb/screen.cpp +++ b/src/drivers/fb/screen.cpp @@ -1,3 +1,5 @@ +#include +#include #include "screen.h" screen::screen(void *addr, unsigned hres, unsigned vres, pixel_order order) : @@ -6,6 +8,7 @@ screen::screen(void *addr, unsigned hres, unsigned vres, pixel_order order) : m_resx(hres), m_resy(vres) { + m_back = reinterpret_cast(malloc(hres*vres*sizeof(pixel_t))); } screen::pixel_t @@ -31,11 +34,17 @@ screen::fill(pixel_t color) { const size_t len = m_resx * m_resy; for (size_t i = 0; i < len; ++i) - m_fb[i] = color; + m_back[i] = color; } void screen::draw_pixel(unsigned x, unsigned y, pixel_t color) { - m_fb[x + y * m_resx] = color; + m_back[x + y * m_resx] = color; +} + +void +screen::update() +{ + memcpy(m_fb, m_back, m_resx*m_resy*sizeof(pixel_t)); } diff --git a/src/drivers/fb/screen.h b/src/drivers/fb/screen.h index a9766ec..8d338ce 100644 --- a/src/drivers/fb/screen.h +++ b/src/drivers/fb/screen.h @@ -19,8 +19,10 @@ public: void fill(pixel_t color); void draw_pixel(unsigned x, unsigned y, pixel_t color); + void update(); + private: - pixel_t *m_fb; + pixel_t *m_fb, *m_back; pixel_order m_order; unsigned m_resx, m_resy; From e52fd8eacff1e1bb9abd22566a56598892366a26 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 17 Jan 2021 20:54:38 -0800 Subject: [PATCH 6/9] [libc] Attempt to speed up memcpy for aligned mem Copy long-by-long instead of byte-by-byte if both pointers are similarly aligned. --- src/libraries/libc/string/memcpy.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/libraries/libc/string/memcpy.c b/src/libraries/libc/string/memcpy.c index 981d3c6..ed1cda9 100644 --- a/src/libraries/libc/string/memcpy.c +++ b/src/libraries/libc/string/memcpy.c @@ -10,9 +10,24 @@ void * memcpy( void * restrict s1, const void * restrict s2, size_t n ) { char * dest = (char *) s1; const char * src = (const char *) s2; - while ( n-- ) - { + + if (((uintptr_t)src & 7) == ((uintptr_t)dest & 7)) { + while (((uintptr_t)src & 7) && n--) + *dest++ = *src++; + + const uint64_t *srcq = (const uint64_t*)src; + uint64_t *destq = (uint64_t*)dest; + while (n >= 8) { + *destq++ = *srcq++; + n -= 8; + } + + src = (const char*)srcq; + dest = (char*)destq; + } + + while (n--) *dest++ = *src++; - } + return s1; } From 34120fc4c19eb7fe27e69ec7568db36e37673bf0 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Mon, 18 Jan 2021 13:26:45 -0800 Subject: [PATCH 7/9] [cpu] Split cpuid validation into separate lib In order to allow the bootloader to do preliminary CPUID validation while UEFI is still handling displaying information to the user, split most of the kernel's CPUID handling into a library to be used by both kernel and boot. --- modules.yaml | 11 ++ src/boot/main.cpp | 24 ++++ src/kernel/cpu.cpp | 109 ++---------------- src/kernel/cpu.h | 69 +---------- src/kernel/main.cpp | 3 +- src/libraries/cpu/cpu.cpp | 97 ++++++++++++++++ src/libraries/cpu/include/cpu/cpu.h | 81 +++++++++++++ .../cpu/include/cpu/features.inc} | 0 8 files changed, 229 insertions(+), 165 deletions(-) create mode 100644 src/libraries/cpu/cpu.cpp create mode 100644 src/libraries/cpu/include/cpu/cpu.h rename src/{kernel/cpu_features.inc => libraries/cpu/include/cpu/features.inc} (100%) diff --git a/modules.yaml b/modules.yaml index ceff427..75bc913 100644 --- a/modules.yaml +++ b/modules.yaml @@ -6,6 +6,7 @@ modules: output: jsix.elf target: host deps: + - cpu - kutil includes: - src/kernel @@ -62,6 +63,8 @@ modules: kind: exe target: boot output: boot.efi + deps: + - cpu source: - src/boot/main.cpp - src/boot/console.cpp @@ -110,6 +113,14 @@ modules: - src/libraries/kutil/memory.cpp - src/libraries/kutil/printf.c + cpu: + kind: lib + output: libcpu.a + includes: + - src/libraries/cpu/include + source: + - src/libraries/cpu/cpu.cpp + libc: kind: lib diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 3f74ee4..f48e3b8 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -8,6 +8,7 @@ #include #include "console.h" +#include "cpu/cpu.h" #include "error.h" #include "fs.h" #include "hardware.h" @@ -94,6 +95,28 @@ add_module(args::header *args, args::mod_type type, buffer &data) m.size = data.size; } +/// 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. @@ -160,6 +183,7 @@ efi_main(uefi::handle image, uefi::system_table *st) { using namespace boot; console con(st->boot_services, st->con_out); + check_cpu_supported(); args::header *args = uefi_preboot(image, st); memory::efi_mem_map map = uefi_exit(args, image, st->boot_services); diff --git a/src/kernel/cpu.cpp b/src/kernel/cpu.cpp index 7e6c25b..4b0720e 100644 --- a/src/kernel/cpu.cpp +++ b/src/kernel/cpu.cpp @@ -1,116 +1,31 @@ #include +#include "kutil/assert.h" #include "kutil/memory.h" #include "cpu.h" +#include "cpu/cpu.h" #include "log.h" cpu_data bsp_cpu_data; -static constexpr uint32_t cpuid_extended = 0x80000000; - - -inline static void -__cpuid( - uint32_t leaf, - uint32_t subleaf, - uint32_t *eax, - uint32_t *ebx = nullptr, - uint32_t *ecx = nullptr, - uint32_t *edx = nullptr) -{ - uint32_t a, b, c, d; - __asm__ __volatile__ ( "cpuid" - : "=a"(a), "=b"(b), "=c"(c), "=d"(d) - : "a"(leaf), "c"(subleaf) - ); - if (eax) *eax = a; - if (ebx) *ebx = b; - if (ecx) *ecx = c; - if (edx) *edx = d; -} - -cpu_id::cpu_id() : - m_features(0) -{ - __cpuid(0, 0, - &m_high_basic, - reinterpret_cast(&m_vendor_id[0]), - reinterpret_cast(&m_vendor_id[8]), - reinterpret_cast(&m_vendor_id[4])); - - __cpuid(cpuid_extended, 0, &m_high_ext); - - if (m_high_ext >= cpuid_extended + 4) { - __cpuid(cpuid_extended + 2, 0, - reinterpret_cast(&m_brand_name[0]), - reinterpret_cast(&m_brand_name[4]), - reinterpret_cast(&m_brand_name[8]), - reinterpret_cast(&m_brand_name[12])); - __cpuid(cpuid_extended + 3, 0, - reinterpret_cast(&m_brand_name[16]), - reinterpret_cast(&m_brand_name[20]), - reinterpret_cast(&m_brand_name[24]), - reinterpret_cast(&m_brand_name[28])); - __cpuid(cpuid_extended + 4, 0, - reinterpret_cast(&m_brand_name[32]), - reinterpret_cast(&m_brand_name[36]), - reinterpret_cast(&m_brand_name[40]), - reinterpret_cast(&m_brand_name[44])); - } else { - m_brand_name[0] = 0; - } -} - -cpu_id::regs -cpu_id::get(uint32_t leaf, uint32_t sub) const -{ - regs ret {0, 0, 0, 0}; - - if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret; - if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret; - - __cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx); - return ret; -} - void -cpu_id::validate() +cpu_validate() { - bool fail = false; - uint32_t leaf = 0; - uint32_t sub = 0; - regs r; + cpu::cpu_id cpu; - log::info(logs::boot, "CPU: %s", brand_name()); - log::debug(logs::boot, " Vendor is %s", vendor_id()); + log::info(logs::boot, "CPU: %s", cpu.brand_name()); + log::debug(logs::boot, " Vendor is %s", cpu.vendor_id()); - log::debug(logs::boot, " Higest basic CPUID: 0x%02x", highest_basic()); - log::debug(logs::boot, " Higest ext CPUID: 0x%02x", highest_ext() & ~cpuid_extended); + log::debug(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic()); + log::debug(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended); -#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \ - if (leaf != feat_leaf || sub != feat_sub) { \ - leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \ - } \ - if (r.regname & (1ull << bit)) \ - m_features |= (1ull << static_cast(cpu_feature::name)); \ - log::debug(logs::boot, " Supports %9s: %s", #name, (r.regname & (1ull << bit)) ? "yes" : "no"); +#define CPU_FEATURE_OPT(name, ...) \ + log::debug(logs::boot, " Supports %9s: %s", #name, cpu.has_feature(cpu::feature::name) ? "yes" : "no"); #define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \ CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \ - if ((r.regname & (1ull << bit)) == 0) { \ - log::error(logs::boot, "CPU missing required feature " #name); \ - fail = true; \ - } + kassert(cpu.has_feature(cpu::feature::name), "Missing required CPU feature " #name ); -#include "cpu_features.inc" +#include "cpu/features.inc" #undef CPU_FEATURE_OPT #undef CPU_FEATURE_REQ - - if (fail) - log::fatal(logs::boot, "CPU not supported."); -} - -bool -cpu_id::has_feature(cpu_feature feat) -{ - return (m_features & (1 << static_cast(feat))) != 0; } diff --git a/src/kernel/cpu.h b/src/kernel/cpu.h index 84108fd..ed5722d 100644 --- a/src/kernel/cpu.h +++ b/src/kernel/cpu.h @@ -27,69 +27,6 @@ struct cpu_data extern cpu_data bsp_cpu_data; -/// Enum of the cpu features jsix cares about -enum class cpu_feature { -#define CPU_FEATURE_REQ(name, ...) name, -#define CPU_FEATURE_OPT(name, ...) name, -#include "cpu_features.inc" -#undef CPU_FEATURE_OPT -#undef CPU_FEATURE_REQ - max -}; - -class cpu_id -{ -public: - /// CPUID result register values - struct regs { - union { - uint32_t reg[4]; - uint32_t eax, ebx, ecx, edx; - }; - - /// Return true if bit |bit| of EAX is set - bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; } - - /// Return true if bit |bit| of EBX is set - bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; } - - /// Return true if bit |bit| of ECX is set - bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; } - - /// Return true if bit |bit| of EDX is set - bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; } - }; - - cpu_id(); - - /// The the result of a given CPUID leaf/subleaf - /// \arg leaf The leaf selector (initial EAX) - /// \arg subleaf The subleaf selector (initial ECX) - /// \returns A |regs| struct of the values retuned - regs get(uint32_t leaf, uint32_t sub = 0) const; - - /// Get the name of the cpu vendor (eg, "GenuineIntel") - inline const char * vendor_id() const { return m_vendor_id; } - - /// Get the brand name of this processor model - inline const char * brand_name() const { return m_brand_name; } - - /// Get the highest basic CPUID leaf supported - inline uint32_t highest_basic() const { return m_high_basic; } - - /// Get the highest extended CPUID leaf supported - inline uint32_t highest_ext() const { return m_high_ext; } - - /// Validate the CPU supports the necessary options for jsix - void validate(); - - /// Return true if the CPU claims to support the given feature - bool has_feature(cpu_feature feat); - -private: - uint32_t m_high_basic; - uint32_t m_high_ext; - char m_vendor_id[13]; - char m_brand_name[48]; - uint64_t m_features; -}; +// We already validated the required options in the bootloader, +// but iterate the options and log about them. +void cpu_validate(); diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 120a2b2..e872f1d 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -135,8 +135,7 @@ kernel_main(args::header *header) run_constructors(); memory_initialize_post_ctors(header); - cpu_id cpu; - cpu.validate(); + cpu_validate(); for (size_t i = 0; i < header->num_modules; ++i) { args::module &mod = header->modules[i]; diff --git a/src/libraries/cpu/cpu.cpp b/src/libraries/cpu/cpu.cpp new file mode 100644 index 0000000..98395e5 --- /dev/null +++ b/src/libraries/cpu/cpu.cpp @@ -0,0 +1,97 @@ +#include +#include "cpu/cpu.h" + +namespace cpu { + +inline static void +__cpuid( + uint32_t leaf, + uint32_t subleaf, + uint32_t *eax, + uint32_t *ebx = nullptr, + uint32_t *ecx = nullptr, + uint32_t *edx = nullptr) +{ + uint32_t a, b, c, d; + __asm__ __volatile__ ( "cpuid" + : "=a"(a), "=b"(b), "=c"(c), "=d"(d) + : "a"(leaf), "c"(subleaf) + ); + if (eax) *eax = a; + if (ebx) *ebx = b; + if (ecx) *ecx = c; + if (edx) *edx = d; +} + +cpu_id::cpu_id() : + m_features {0}, + m_missing {0} +{ + __cpuid(0, 0, + &m_high_basic, + reinterpret_cast(&m_vendor_id[0]), + reinterpret_cast(&m_vendor_id[8]), + reinterpret_cast(&m_vendor_id[4])); + + __cpuid(cpuid_extended, 0, &m_high_ext); + + if (m_high_ext >= cpuid_extended + 4) { + __cpuid(cpuid_extended + 2, 0, + reinterpret_cast(&m_brand_name[0]), + reinterpret_cast(&m_brand_name[4]), + reinterpret_cast(&m_brand_name[8]), + reinterpret_cast(&m_brand_name[12])); + __cpuid(cpuid_extended + 3, 0, + reinterpret_cast(&m_brand_name[16]), + reinterpret_cast(&m_brand_name[20]), + reinterpret_cast(&m_brand_name[24]), + reinterpret_cast(&m_brand_name[28])); + __cpuid(cpuid_extended + 4, 0, + reinterpret_cast(&m_brand_name[32]), + reinterpret_cast(&m_brand_name[36]), + reinterpret_cast(&m_brand_name[40]), + reinterpret_cast(&m_brand_name[44])); + } else { + m_brand_name[0] = 0; + } + + uint32_t leaf = -1u; + uint32_t sub = -1u; + regs r; +#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \ + if (leaf != feat_leaf || sub != feat_sub) { \ + leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \ + } \ + if (r.regname & (1ull << bit)) \ + m_features |= (1ull << static_cast(feature::name)); \ + +#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \ + CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \ + if ((r.regname & (1ull << bit)) == 0) { \ + m_missing |= (1ull << static_cast(feature::name)); \ + } + +#include "cpu/features.inc" +#undef CPU_FEATURE_OPT +#undef CPU_FEATURE_REQ +} + +cpu_id::regs +cpu_id::get(uint32_t leaf, uint32_t sub) const +{ + regs ret {0, 0, 0, 0}; + + if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret; + if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret; + + __cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx); + return ret; +} + +bool +cpu_id::has_feature(feature feat) +{ + return (m_features & (1 << static_cast(feat))) != 0; +} + +} diff --git a/src/libraries/cpu/include/cpu/cpu.h b/src/libraries/cpu/include/cpu/cpu.h new file mode 100644 index 0000000..ceace0f --- /dev/null +++ b/src/libraries/cpu/include/cpu/cpu.h @@ -0,0 +1,81 @@ +#pragma once +/// \file cpu.h Definition of required cpu features for jsix + +#include + +namespace cpu { + +/// Enum of the cpu features jsix cares about +enum class feature { +#define CPU_FEATURE_REQ(name, ...) name, +#define CPU_FEATURE_OPT(name, ...) name, +#include "cpu/features.inc" +#undef CPU_FEATURE_OPT +#undef CPU_FEATURE_REQ + max +}; + +class cpu_id +{ +public: + static constexpr uint32_t cpuid_extended = 0x80000000; + + /// CPUID result register values + struct regs { + union { + uint32_t reg[4]; + uint32_t eax, ebx, ecx, edx; + }; + + /// Return true if bit |bit| of EAX is set + bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; } + + /// Return true if bit |bit| of EBX is set + bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; } + + /// Return true if bit |bit| of ECX is set + bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; } + + /// Return true if bit |bit| of EDX is set + bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; } + }; + + cpu_id(); + + /// The the result of a given CPUID leaf/subleaf + /// \arg leaf The leaf selector (initial EAX) + /// \arg subleaf The subleaf selector (initial ECX) + /// \returns A |regs| struct of the values retuned + regs get(uint32_t leaf, uint32_t sub = 0) const; + + /// Get the name of the cpu vendor (eg, "GenuineIntel") + inline const char * vendor_id() const { return m_vendor_id; } + + /// Get the brand name of this processor model + inline const char * brand_name() const { return m_brand_name; } + + /// Get the highest basic CPUID leaf supported + inline uint32_t highest_basic() const { return m_high_basic; } + + /// Get the highest extended CPUID leaf supported + inline uint32_t highest_ext() const { return m_high_ext; } + + /// Get which required options are missing as flags + inline uint64_t missing() const { return m_missing; } + + /// Validate the CPU supports the necessary options for jsix + inline bool supported() const { return m_missing; } + + /// Return true if the CPU claims to support the given feature + bool has_feature(feature feat); + +private: + uint32_t m_high_basic; + uint32_t m_high_ext; + uint64_t m_features; + uint64_t m_missing; + char m_vendor_id[13]; + char m_brand_name[48]; +}; + +} diff --git a/src/kernel/cpu_features.inc b/src/libraries/cpu/include/cpu/features.inc similarity index 100% rename from src/kernel/cpu_features.inc rename to src/libraries/cpu/include/cpu/features.inc From f3bb2e52598f2d2612e0b70fcebf3e45593a0d17 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Mon, 18 Jan 2021 13:35:01 -0800 Subject: [PATCH 8/9] [boot] Save commented-out mem map dumping code This is often needed, so I'm commiting it commented out. --- src/boot/memory.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/boot/memory.cpp b/src/boot/memory.cpp index e0732b2..92bafa5 100644 --- a/src/boot/memory.cpp +++ b/src/boot/memory.cpp @@ -36,6 +36,15 @@ static const wchar_t *memory_type_names[] = { L"persistent memory" }; +static const wchar_t *kernel_memory_type_names[] = { + L"free", + L"pending", + L"acpi", + L"uefi_runtime", + L"mmio", + L"persistent" +}; + static const wchar_t * memory_type_name(uefi::memory_type t) { @@ -45,6 +54,12 @@ memory_type_name(uefi::memory_type t) return L"Bad Type Value"; } +static const wchar_t * +kernel_memory_type_name(kernel::args::mem_type t) +{ + return kernel_memory_type_names[static_cast(t)]; +} + void update_marked_addresses(uefi::event, void *context) { @@ -144,6 +159,7 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs) bool first = true; for (auto desc : map) { /* + // EFI map dump 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); */ @@ -217,6 +233,15 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs) args->mem_map = kernel_map; args->map_count = i; + /* + // kernel map dump + for (unsigned i = 0; i < args->map_count; ++i) { + const kernel::args::mem_entry &e = kernel_map[i]; + console::print(L" Range %lx (%lx) %x(%s) [%lu]\r\n", + e.start, e.attr, e.type, kernel_memory_type_name(e.type), e.pages); + } + */ + return map; } From 699fc57e0a54e32e1ac66c1affe40ca49f3fa203 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Mon, 18 Jan 2021 13:36:05 -0800 Subject: [PATCH 9/9] [boot] Log address of new table pages Since it's often needed when debugging between the bootloader and kernel, log the address of the table pages the bootloader allocated. --- src/boot/paging.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/boot/paging.cpp b/src/boot/paging.cpp index de61509..b1423fb 100644 --- a/src/boot/paging.cpp +++ b/src/boot/paging.cpp @@ -215,6 +215,8 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs) args->table_count = tables_needed - 1; args->page_tables = offset_ptr(addr, page_size); + console::print(L" First page (pml4) at: 0x%lx\r\n", pml4); + add_kernel_pds(pml4, args->page_tables, args->table_count); add_offset_mappings(pml4, args->page_tables, args->table_count);