Map all physical memory in the long mode paging setup.

Since x86_64 has such a large virtual address space all available physical
memory can be mapped in to it. The physical page mapper implementation for
x86_64 will use this mapping. Also changed the mapping code to map kernel
pages with the global flag.
This commit is contained in:
Alex Smith
2012-07-04 18:28:50 +01:00
parent 950b24e32d
commit e70dd7e0af
+54 -14
View File
@@ -6,6 +6,8 @@
#include "long.h"
#include <algorithm>
#include <KernelExport.h>
// Include the x86_64 version of descriptors.h
@@ -24,6 +26,12 @@
#include "mmu.h"
static const uint64 kTableMappingFlags = 0x3;
static const uint64 kLargePageMappingFlags = 0x183;
static const uint64 kPageMappingFlags = 0x103;
// Global, R/W, Present
/*! Convert a 32-bit address to a 64-bit address. */
static inline uint64
fix_address(uint64 address)
@@ -87,36 +95,68 @@ long_idt_init()
static void
long_mmu_init()
{
uint64* pml4;
uint64* pdpt;
uint64* pageDir;
uint64* pageTable;
addr_t physicalAddress;
// Allocate the top level PML4.
uint64* pml4 = (uint64*)mmu_allocate_page(&gKernelArgs.arch_args.phys_pgdir);
pml4 = (uint64*)mmu_allocate_page(&gKernelArgs.arch_args.phys_pgdir);
memset(pml4, 0, B_PAGE_SIZE);
gKernelArgs.arch_args.vir_pgdir = (uint64)(addr_t)pml4;
// Identity map the first 1GB of memory, do so using large pages.
// Find the highest physical memory address. We map all physical memory
// into the kernel address space, so we want to make sure we map everything
// we have available.
uint64 maxAddress = 0;
for (uint32 i = 0; i < gKernelArgs.num_physical_memory_ranges; i++) {
maxAddress = std::max(maxAddress,
gKernelArgs.physical_memory_range[i].start
+ gKernelArgs.physical_memory_range[i].size);
}
uint64* pdpt = (uint64*)mmu_allocate_page(&physicalAddress);
// Want to map at least 4GB, there may be stuff other than usable RAM that
// could be in the first 4GB of physical address space.
maxAddress = std::max(maxAddress, (uint64)0x100000000ll);
maxAddress = ROUNDUP(maxAddress, 0x40000000);
// Currently only use 1 PDPT (512GB). This will need to change if someone
// wants to use Haiku on a box with more than 512GB of RAM but that's
// probably not going to happen any time soon.
if (maxAddress / 0x40000000 > 512)
panic("Can't currently support more than 512GB of RAM!");
// Create page tables for the physical map area. Also map this PDPT
// temporarily at the bottom of the address space so that we are identity
// mapped.
pdpt = (uint64*)mmu_allocate_page(&physicalAddress);
memset(pdpt, 0, B_PAGE_SIZE);
pml4[0] = physicalAddress | 0x3;
pml4[510] = physicalAddress | kTableMappingFlags;
pml4[0] = physicalAddress | kTableMappingFlags;
uint64* pageDir = (uint64*)mmu_allocate_page(&physicalAddress);
memset(pageDir, 0, B_PAGE_SIZE);
pdpt[0] = physicalAddress | 0x3;
for (uint64 i = 0; i < maxAddress; i += 0x40000000) {
dprintf("mapping %llu GB\n", i / 0x40000000);
for (uint32 i = 0; i < 512; i++) {
pageDir[i] = (i * 0x200000) | 0x83;
pageDir = (uint64*)mmu_allocate_page(&physicalAddress);
memset(pageDir, 0, B_PAGE_SIZE);
pdpt[i / 0x40000000] = physicalAddress | kTableMappingFlags;
for (uint64 j = 0; j < 0x40000000; j += 0x200000) {
pageDir[j / 0x200000] = (i + j) | kLargePageMappingFlags;
}
}
// Allocate tables for the kernel mappings.
pdpt = (uint64*)mmu_allocate_page(&physicalAddress);
memset(pdpt, 0, B_PAGE_SIZE);
pml4[511] = physicalAddress | 0x3;
pml4[511] = physicalAddress | kTableMappingFlags;
pageDir = (uint64*)mmu_allocate_page(&physicalAddress);
memset(pageDir, 0, B_PAGE_SIZE);
pdpt[510] = physicalAddress | 0x3;
pdpt[510] = physicalAddress | kTableMappingFlags;
// Store the virtual memory usage information.
gKernelArgs.virtual_allocated_range[0].start = KERNEL_BASE_64BIT;
@@ -125,13 +165,13 @@ long_mmu_init()
// We can now allocate page tables and duplicate the mappings across from
// the 32-bit address space to them.
uint64* pageTable = NULL;
pageTable = NULL;
for (uint32 i = 0; i < gKernelArgs.virtual_allocated_range[0].size
/ B_PAGE_SIZE; i++) {
if ((i % 512) == 0) {
pageTable = (uint64*)mmu_allocate_page(&physicalAddress);
memset(pageTable, 0, B_PAGE_SIZE);
pageDir[i / 512] = physicalAddress | 0x3;
pageDir[i / 512] = physicalAddress | kTableMappingFlags;
// Just performed another virtual allocation, account for it.
gKernelArgs.virtual_allocated_range[0].size += B_PAGE_SIZE;
@@ -142,7 +182,7 @@ long_mmu_init()
&physicalAddress))
continue;
pageTable[i % 512] = physicalAddress | 0x3;
pageTable[i % 512] = physicalAddress | kPageMappingFlags;
}
gKernelArgs.arch_args.virtual_end = ROUNDUP(KERNEL_BASE_64BIT