From 9da62f52a198a8e043f5ca8ff43570fa040d15d2 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 9 Jun 2019 11:48:58 +0200 Subject: [PATCH] Kernel: Use the Multiboot memory map info to inform our paging setup. This makes it possible to run Serenity with more than 64 MB of RAM. Because each physical page is represented by a PhysicalPage object, and such objects are allocated using kmalloc_eternal(), more RAM means more pressure on kmalloc_eternal(), so we're gonna need a better strategy for this. But for now, let's just celebrate that we can use the 128 MB of RAM we've been telling QEMU to run with. :^) --- Kernel/Multiboot.h | 14 ++++++++ Kernel/VM/MemoryManager.cpp | 65 ++++++++++++++++++++++++------------- Kernel/VM/MemoryManager.h | 6 ++-- Kernel/kmalloc.cpp | 8 ++--- 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/Kernel/Multiboot.h b/Kernel/Multiboot.h index 6f586bc395..a74c4feb34 100644 --- a/Kernel/Multiboot.h +++ b/Kernel/Multiboot.h @@ -18,6 +18,20 @@ struct multiboot_elf_section_header_table { }; typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + +struct multiboot_mmap_entry { + dword size; + qword addr; + qword len; + dword type; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + struct multiboot_info { // Multiboot info version number. dword flags; diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index 9b80eaae57..00537c5fa5 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include //#define MM_DEBUG @@ -21,18 +22,9 @@ MemoryManager& MM MemoryManager::MemoryManager() { - // FIXME: This is not the best way to do memory map detection. - // Rewrite to use BIOS int 15,e820 once we have VM86 support. - word base_memory = (CMOS::read(0x16) << 8) | CMOS::read(0x15); - word ext_memory = (CMOS::read(0x18) << 8) | CMOS::read(0x17); - - kprintf("%u kB base memory\n", base_memory); - kprintf("%u kB extended memory\n", ext_memory); - - m_ram_size = ext_memory * 1024; - m_kernel_page_directory = PageDirectory::create_at_fixed_address(PhysicalAddress(0x4000)); m_page_table_zero = (dword*)0x6000; + m_page_table_one = (dword*)0x7000; initialize_paging(); @@ -47,6 +39,7 @@ void MemoryManager::populate_page_directory(PageDirectory& page_directory) { page_directory.m_directory_page = allocate_supervisor_physical_page(); page_directory.entries()[0] = kernel_page_directory().entries()[0]; + page_directory.entries()[1] = kernel_page_directory().entries()[1]; // Defer to the kernel page tables for 0xC0000000-0xFFFFFFFF for (int i = 768; i < 1024; ++i) page_directory.entries()[i] = kernel_page_directory().entries()[i]; @@ -57,6 +50,7 @@ void MemoryManager::initialize_paging() static_assert(sizeof(MemoryManager::PageDirectoryEntry) == 4); static_assert(sizeof(MemoryManager::PageTableEntry) == 4); memset(m_page_table_zero, 0, PAGE_SIZE); + memset(m_page_table_one, 0, PAGE_SIZE); #ifdef MM_DEBUG dbgprintf("MM: Kernel page directory @ %p\n", kernel_page_directory().cr3()); @@ -69,27 +63,48 @@ void MemoryManager::initialize_paging() map_protected(VirtualAddress(0), PAGE_SIZE); #ifdef MM_DEBUG - dbgprintf("MM: Identity map bottom 4MB\n"); + dbgprintf("MM: Identity map bottom 5MB\n"); #endif - // The bottom 4 MB (except for the null page) are identity mapped & supervisor only. + // The bottom 5 MB (except for the null page) are identity mapped & supervisor only. // Every process shares these mappings. - create_identity_mapping(kernel_page_directory(), VirtualAddress(PAGE_SIZE), (4 * MB) - PAGE_SIZE); + create_identity_mapping(kernel_page_directory(), VirtualAddress(PAGE_SIZE), (5 * MB) - PAGE_SIZE); // Basic memory map: // 0 -> 512 kB Kernel code. Root page directory & PDE 0. // (last page before 1MB) Used by quickmap_page(). - // 1 MB -> 2 MB kmalloc_eternal() space. - // 2 MB -> 3 MB kmalloc() space. - // 3 MB -> 4 MB Supervisor physical pages (available for allocation!) - // 4 MB -> 0xc0000000 Userspace physical pages (available for allocation!) + // 1 MB -> 3 MB kmalloc_eternal() space. + // 3 MB -> 4 MB kmalloc() space. + // 4 MB -> 5 MB Supervisor physical pages (available for allocation!) + // 5 MB -> 0xc0000000 Userspace physical pages (available for allocation!) // 0xc0000000-0xffffffff Kernel-only linear address space - for (size_t i = (2 * MB); i < (4 * MB); i += PAGE_SIZE) - m_free_supervisor_physical_pages.append(PhysicalPage::create_eternal(PhysicalAddress(i), true)); + for (auto* mmap = (multiboot_memory_map_t*)multiboot_info_ptr->mmap_addr; (unsigned long)mmap < multiboot_info_ptr->mmap_addr + multiboot_info_ptr->mmap_length; mmap = (multiboot_memory_map_t*)((unsigned long)mmap + mmap->size + sizeof(mmap->size))) { + kprintf("MM: Multiboot mmap: base_addr = 0x%x%08x, length = 0x%x%08x, type = 0x%x\n", + (dword)(mmap->addr >> 32), + (dword)(mmap->addr & 0xffffffff), + (dword)(mmap->len >> 32), + (dword)(mmap->len & 0xffffffff), + (dword)mmap->type); + + if (mmap->type != MULTIBOOT_MEMORY_AVAILABLE) + continue; + // FIXME: Maybe make use of stuff below the 1MB mark? + if (mmap->addr < (1 * MB)) + continue; + + for (size_t page_base = mmap->addr; page_base < (mmap->addr + mmap->len); page_base += PAGE_SIZE) { + if (page_base < (4 * MB)) { + // Skip over pages managed by kmalloc. + continue; + } + + if (page_base < (5 * MB)) + m_free_supervisor_physical_pages.append(PhysicalPage::create_eternal(PhysicalAddress(page_base), true)); + else + m_free_physical_pages.append(PhysicalPage::create_eternal(PhysicalAddress(page_base), false)); + } + } - dbgprintf("MM: 4MB-%uMB available for allocation\n", m_ram_size / 1048576); - for (size_t i = (4 * MB); i < m_ram_size; i += PAGE_SIZE) - m_free_physical_pages.append(PhysicalPage::create_eternal(PhysicalAddress(i), false)); m_quickmap_addr = VirtualAddress((1 * MB) - PAGE_SIZE); #ifdef MM_DEBUG dbgprintf("MM: Quickmap will use P%x\n", m_quickmap_addr.get()); @@ -150,6 +165,12 @@ auto MemoryManager::ensure_pte(PageDirectory& page_directory, VirtualAddress vad pde.set_user_allowed(false); pde.set_present(true); pde.set_writable(true); + } else if (page_directory_index == 1) { + ASSERT(&page_directory == m_kernel_page_directory); + pde.set_page_table_base((dword)m_page_table_one); + pde.set_user_allowed(false); + pde.set_present(true); + pde.set_writable(true); } else { //ASSERT(&page_directory != m_kernel_page_directory.ptr()); auto page_table = allocate_page_table(page_directory, page_directory_index); diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h index 94f8576998..ef2e274faa 100644 --- a/Kernel/VM/MemoryManager.h +++ b/Kernel/VM/MemoryManager.h @@ -64,8 +64,6 @@ public: void remap_region(PageDirectory&, Region&); - size_t ram_size() const { return m_ram_size; } - int user_physical_pages_in_existence() const { return s_user_physical_pages_in_existence; } int super_physical_pages_in_existence() const { return s_super_physical_pages_in_existence; } @@ -214,7 +212,8 @@ private: PageTableEntry ensure_pte(PageDirectory&, VirtualAddress); RetainPtr m_kernel_page_directory; - dword* m_page_table_zero; + dword* m_page_table_zero { nullptr }; + dword* m_page_table_one { nullptr }; VirtualAddress m_quickmap_addr; @@ -225,7 +224,6 @@ private: HashTable m_user_regions; HashTable m_kernel_regions; - size_t m_ram_size { 0 }; bool m_quickmap_in_use { false }; }; diff --git a/Kernel/kmalloc.cpp b/Kernel/kmalloc.cpp index c5d8a76024..48d18cb98b 100644 --- a/Kernel/kmalloc.cpp +++ b/Kernel/kmalloc.cpp @@ -23,11 +23,11 @@ struct [[gnu::packed]] allocation_t #define CHUNK_SIZE 32 #define POOL_SIZE (1024 * 1024) -#define ETERNAL_BASE_PHYSICAL 0x100000 -#define ETERNAL_RANGE_SIZE 0x100000 +#define ETERNAL_BASE_PHYSICAL (1 * MB) +#define ETERNAL_RANGE_SIZE (2 * MB) -#define BASE_PHYSICAL 0x200000 -#define RANGE_SIZE 0x100000 +#define BASE_PHYSICAL (3 * MB) +#define RANGE_SIZE (1 * MB) static byte alloc_map[POOL_SIZE / CHUNK_SIZE / 8];