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];