Fixed a bug resulting from a mistake in the boot 64-bit paging setup.

This was an interesting bug to find. Was getting spurious triple faults
in the slab allocator. The problem was that the boot paging setup code
was mapping all page tables it created into the virtual address space,
but in the kernel no areas were being created to cover them, so during
arch_vm_init_end() the pages for them ended up being freed and then
overwritten later on. Fixed by unmapping page tables after populating
them in long_mmu_init().
This commit is contained in:
Alex Smith
2012-07-08 15:03:23 +01:00
parent cc248cf2b3
commit 93cba1da96
3 changed files with 23 additions and 15 deletions
+18 -10
View File
@@ -106,6 +106,13 @@ long_mmu_init()
memset(pml4, 0, B_PAGE_SIZE);
gKernelArgs.arch_args.vir_pgdir = fix_address((uint64)(addr_t)pml4);
// Store the virtual memory usage information.
gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE_64BIT;
gKernelArgs.virtual_allocated_range[0].size = mmu_get_virtual_usage();
gKernelArgs.num_virtual_allocated_ranges = 1;
gKernelArgs.arch_args.virtual_end = ROUNDUP(KERNEL_LOAD_BASE_64BIT
+ gKernelArgs.virtual_allocated_range[0].size, 0x200000);
// 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.
@@ -144,8 +151,12 @@ long_mmu_init()
for (uint64 j = 0; j < 0x40000000; j += 0x200000) {
pageDir[j / 0x200000] = (i + j) | kLargePageMappingFlags;
}
mmu_free(pageDir, B_PAGE_SIZE);
}
mmu_free(pdpt, B_PAGE_SIZE);
// Allocate tables for the kernel mappings.
pdpt = (uint64*)mmu_allocate_page(&physicalAddress);
@@ -156,23 +167,18 @@ long_mmu_init()
memset(pageDir, 0, B_PAGE_SIZE);
pdpt[510] = physicalAddress | kTableMappingFlags;
// Store the virtual memory usage information.
gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE_64BIT;
gKernelArgs.virtual_allocated_range[0].size = mmu_get_virtual_usage();
gKernelArgs.num_virtual_allocated_ranges = 1;
// We can now allocate page tables and duplicate the mappings across from
// the 32-bit address space to them.
pageTable = NULL;
for (uint32 i = 0; i < gKernelArgs.virtual_allocated_range[0].size
/ B_PAGE_SIZE; i++) {
if ((i % 512) == 0) {
if (pageTable)
mmu_free(pageTable, B_PAGE_SIZE);
pageTable = (uint64*)mmu_allocate_page(&physicalAddress);
memset(pageTable, 0, B_PAGE_SIZE);
pageDir[i / 512] = physicalAddress | kTableMappingFlags;
// Just performed another virtual allocation, account for it.
gKernelArgs.virtual_allocated_range[0].size += B_PAGE_SIZE;
}
// Get the physical address to map.
@@ -183,8 +189,10 @@ long_mmu_init()
pageTable[i % 512] = physicalAddress | kPageMappingFlags;
}
gKernelArgs.arch_args.virtual_end = ROUNDUP(KERNEL_LOAD_BASE_64BIT
+ gKernelArgs.virtual_allocated_range[0].size, 0x200000);
if (pageTable)
mmu_free(pageTable, B_PAGE_SIZE);
mmu_free(pageDir, B_PAGE_SIZE);
mmu_free(pdpt, B_PAGE_SIZE);
// Sort the address ranges.
sort_address_ranges(gKernelArgs.physical_memory_range,
+1 -1
View File
@@ -324,7 +324,7 @@ arch_system_info_init(struct kernel_args *args)
status_t
arch_thread_init(struct kernel_args *args)
{
return B_OK;
return B_ERROR;
}
@@ -197,7 +197,7 @@ X86PagingMethod64Bit::PageTableForAddress(uint64* virtualPML4,
vm_page_reservation* reservation,
TranslationMapPhysicalPageMapper* pageMapper, int32& mapCount)
{
TRACE("X86PagingMethod64Bit::PageTableEntryForAddress(%#" B_PRIxADDR ", "
TRACE("X86PagingMethod64Bit::PageTableForAddress(%#" B_PRIxADDR ", "
"%d)\n", virtualAddress, allocateTables);
// Get the PDPT.
@@ -215,7 +215,7 @@ X86PagingMethod64Bit::PageTableForAddress(uint64* virtualPML4,
phys_addr_t physicalPDPT
= (phys_addr_t)page->physical_page_number * B_PAGE_SIZE;
TRACE("X86PagingMethod64Bit::PageTableEntryForAddress(): creating PDPT "
TRACE("X86PagingMethod64Bit::PageTableForAddress(): creating PDPT "
"for va %#" B_PRIxADDR " at %#" B_PRIxPHYSADDR "\n", virtualAddress,
physicalPDPT);
@@ -245,7 +245,7 @@ X86PagingMethod64Bit::PageTableForAddress(uint64* virtualPML4,
phys_addr_t physicalPageDir
= (phys_addr_t)page->physical_page_number * B_PAGE_SIZE;
TRACE("X86PagingMethod64Bit::PageTableEntryForAddress(): creating page "
TRACE("X86PagingMethod64Bit::PageTableForAddress(): creating page "
"directory for va %#" B_PRIxADDR " at %#" B_PRIxPHYSADDR "\n",
virtualAddress, physicalPageDir);
@@ -275,7 +275,7 @@ X86PagingMethod64Bit::PageTableForAddress(uint64* virtualPML4,
phys_addr_t physicalPageTable
= (phys_addr_t)page->physical_page_number * B_PAGE_SIZE;
TRACE("X86PagingMethod64Bit::PageTableEntryForAddress(): creating page "
TRACE("X86PagingMethod64Bit::PageTableForAddress(): creating page "
"table for va %#" B_PRIxADDR " at %#" B_PRIxPHYSADDR "\n",
virtualAddress, physicalPageTable);