mirror of
https://github.com/RGBCube/serenity
synced 2025-05-23 18:25:08 +00:00
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. :^)
This commit is contained in:
parent
8258b699db
commit
9da62f52a1
4 changed files with 63 additions and 30 deletions
|
@ -18,6 +18,20 @@ struct multiboot_elf_section_header_table {
|
||||||
};
|
};
|
||||||
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
|
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 {
|
struct multiboot_info {
|
||||||
// Multiboot info version number.
|
// Multiboot info version number.
|
||||||
dword flags;
|
dword flags;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <AK/kstdio.h>
|
#include <AK/kstdio.h>
|
||||||
#include <Kernel/Arch/i386/CPU.h>
|
#include <Kernel/Arch/i386/CPU.h>
|
||||||
#include <Kernel/FileSystem/Inode.h>
|
#include <Kernel/FileSystem/Inode.h>
|
||||||
|
#include <Kernel/Multiboot.h>
|
||||||
#include <Kernel/VM/MemoryManager.h>
|
#include <Kernel/VM/MemoryManager.h>
|
||||||
|
|
||||||
//#define MM_DEBUG
|
//#define MM_DEBUG
|
||||||
|
@ -21,18 +22,9 @@ MemoryManager& MM
|
||||||
|
|
||||||
MemoryManager::MemoryManager()
|
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_kernel_page_directory = PageDirectory::create_at_fixed_address(PhysicalAddress(0x4000));
|
||||||
m_page_table_zero = (dword*)0x6000;
|
m_page_table_zero = (dword*)0x6000;
|
||||||
|
m_page_table_one = (dword*)0x7000;
|
||||||
|
|
||||||
initialize_paging();
|
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.m_directory_page = allocate_supervisor_physical_page();
|
||||||
page_directory.entries()[0] = kernel_page_directory().entries()[0];
|
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
|
// Defer to the kernel page tables for 0xC0000000-0xFFFFFFFF
|
||||||
for (int i = 768; i < 1024; ++i)
|
for (int i = 768; i < 1024; ++i)
|
||||||
page_directory.entries()[i] = kernel_page_directory().entries()[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::PageDirectoryEntry) == 4);
|
||||||
static_assert(sizeof(MemoryManager::PageTableEntry) == 4);
|
static_assert(sizeof(MemoryManager::PageTableEntry) == 4);
|
||||||
memset(m_page_table_zero, 0, PAGE_SIZE);
|
memset(m_page_table_zero, 0, PAGE_SIZE);
|
||||||
|
memset(m_page_table_one, 0, PAGE_SIZE);
|
||||||
|
|
||||||
#ifdef MM_DEBUG
|
#ifdef MM_DEBUG
|
||||||
dbgprintf("MM: Kernel page directory @ %p\n", kernel_page_directory().cr3());
|
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);
|
map_protected(VirtualAddress(0), PAGE_SIZE);
|
||||||
|
|
||||||
#ifdef MM_DEBUG
|
#ifdef MM_DEBUG
|
||||||
dbgprintf("MM: Identity map bottom 4MB\n");
|
dbgprintf("MM: Identity map bottom 5MB\n");
|
||||||
#endif
|
#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.
|
// 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:
|
// Basic memory map:
|
||||||
// 0 -> 512 kB Kernel code. Root page directory & PDE 0.
|
// 0 -> 512 kB Kernel code. Root page directory & PDE 0.
|
||||||
// (last page before 1MB) Used by quickmap_page().
|
// (last page before 1MB) Used by quickmap_page().
|
||||||
// 1 MB -> 2 MB kmalloc_eternal() space.
|
// 1 MB -> 3 MB kmalloc_eternal() space.
|
||||||
// 2 MB -> 3 MB kmalloc() space.
|
// 3 MB -> 4 MB kmalloc() space.
|
||||||
// 3 MB -> 4 MB Supervisor physical pages (available for allocation!)
|
// 4 MB -> 5 MB Supervisor physical pages (available for allocation!)
|
||||||
// 4 MB -> 0xc0000000 Userspace physical pages (available for allocation!)
|
// 5 MB -> 0xc0000000 Userspace physical pages (available for allocation!)
|
||||||
// 0xc0000000-0xffffffff Kernel-only linear address space
|
// 0xc0000000-0xffffffff Kernel-only linear address space
|
||||||
|
|
||||||
for (size_t i = (2 * MB); i < (4 * MB); i += PAGE_SIZE)
|
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))) {
|
||||||
m_free_supervisor_physical_pages.append(PhysicalPage::create_eternal(PhysicalAddress(i), true));
|
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);
|
m_quickmap_addr = VirtualAddress((1 * MB) - PAGE_SIZE);
|
||||||
#ifdef MM_DEBUG
|
#ifdef MM_DEBUG
|
||||||
dbgprintf("MM: Quickmap will use P%x\n", m_quickmap_addr.get());
|
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_user_allowed(false);
|
||||||
pde.set_present(true);
|
pde.set_present(true);
|
||||||
pde.set_writable(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 {
|
} else {
|
||||||
//ASSERT(&page_directory != m_kernel_page_directory.ptr());
|
//ASSERT(&page_directory != m_kernel_page_directory.ptr());
|
||||||
auto page_table = allocate_page_table(page_directory, page_directory_index);
|
auto page_table = allocate_page_table(page_directory, page_directory_index);
|
||||||
|
|
|
@ -64,8 +64,6 @@ public:
|
||||||
|
|
||||||
void remap_region(PageDirectory&, Region&);
|
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 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; }
|
int super_physical_pages_in_existence() const { return s_super_physical_pages_in_existence; }
|
||||||
|
|
||||||
|
@ -214,7 +212,8 @@ private:
|
||||||
PageTableEntry ensure_pte(PageDirectory&, VirtualAddress);
|
PageTableEntry ensure_pte(PageDirectory&, VirtualAddress);
|
||||||
|
|
||||||
RetainPtr<PageDirectory> m_kernel_page_directory;
|
RetainPtr<PageDirectory> 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;
|
VirtualAddress m_quickmap_addr;
|
||||||
|
|
||||||
|
@ -225,7 +224,6 @@ private:
|
||||||
HashTable<Region*> m_user_regions;
|
HashTable<Region*> m_user_regions;
|
||||||
HashTable<Region*> m_kernel_regions;
|
HashTable<Region*> m_kernel_regions;
|
||||||
|
|
||||||
size_t m_ram_size { 0 };
|
|
||||||
bool m_quickmap_in_use { false };
|
bool m_quickmap_in_use { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,11 @@ struct [[gnu::packed]] allocation_t
|
||||||
#define CHUNK_SIZE 32
|
#define CHUNK_SIZE 32
|
||||||
#define POOL_SIZE (1024 * 1024)
|
#define POOL_SIZE (1024 * 1024)
|
||||||
|
|
||||||
#define ETERNAL_BASE_PHYSICAL 0x100000
|
#define ETERNAL_BASE_PHYSICAL (1 * MB)
|
||||||
#define ETERNAL_RANGE_SIZE 0x100000
|
#define ETERNAL_RANGE_SIZE (2 * MB)
|
||||||
|
|
||||||
#define BASE_PHYSICAL 0x200000
|
#define BASE_PHYSICAL (3 * MB)
|
||||||
#define RANGE_SIZE 0x100000
|
#define RANGE_SIZE (1 * MB)
|
||||||
|
|
||||||
static byte alloc_map[POOL_SIZE / CHUNK_SIZE / 8];
|
static byte alloc_map[POOL_SIZE / CHUNK_SIZE / 8];
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue