From 97685cbad7b5285b0d04e696a2bc6f58d7add025 Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 20 Apr 2020 17:39:39 -0700 Subject: [PATCH 1/2] Add comments to describe the boot process. --- bootentry.S | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/bootentry.S b/bootentry.S index cba6cbb..7031eb1 100644 --- a/bootentry.S +++ b/bootentry.S @@ -63,37 +63,48 @@ init_boot_pagetable: # 0x2000: L2 page table; entries 0 and 510 map 1st 1GB of physmem # This weird setup is the minimal page table that maps all of # low-canonical, high-canonical, and kernel-text addresses to - # the first 1GB of physical memory. + # the first 1GB (?) of physical memory. + # (Not sure about the 1 GB number. Emperical tests show only 128 MB!) movl $BOOT_PAGETABLE, %edi - leal 0x1000 + PTE_P + PTE_W(%edi), %ecx + leal 0x1000 + PTE_P + PTE_W(%edi), %ecx # combine address with flags movl %ecx, (%edi) movl %ecx, 0x800(%edi) movl %ecx, 0xFF8(%edi) + # the offsets below are adjusted by -3 to remove the flags! movl $(PTE_P + PTE_W + PTE_PS), -3(%ecx) movl $(PTE_P + PTE_W + PTE_PS), 0xFED(%ecx) -# Switch from real to protected mode: -# Up until now, there's been no protection, so we've gotten along perfectly -# well without explicitly telling the processor how to translate addresses. -# When we switch to protected mode, this is no longer true! +# Switch from real mode (16-bit) to long mode (64-bit): +# Up until now, we have used direct physical memory addressing (real mode) +# without explicitly telling the processor how to translate addresses. +# When we enable paging, this is no longer true! # We need at least to set up some "segments" that tell the processor it's # OK to run code at any address, or write to any address. # The `gdt` and `gdtdesc` tables below define these segments. # This code loads them into the processor. # We need this setup to ensure the transition to protected mode is smooth. +# See https://en.wikipedia.org/wiki/X86-64 for a nice diagram and description of processor modes. -real_to_prot: +real_to_long: movl %cr4, %eax # enable physical address extensions - orl $(CR4_PSE | CR4_PAE), %eax + orl $(CR4_PAE), %eax # https://en.wikipedia.org/wiki/Physical_Address_Extension movl %eax, %cr4 - movl %edi, %cr3 - movl $MSR_IA32_EFER, %ecx # turn on 64-bit mode - rdmsr + movl %edi, %cr3 # set the address of the page table + + movl $MSR_IA32_EFER, %ecx # enable long mode (https://wiki.osdev.org/Setting_Up_Long_Mode) + + rdmsr # read from the model-specific register into %eax + # IA32_EFER_LME is to enable 64-bit mode + # IA32_EFER_SCE is to enable syscall/sysret + # IA32_EFER_NXE is to allow PTE_XD (eXecute Disabled) in page table entries orl $(IA32_EFER_LME | IA32_EFER_SCE | IA32_EFER_NXE), %eax - wrmsr + wrmsr # write %eax to the model-specific register - movl %cr0, %eax # turn on protected mode + movl %cr0, %eax # turn on some other features + # CR0_PE sets Protection Enable + # CR0_WP sets Write Protect + # CR0_PG sets CR0_PG orl $(CR0_PE | CR0_WP | CR0_PG), %eax movl %eax, %cr0 From 087a12bf8f7605bb9dd350a99f301cde733447da Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 20 Apr 2020 18:17:43 -0700 Subject: [PATCH 2/2] Code to look at boot page table's impact. --- kernel.cc | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/kernel.cc b/kernel.cc index 2b8d6ca..eee94bd 100644 --- a/kernel.cc +++ b/kernel.cc @@ -19,6 +19,7 @@ std::atomic kdisplay; static void kdisplay_ontick(); static void boot_process_start(pid_t pid, const char* program_name); +void find_mapped_memory(); // kernel_start(command) @@ -26,6 +27,8 @@ static void boot_process_start(pid_t pid, const char* program_name); // string is an optional string passed from the boot loader. void kernel_start(const char* command) { + // find_mapped_memory(); // uncomment this to test the boot page table + init_hardware(); console_clear(); @@ -417,3 +420,37 @@ void kdisplay_ontick() { memshow(); } } + +/* The comment at init_boot_pagetable in bootentry.s says that 1 GB of RAM + * is mapped. It appears that only 128 MB is mapped. That is, when we write + * to one address, can we find the value when we read from the other address? + * Disable optimizations so we can step through this in a debugger. + */ +#pragma GCC push_options +#pragma GCC optimize ("O0") + +void find_mapped_memory() { + long lowCanonical = 0x0; + long highCanonical = 0xffff800000000000; + long kernel = 0xffffffff80000000; + char magic = 0x42; + for (long i = 0x7ffffff; i < 0x80000000; ++i) { + char* p1 = (char*) (lowCanonical + i); + char* p2 = ((char*) highCanonical + i); + char* p3 = ((char*) kernel + i); + *p1 = magic; + char c1 = *p1; + char c2 = *p2; + char c3 = *p3; + if (c1 != magic) { + *p2 = magic; + c2 = *p2; + c1 = *p1; // break here! + } + c1 = c2; // avoid compiler warnings + c2 = c3; + c3 = c1; + } +} + +#pragma GCC pop_options \ No newline at end of file