From 12fb906ccc587199a33c443ee0b8f3a2804e0c0e Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 1 Oct 2019 12:37:27 +0300 Subject: [PATCH] [amd64] Fixed problem with invalid upper mapping --- include/sys/amd64/mm.h | 12 ++- sys/amd64/acpi/hpet.c | 5 +- sys/amd64/kernel.c | 2 +- sys/amd64/link.ld | 6 +- sys/amd64/mm/map.c | 167 +++++++++++++++++------------------------ sys/amd64/mm/mm.c | 13 ++-- sys/amd64/mm/phys.c | 3 +- 7 files changed, 94 insertions(+), 114 deletions(-) diff --git a/include/sys/amd64/mm.h b/include/sys/amd64/mm.h index f36a0ce..9961bd0 100644 --- a/include/sys/amd64/mm.h +++ b/include/sys/amd64/mm.h @@ -1,16 +1,20 @@ /* vim: set ft=cpp.doxygen : */ #pragma once #include +#include "sys/amd64/loader/data.h" /// The place where the kernel pages are virtually mapped to #define KERNEL_VIRT_BASE 0xFFFFFF0000000000 /// amd64 standard states that addresses' upper bits are copies of the 47th bit, so these need to be /// stripped down to only 48 bits -#define AMD64_MM_MASK(a) ((uintptr_t) (a) & 0xFFFFFFFFFFFF) +#define AMD64_MM_STRIPSX(a) ((uintptr_t) (a) & 0xFFFFFFFFFFFF) +#define AMD64_MM_ADDRSX(a) (((uintptr_t) (a) & (1ULL << 47)) ? \ + (0xFFFFFF0000000000 | ((uintptr_t) (a))) : \ + ((uintptr_t) (a))) -#define MM_VIRTUALIZE(a) ((uintptr_t) (a) + 0xFFFFFF0000000000) -#define MM_PHYS(a) ((uintptr_t) (a) - 0xFFFFFF0000000000) +#define MM_VIRTUALIZE(a) ((uintptr_t) (a) + 0xFFFFFF0000000000) +#define MM_PHYS(a) ((uintptr_t) (a) - 0xFFFFFF0000000000) /// Page map level 4 typedef uint64_t *mm_pml4_t; @@ -27,4 +31,4 @@ typedef mm_pml4_t mm_space_t; /// Kernel memory space extern mm_space_t mm_kernel; -void amd64_mm_init(void); +void amd64_mm_init(struct amd64_loader_data *data); diff --git a/sys/amd64/acpi/hpet.c b/sys/amd64/acpi/hpet.c index 39291ba..84dc5f5 100644 --- a/sys/amd64/acpi/hpet.c +++ b/sys/amd64/acpi/hpet.c @@ -62,9 +62,8 @@ int acpi_hpet_init(void) { if (!hpet_base) { return -1; } - uint64_t addr = 0x7FFFFFFFF000ULL; - hpet = (struct hpet *) addr; - mm_map_pages_contiguous(mm_kernel, addr, hpet_base, 1, 0); + hpet = (struct hpet *) MM_VIRTUALIZE(hpet_base); + kdebug("HPET = %p\n", hpet); uint64_t hpet_clk = (hpet->caps >> 32) & 0xFFFFFFFF; assert(hpet_clk != 0, "HPET does not work correctly\n"); diff --git a/sys/amd64/kernel.c b/sys/amd64/kernel.c index 963aaac..991832f 100644 --- a/sys/amd64/kernel.c +++ b/sys/amd64/kernel.c @@ -55,7 +55,7 @@ void kernel_main(uintptr_t loader_info_phys_ptr) { // Memory management kernel_startup_section("Memory management"); amd64_phys_memory_map((multiboot_memory_map_t *) MM_VIRTUALIZE(multiboot_info->mmap_addr), multiboot_info->mmap_length); - amd64_mm_init(); + amd64_mm_init(loader_data); kernel_startup_section("Basic hardware"); amd64_gdt_init(); diff --git a/sys/amd64/link.ld b/sys/amd64/link.ld index 1cfde89..09f7844 100644 --- a/sys/amd64/link.ld +++ b/sys/amd64/link.ld @@ -6,7 +6,7 @@ ENTRY(_start) _kernel_base = 0xFFFFFF0000000000; -_kernel_base_phys = 0x200000; +_kernel_base_phys = 0x4000000; SECTIONS { . = _kernel_base + _kernel_base_phys; @@ -29,5 +29,9 @@ SECTIONS { *(COMMON) *(.bss) } + + . = ALIGN(4K); + _kernel_end = .; + _kernel_end_phys = . - _kernel_base; } diff --git a/sys/amd64/mm/map.c b/sys/amd64/mm/map.c index b727000..80780f6 100644 --- a/sys/amd64/mm/map.c +++ b/sys/amd64/mm/map.c @@ -7,6 +7,7 @@ #include "sys/amd64/mm/pool.h" uintptr_t amd64_map_get(const mm_space_t pml4, uintptr_t vaddr, uint64_t *flags) { + vaddr = AMD64_MM_STRIPSX(vaddr); size_t pml4i = (vaddr >> 39) & 0x1FF; size_t pdpti = (vaddr >> 30) & 0x1FF; size_t pdi = (vaddr >> 21) & 0x1FF; @@ -64,6 +65,7 @@ uintptr_t amd64_map_get(const mm_space_t pml4, uintptr_t vaddr, uint64_t *flags) } uintptr_t amd64_map_umap(mm_space_t pml4, uintptr_t vaddr, uint32_t size) { + vaddr = AMD64_MM_STRIPSX(vaddr); // TODO: support page sizes other than 4KiB // (Though I can't think of any reason to use it) size_t pml4i = (vaddr >> 39) & 0x1FF; @@ -116,6 +118,7 @@ uintptr_t amd64_map_umap(mm_space_t pml4, uintptr_t vaddr, uint32_t size) { } int amd64_map_single(mm_space_t pml4, uintptr_t virt_addr, uintptr_t phys, uint32_t flags) { + virt_addr = AMD64_MM_STRIPSX(virt_addr); // TODO: support page sizes other than 4KiB // (Though I can't think of any reason to use it) size_t pml4i = (virt_addr >> 39) & 0x1FF; @@ -200,6 +203,69 @@ int mm_space_clone(mm_space_t dst_pml4, const mm_space_t src_pml4, uint32_t flag return 0; } +static void amd64_mm_describe_range(const mm_space_t pml4, uintptr_t start_addr, uintptr_t end_addr) { + uintptr_t addr = AMD64_MM_STRIPSX(start_addr); + + size_t range_length = 0; + uintptr_t virt_range_begin = MM_NADDR; + uint32_t range_flags = 0; + + mm_pdpt_t pdpt; + + while (addr < AMD64_MM_STRIPSX(end_addr)) { + size_t pml4i = (addr >> 39) & 0x1FF; + size_t pdpti = (addr >> 30) & 0x1FF; + size_t pdi = (addr >> 21) & 0x1FF; + size_t pti = (addr >> 12) & 0x1FF; + size_t page_size = 1ULL << 39; + + if (pml4[pml4i] & 1) { + if (pml4[pml4i] & (1 << 7)) { + panic("Found a huge page in PML4 (shouldn't be possible): %p\n", AMD64_MM_ADDRSX(addr)); + } + + page_size = 1ULL << 30; + pdpt = (mm_pdpt_t) MM_VIRTUALIZE(pml4[pml4i] & ~0xFFF); + + if (pdpt[pdpti] & 1) { + if (pdpt[pdpti] & (1 << 7)) { + if (virt_range_begin == MM_NADDR) { + virt_range_begin = addr; + range_length = 0; + range_flags = pdpt[pdpti] & 5; + } + + goto found; + } + + panic("TODO: implement smaller page description\n"); + } + } + + if (virt_range_begin != MM_NADDR) { + kdebug("Range %p .. %p (%c%c) %S\n", + virt_range_begin, + virt_range_begin + range_length, + (range_flags & (1 << 2) ? 'u' : '-'), + (range_flags & (1 << 1) ? 'w' : '-'), + range_length); + } + +found: + addr += page_size; + range_length += page_size; + } + + if (virt_range_begin != MM_NADDR) { + kdebug("Range %p .. %p (%c%c) %S\n", + virt_range_begin, + virt_range_begin + range_length, + (range_flags & (1 << 2) ? 'u' : '-'), + (range_flags & (1 << 1) ? 'w' : '-'), + range_length); + } +} + void mm_describe(const mm_space_t pml4) { kdebug("Memory space V:%p:\n", pml4); @@ -209,104 +275,7 @@ void mm_describe(const mm_space_t pml4) { // Dump everything except kernel-space mappings kdebug("- Userspace:\n"); - for (size_t pml4i = 0; pml4i < 255; ++pml4i) { - if (!(pml4[pml4i] & 1)) { - continue; - } - - if (pml4[pml4i] & (1 << 7)) { - kdebug("`- PHYS %p\n", pml4[pml4i] & ~0xFFF); - continue; - } - - pdpt = (mm_pdpt_t) MM_VIRTUALIZE(pml4[pml4i] & ~0xFFF); - kdebug("`- PDPT %p\n", pdpt); - - for (size_t pdpti = 0; pdpti < 512; ++pdpti) { - if (!(pdpt[pdpti] & 1)) { - continue; - } - - if (pdpt[pdpti] & (1 << 7)) { - kdebug("`- PHYS %p\n", pdpt[pdpti] & ~0xFFF); - continue; - } - - pd = (mm_pagedir_t) MM_VIRTUALIZE(pdpt[pdpti] & ~0xFFF); - kdebug(" `- PDIR %p\n", pd); - - for (size_t pdi = 0; pdi < 512; ++pdi) { - if (!(pd[pdi] & 1)) { - continue; - } - - if (pd[pdi] & (1 << 7)) { - kdebug("`- PHYS %p\n", pdpt[pdpti] & ~0xFFF); - continue; - } - - pt = (mm_pagetab_t) MM_VIRTUALIZE(pd[pdi] & ~0xFFF); - kdebug(" `- PTAB %p\n", pt); - - for (size_t pti = 0; pti < 512; ++pti) { - if (!(pt[pti] & 1)) { - continue; - } - - kdebug(" `- %p - %p (4KiB)\n", (pml4i << 39) | (pdpti << 30) | (pdi << 21) | (pti << 12), pt[pti] & ~0xFFF); - } - } - } - } - + amd64_mm_describe_range(pml4, 0, 0xFFFFFF0000000000); kdebug("- Kernelspace:\n"); - for (size_t pml4i = 255; pml4i < 510; ++pml4i) { - if (!(pml4[pml4i] & 1)) { - continue; - } - - if (pml4[pml4i] & (1 << 7)) { - kdebug("`- PHYS %p\n", pml4[pml4i] & ~0xFFF); - continue; - } - - pdpt = (mm_pdpt_t) MM_VIRTUALIZE(pml4[pml4i] & ~0xFFF); - kdebug("`- PDPT %p\n", pdpt); - - for (size_t pdpti = 0; pdpti < 512; ++pdpti) { - if (!(pdpt[pdpti] & 1)) { - continue; - } - - if (pdpt[pdpti] & (1 << 7)) { - kdebug("`- PHYS %p\n", pdpt[pdpti] & ~0xFFF); - continue; - } - - pd = (mm_pagedir_t) MM_VIRTUALIZE(pdpt[pdpti] & ~0xFFF); - kdebug(" `- PDIR %p\n", pd); - - for (size_t pdi = 0; pdi < 512; ++pdi) { - if (!(pd[pdi] & 1)) { - continue; - } - - if (pd[pdi] & (1 << 7)) { - kdebug("`- PHYS %p\n", pdpt[pdpti] & ~0xFFF); - continue; - } - - pt = (mm_pagetab_t) MM_VIRTUALIZE(pd[pdi] & ~0xFFF); - kdebug(" `- PTAB %p\n", pt); - - for (size_t pti = 0; pti < 512; ++pti) { - if (!(pt[pti] & 1)) { - continue; - } - - kdebug(" `- %p - %p (4KiB)\n", (pml4i << 39) | (pdpti << 30) | (pdi << 21) | (pti << 12), pt[pti] & ~0xFFF); - } - } - } - } + amd64_mm_describe_range(pml4, 0xFFFFFF0000000000, 0xFFFFFF00FFFFFFFF); } diff --git a/sys/amd64/mm/mm.c b/sys/amd64/mm/mm.c index 0b5ba76..7ad6b82 100644 --- a/sys/amd64/mm/mm.c +++ b/sys/amd64/mm/mm.c @@ -10,7 +10,9 @@ mm_space_t mm_kernel; -void amd64_mm_init(void) { +extern int _kernel_end; + +void amd64_mm_init(struct amd64_loader_data *data) { kdebug("Memory manager init\n"); // Physical memory at this point: @@ -26,16 +28,17 @@ void amd64_mm_init(void) { memset((void *) (0x200000 - 2 * 0x1000), 0, 0x1000 * 2); // 0xFFFFFF0000000000 -> 0 (512GiB) mapping - pml4[AMD64_MM_MASK(KERNEL_VIRT_BASE) >> 39] = (uint64_t) pdpt | 1 | 2 | 4; - for (int i = 0; i < 512; ++i) { - pdpt[(AMD64_MM_MASK((KERNEL_VIRT_BASE) >> 30) + i) & 0x1FF] = 1 | 2 | 4 | (1 << 7); + pml4[AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 39] = ((uintptr_t) pdpt) | 1 | 2 | 4; + for (uint64_t i = 0; i < 4; ++i) { + kdebug("Mapping %p -> %p\n", KERNEL_VIRT_BASE | (i << 30), i << 30); + pdpt[((AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 30) + i) & 0x1FF] = (i << 30) | 1 | 2 | 4 | (1 << 7); } // Load the new table asm volatile ("mov %0, %%cr3"::"a"(pml4):"memory"); // Create a pool located right after kernel image - amd64_mm_pool_init(MM_VIRTUALIZE(0x400000), MM_POOL_SIZE); + amd64_mm_pool_init((uintptr_t) &_kernel_end, MM_POOL_SIZE); mm_kernel = (mm_space_t) (MM_VIRTUALIZE(pml4)); diff --git a/sys/amd64/mm/phys.c b/sys/amd64/mm/phys.c index 5ab94b8..6eb6ab8 100644 --- a/sys/amd64/mm/phys.c +++ b/sys/amd64/mm/phys.c @@ -6,9 +6,10 @@ #include "sys/mem.h" #include "sys/mm.h" +extern int _kernel_end_phys; // Roughly 36MiB of lower memory is occupied by kernel so far: // The rest is available for both kernel and user allocation -#define PHYS_ALLOWED_BEGIN (((/* Kernel image end */ 0x400000 + MM_POOL_SIZE) + 0xFFF) & ~0xFFF) +#define PHYS_ALLOWED_BEGIN ((((uintptr_t) &_kernel_end_phys + MM_POOL_SIZE) + 0xFFF) & ~0xFFF) // TODO: move to sys/util.h #define MAX(x, y) ((x) > (y) ? (x) : (y))