diff --git a/headers/private/kernel/arch/x86/arch_kernel_args.h b/headers/private/kernel/arch/x86/arch_kernel_args.h index 76fcd46d1e..8fb6268c82 100644 --- a/headers/private/kernel/arch/x86/arch_kernel_args.h +++ b/headers/private/kernel/arch/x86/arch_kernel_args.h @@ -25,6 +25,7 @@ typedef struct { uint32 vir_pgdir; uint32 num_pgtables; uint32 pgtables[MAX_BOOT_PTABLES]; + uint32 virtual_end; uint32 phys_idt; uint32 vir_idt; uint32 phys_gdt; diff --git a/headers/private/kernel/boot/platform/bios_ia32/platform_kernel_args.h b/headers/private/kernel/boot/platform/bios_ia32/platform_kernel_args.h index 946bddd4c7..ef24b3ad7a 100644 --- a/headers/private/kernel/boot/platform/bios_ia32/platform_kernel_args.h +++ b/headers/private/kernel/boot/platform/bios_ia32/platform_kernel_args.h @@ -16,9 +16,9 @@ // must match SMP_MAX_CPUS in arch_smp.h #define MAX_BOOT_CPUS 8 -#define MAX_PHYSICAL_MEMORY_RANGE 6 -#define MAX_PHYSICAL_ALLOCATED_RANGE 6 -#define MAX_VIRTUAL_ALLOCATED_RANGE 6 +#define MAX_PHYSICAL_MEMORY_RANGE 8 +#define MAX_PHYSICAL_ALLOCATED_RANGE 8 +#define MAX_VIRTUAL_ALLOCATED_RANGE 8 #define MAX_SERIAL_PORTS 4 diff --git a/src/system/boot/platform/bios_ia32/mmu.cpp b/src/system/boot/platform/bios_ia32/mmu.cpp index fbaf362c0d..9ad79f96b7 100644 --- a/src/system/boot/platform/bios_ia32/mmu.cpp +++ b/src/system/boot/platform/bios_ia32/mmu.cpp @@ -72,7 +72,7 @@ struct extended_memory { static const uint32 kDefaultPageTableFlags = 0x07; // present, user, R/W -static const size_t kMaxKernelSize = 0x200000; // 2 MB for the kernel +static const size_t kMaxKernelSize = 0x1000000; // 16 MB for the kernel // working page directory and page table static uint32 *sPageDirectory = 0; @@ -81,7 +81,6 @@ static uint32 *sPageDirectory = 0; static addr_t sNextPhysicalAddress = 0x112000; static addr_t sNextVirtualAddress = KERNEL_BASE + kMaxKernelSize; -static addr_t sMaxVirtualAddress = KERNEL_BASE + 0x400000; static addr_t sNextPageTableAddress = 0x7d000; static const uint32 kPageTableRegionEnd = 0x8b000; @@ -91,7 +90,6 @@ static const uint32 kPageTableRegionEnd = 0x8b000; static addr_t sNextPhysicalAddress = 0x100000; static addr_t sNextVirtualAddress = KERNEL_BASE + kMaxKernelSize; -static addr_t sMaxVirtualAddress = KERNEL_BASE + 0x400000; static addr_t sNextPageTableAddress = 0x90000; static const uint32 kPageTableRegionEnd = 0x9e000; @@ -151,14 +149,17 @@ get_next_page_table() /*! Adds a new page table for the specified base address */ -static void +static uint32* add_page_table(addr_t base) { + base = ROUNDDOWN(base, B_PAGE_SIZE * 1024); + // Get new page table and clear it out uint32 *pageTable = get_next_page_table(); if (pageTable > (uint32 *)(8 * 1024 * 1024)) { panic("tried to add page table beyond the identity mapped 8 MB " "region\n"); + return NULL; } TRACE("add_page_table(base = %p), got page: %p\n", (void*)base, pageTable); @@ -172,6 +173,13 @@ add_page_table(addr_t base) // put the new page table into the page directory sPageDirectory[base / (4 * 1024 * 1024)] = (uint32)pageTable | kDefaultPageTableFlags; + + // update the virtual end address in the kernel args + base += B_PAGE_SIZE * 1024; + if (base > gKernelArgs.arch_args.virtual_end) + gKernelArgs.arch_args.virtual_end = base; + + return pageTable; } @@ -210,22 +218,23 @@ map_page(addr_t virtualAddress, addr_t physicalAddress, uint32 flags) (void *)virtualAddress); } - if (virtualAddress >= sMaxVirtualAddress) { - // we need to add a new page table - add_page_table(sMaxVirtualAddress); - sMaxVirtualAddress += B_PAGE_SIZE * 1024; + uint32 *pageTable = (uint32 *)(sPageDirectory[virtualAddress + / (B_PAGE_SIZE * 1024)] & 0xfffff000); - if (virtualAddress >= sMaxVirtualAddress) { - panic("map_page: asked to map a page to %p\n", - (void *)virtualAddress); + if (pageTable == NULL) { + // we need to add a new page table + pageTable = add_page_table(virtualAddress); + + if (pageTable == NULL) { + panic("map_page: failed to allocate a page table for virtual " + "address %p\n", (void*)virtualAddress); + return; } } physicalAddress &= ~(B_PAGE_SIZE - 1); // map the page to the correct page table - uint32 *pageTable = (uint32 *)(sPageDirectory[virtualAddress - / (B_PAGE_SIZE * 1024)] & 0xfffff000); uint32 tableEntry = (virtualAddress % (B_PAGE_SIZE * 1024)) / B_PAGE_SIZE; TRACE("map_page: inserting pageTable %p, tableEntry %" B_PRIu32 @@ -350,7 +359,6 @@ init_page_directory(void) sPageDirectory[1] = (uint32)pageTable | kDefaultPageFlags; gKernelArgs.arch_args.num_pgtables = 0; - add_page_table(KERNEL_BASE); // switch to the new pgdir and enable paging asm("movl %0, %%eax;" @@ -598,6 +606,8 @@ mmu_init(void) { TRACE("mmu_init\n"); + gKernelArgs.arch_args.virtual_end = KERNEL_BASE; + gKernelArgs.physical_allocated_range[0].start = sNextPhysicalAddress; gKernelArgs.physical_allocated_range[0].size = 0; gKernelArgs.num_physical_allocated_ranges = 1; @@ -635,69 +645,42 @@ mmu_init(void) for (uint32 i = 0; i < extMemoryCount; i++) { // Type 1 is available memory if (extMemoryBlock[i].type == 1) { + uint64 base = extMemoryBlock[i].base_addr; + uint64 end = base + extMemoryBlock[i].length; + // round everything up to page boundaries, exclusive of pages // it partially occupies - if ((extMemoryBlock[i].base_addr % B_PAGE_SIZE) != 0) { - extMemoryBlock[i].length -= B_PAGE_SIZE - - extMemoryBlock[i].base_addr % B_PAGE_SIZE; - } - extMemoryBlock[i].base_addr - = ROUNDUP(extMemoryBlock[i].base_addr, B_PAGE_SIZE); - extMemoryBlock[i].length - = ROUNDDOWN(extMemoryBlock[i].length, B_PAGE_SIZE); + base = ROUNDUP(base, B_PAGE_SIZE); + end = ROUNDDOWN(end, B_PAGE_SIZE); // we ignore all memory beyond 4 GB - if (extMemoryBlock[i].base_addr > 0xffffffffULL) + if (end > 0x100000000ULL) + end = 0x100000000ULL; + if (end <= base) continue; - if (extMemoryBlock[i].base_addr + extMemoryBlock[i].length - > 0xffffffffULL) { - extMemoryBlock[i].length - = 0x100000000ULL - extMemoryBlock[i].base_addr; + if (insert_physical_memory_range(base, end - base) != B_OK) { + panic("mmu_init(): Failed to add physical memory range " + "%#" B_PRIx64 " - %#" B_PRIx64 "\n", base, end); } - - if (gKernelArgs.num_physical_memory_ranges > 0) { - // we might want to extend a previous hole - addr_t previousEnd = gKernelArgs.physical_memory_range[ - gKernelArgs.num_physical_memory_ranges - 1].start - + gKernelArgs.physical_memory_range[ - gKernelArgs.num_physical_memory_ranges - 1].size; - addr_t holeSize = extMemoryBlock[i].base_addr - previousEnd; - - // If the hole is smaller than 1 MB, we try to mark the - // memory as allocated and extend the previous memory range - if (previousEnd <= extMemoryBlock[i].base_addr - && holeSize < 0x100000 - && insert_physical_allocated_range(previousEnd, - extMemoryBlock[i].base_addr - previousEnd) - == B_OK) { - gKernelArgs.physical_memory_range[ - gKernelArgs.num_physical_memory_ranges - 1].size - += holeSize; - } - } - - insert_physical_memory_range(extMemoryBlock[i].base_addr, - extMemoryBlock[i].length); } } + + // sort the range + sort_addr_range(gKernelArgs.physical_memory_range, + gKernelArgs.num_physical_memory_ranges); } else { // TODO: for now! - dprintf("No extended memory block - using 32 MB (fix me!)\n"); - uint32 memSize = 32 * 1024 * 1024; + dprintf("No extended memory block - using 64 MB (fix me!)\n"); + uint32 memSize = 64 * 1024 * 1024; // We dont have an extended map, assume memory is contiguously mapped - // at 0x0 + // at 0x0, but leave out the BIOS range ((640k - 1 page) to 1 MB). gKernelArgs.physical_memory_range[0].start = 0; - gKernelArgs.physical_memory_range[0].size = memSize; - gKernelArgs.num_physical_memory_ranges = 1; - - // mark the bios area allocated - uint32 biosRange = gKernelArgs.num_physical_allocated_ranges++; - - gKernelArgs.physical_allocated_range[biosRange].start = 0x9f000; - // 640k - 1 page - gKernelArgs.physical_allocated_range[biosRange].size = 0x61000; + gKernelArgs.physical_memory_range[0].size = 0x9f000; + gKernelArgs.physical_memory_range[1].start = 0x100000; + gKernelArgs.physical_memory_range[1].size = memSize; + gKernelArgs.num_physical_memory_ranges = 2; } gKernelArgs.arch_args.page_hole = 0xffc00000; diff --git a/src/system/kernel/arch/x86/arch_vm.cpp b/src/system/kernel/arch/x86/arch_vm.cpp index 821f1088a6..ead981aceb 100644 --- a/src/system/kernel/arch/x86/arch_vm.cpp +++ b/src/system/kernel/arch/x86/arch_vm.cpp @@ -615,7 +615,7 @@ arch_vm_init_end(kernel_args *args) // throw away anything in the kernel_args.pgtable[] that's not yet mapped vm_free_unused_boot_loader_range(KERNEL_BASE, - 0x400000 * args->arch_args.num_pgtables); + args->arch_args.virtual_end - KERNEL_BASE); return B_OK; } diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 85b939add1..e43a716a55 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -3004,7 +3004,8 @@ unmap_and_free_physical_pages(VMTranslationMap* map, addr_t start, addr_t end) && (flags & PAGE_PRESENT) != 0) { vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); if (page != NULL && page->State() != PAGE_STATE_FREE - && page->State() != PAGE_STATE_CLEAR) { + && page->State() != PAGE_STATE_CLEAR + && page->State() != PAGE_STATE_UNUSED) { DEBUG_PAGE_ACCESS_START(page); vm_page_set_state(page, PAGE_STATE_FREE); } diff --git a/src/system/kernel/vm/vm_page.cpp b/src/system/kernel/vm/vm_page.cpp index 33144a1869..3468e0163f 100644 --- a/src/system/kernel/vm/vm_page.cpp +++ b/src/system/kernel/vm/vm_page.cpp @@ -1253,6 +1253,63 @@ clear_page(struct vm_page *page) } +static status_t +mark_page_range_in_use(addr_t startPage, addr_t length, bool wired) +{ + TRACE(("mark_page_range_in_use: start 0x%lx, len 0x%lx\n", + startPage, length)); + + if (sPhysicalPageOffset > startPage) { + TRACE(("mark_page_range_in_use: start page %ld is before free list\n", + startPage)); + return B_BAD_VALUE; + } + startPage -= sPhysicalPageOffset; + if (startPage + length > sNumPages) { + TRACE(("mark_page_range_in_use: range would extend past free list\n")); + return B_BAD_VALUE; + } + + WriteLocker locker(sFreePageQueuesLock); + + for (addr_t i = 0; i < length; i++) { + vm_page *page = &sPages[startPage + i]; + switch (page->State()) { + case PAGE_STATE_FREE: + case PAGE_STATE_CLEAR: + { +// TODO: This violates the page reservation policy, since we remove pages from +// the free/clear queues without having reserved them before. This should happen +// in the early boot process only, though. + DEBUG_PAGE_ACCESS_START(page); + VMPageQueue& queue = page->State() == PAGE_STATE_FREE + ? sFreePageQueue : sClearPageQueue; + queue.Remove(page); + page->SetState(wired ? PAGE_STATE_UNUSED : PAGE_STATE_UNUSED); + page->busy = false; + atomic_add(&sUnreservedFreePages, -1); + DEBUG_PAGE_ACCESS_END(page); + break; + } + case PAGE_STATE_WIRED: + case PAGE_STATE_UNUSED: + break; + case PAGE_STATE_ACTIVE: + case PAGE_STATE_INACTIVE: + case PAGE_STATE_MODIFIED: + case PAGE_STATE_CACHED: + default: + // uh + dprintf("mark_page_range_in_use: page 0x%lx in non-free state %d!\n", + startPage + i, page->State()); + break; + } + } + + return B_OK; +} + + /*! This is a background thread that wakes up every now and then (every 100ms) and moves some pages from the free queue over to the clear queue. @@ -2761,10 +2818,23 @@ vm_page_init(kernel_args *args) TRACE(("initialized table\n")); - // mark some of the page ranges in use + // mark the ranges between usable physical memory unused + addr_t previousEnd = 0; + for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) { + addr_t base = args->physical_memory_range[i].start; + addr_t size = args->physical_memory_range[i].size; + if (base > previousEnd) { + mark_page_range_in_use(previousEnd / B_PAGE_SIZE, + (base - previousEnd) / B_PAGE_SIZE, false); + } + previousEnd = base + size; + } + + // mark the allocated physical page ranges wired for (uint32 i = 0; i < args->num_physical_allocated_ranges; i++) { - vm_mark_page_range_inuse(args->physical_allocated_range[i].start / B_PAGE_SIZE, - args->physical_allocated_range[i].size / B_PAGE_SIZE); + mark_page_range_in_use( + args->physical_allocated_range[i].start / B_PAGE_SIZE, + args->physical_allocated_range[i].size / B_PAGE_SIZE, true); } // The target of actually free pages. This must be at least the system @@ -2873,57 +2943,7 @@ vm_mark_page_inuse(addr_t page) status_t vm_mark_page_range_inuse(addr_t startPage, addr_t length) { - TRACE(("vm_mark_page_range_inuse: start 0x%lx, len 0x%lx\n", - startPage, length)); - - if (sPhysicalPageOffset > startPage) { - TRACE(("vm_mark_page_range_inuse: start page %ld is before free list\n", - startPage)); - return B_BAD_VALUE; - } - startPage -= sPhysicalPageOffset; - if (startPage + length > sNumPages) { - TRACE(("vm_mark_page_range_inuse: range would extend past free list\n")); - return B_BAD_VALUE; - } - - WriteLocker locker(sFreePageQueuesLock); - - for (addr_t i = 0; i < length; i++) { - vm_page *page = &sPages[startPage + i]; - switch (page->State()) { - case PAGE_STATE_FREE: - case PAGE_STATE_CLEAR: - { -// TODO: This violates the page reservation policy, since we remove pages from -// the free/clear queues without having reserved them before. This should happen -// in the early boot process only, though. - DEBUG_PAGE_ACCESS_START(page); - VMPageQueue& queue = page->State() == PAGE_STATE_FREE - ? sFreePageQueue : sClearPageQueue; - queue.Remove(page); - page->SetState(PAGE_STATE_UNUSED); - page->busy = false; - atomic_add(&sUnreservedFreePages, -1); - DEBUG_PAGE_ACCESS_END(page); - break; - } - case PAGE_STATE_WIRED: - break; - case PAGE_STATE_ACTIVE: - case PAGE_STATE_INACTIVE: - case PAGE_STATE_MODIFIED: - case PAGE_STATE_CACHED: - case PAGE_STATE_UNUSED: - default: - // uh - dprintf("vm_mark_page_range_inuse: page 0x%lx in non-free state %d!\n", - startPage + i, page->State()); - break; - } - } - - return B_OK; + return mark_page_range_in_use(startPage, length, false); }