From 93cba1da96275eb617fcdc581ec4522e0b107adf Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Sun, 8 Jul 2012 15:03:23 +0100 Subject: [PATCH] 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(). --- src/system/boot/platform/bios_ia32/long.cpp | 28 ++++++++++++------- src/system/kernel/arch/x86/64/stubs.cpp | 2 +- .../x86/paging/64bit/X86PagingMethod64Bit.cpp | 8 +++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/system/boot/platform/bios_ia32/long.cpp b/src/system/boot/platform/bios_ia32/long.cpp index 16fd1ae0f1..28137d48eb 100644 --- a/src/system/boot/platform/bios_ia32/long.cpp +++ b/src/system/boot/platform/bios_ia32/long.cpp @@ -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, diff --git a/src/system/kernel/arch/x86/64/stubs.cpp b/src/system/kernel/arch/x86/64/stubs.cpp index 041e17f525..a803b1ce19 100644 --- a/src/system/kernel/arch/x86/64/stubs.cpp +++ b/src/system/kernel/arch/x86/64/stubs.cpp @@ -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; } diff --git a/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.cpp b/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.cpp index 4c622548d3..a834cd264c 100644 --- a/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.cpp +++ b/src/system/kernel/arch/x86/paging/64bit/X86PagingMethod64Bit.cpp @@ -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);