From 3e161fb661c1084b1667042e4ca9873e71a87ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 8 Jan 2007 12:14:06 +0000 Subject: [PATCH] * Instead of its home-brewn solution, mmu_init() now uses the functions declared in addr_range.h to add ranges to the arrays. This fixes the crashing bug reported by Larry Baydak. * Added some more exported functions to kernel_args.cpp (prototypes are in addr_range.h). * TODO: let the PPC/OpenFirmware implementation use those as well. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19739 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/boot/addr_range.h | 20 ++++- src/system/boot/loader/kernel_args.cpp | 89 ++++++++++++++++++++-- src/system/boot/platform/bios_ia32/mmu.cpp | 52 ++++++------- 3 files changed, 126 insertions(+), 35 deletions(-) diff --git a/headers/private/kernel/boot/addr_range.h b/headers/private/kernel/boot/addr_range.h index c048a309ae..201fb9fcc3 100644 --- a/headers/private/kernel/boot/addr_range.h +++ b/headers/private/kernel/boot/addr_range.h @@ -1,7 +1,7 @@ /* -** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. -** Distributed under the terms of the Haiku License. -*/ + * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ #ifndef KERNEL_BOOT_ADDR_RANGE_H #define KERNEL_BOOT_ADDR_RANGE_H @@ -14,10 +14,22 @@ typedef struct addr_range { addr_t size; } addr_range; + #ifdef __cplusplus -extern "C" +extern "C" { #endif + status_t insert_address_range(addr_range *ranges, uint32 *_numRanges, uint32 maxRanges, addr_t start, uint32 size); +status_t remove_addr_range(addr_range *ranges, uint32 *_numRanges, uint32 maxRanges, + addr_t start, uint32 size); + +status_t insert_physical_memory_range(addr_t start, uint32 size); +status_t insert_physical_allocated_range(addr_t start, uint32 size); +status_t insert_virtual_allocated_range(addr_t start, uint32 size); + +#ifdef __cplusplus +} +#endif #endif /* KERNEL_BOOT_ADDR_RANGE_H */ diff --git a/src/system/boot/loader/kernel_args.cpp b/src/system/boot/loader/kernel_args.cpp index 6007fec2bd..3ae59fae3e 100644 --- a/src/system/boot/loader/kernel_args.cpp +++ b/src/system/boot/loader/kernel_args.cpp @@ -36,6 +36,18 @@ remove_range_index(addr_range *ranges, uint32 &numRanges, uint32 index) } +static status_t +add_kernel_args_range(void *start, uint32 size) +{ + return insert_address_range(gKernelArgs.kernel_args_range, + &gKernelArgs.num_kernel_args_ranges, MAX_KERNEL_ARGS_RANGE, + (addr_t)start, size); +} + + +// #pragma mark - addr_range utility + + /** Inserts the specified (start, size) pair (aka range) in the * addr_range array. * It will extend existing ranges in order to have as little @@ -122,15 +134,82 @@ insert_address_range(addr_range *ranges, uint32 *_numRanges, uint32 maxRanges, } -static status_t -add_kernel_args_range(void *start, uint32 size) +extern "C" status_t +remove_address_range(addr_range *ranges, uint32 *_numRanges, uint32 maxRanges, + addr_t start, uint32 size) { - return insert_address_range(gKernelArgs.kernel_args_range, - &gKernelArgs.num_kernel_args_ranges, MAX_KERNEL_ARGS_RANGE, - (addr_t)start, size); + uint32 numRanges = *_numRanges; + + addr_t end = ROUNDUP(start + size, B_PAGE_SIZE); + start = ROUNDOWN(start, B_PAGE_SIZE); + + for (uint32 i = 0; i < numRanges; i++) { + addr_t rangeStart = ranges[i].start; + addr_t rangeEnd = rangeStart + ranges[i].size; + + if (start <= rangeStart) { + if (end <= rangeStart) { + // no intersection + } else if (end >= rangeEnd) { + // remove the complete range + remove_range_index(ranges, numRanges, i); + i--; + } else { + // remove the head of the range + ranges[i].start = end; + ranges[i].size = rangeEnd - end; + } + } else if (end >= rangeEnd) { + if (start < rangeEnd) { + // remove the tail + ranges[i].size = start - rangeStart; + } // else: no intersection + } else { + // rangeStart < start < end < rangeEnd + // The ugly case: We have to remove something from the middle of + // the range. We keep the head of the range and insert its tail + // as a new range. + ranges[i].size = start - rangeStart; + return insert_address_range(ranges, _numRanges, maxRanges, + end, rangeEnd - end); + } + } + + *_numRanges = numRanges; + return B_OK; } +status_t +insert_physical_memory_range(addr_t start, uint32 size) +{ + return insert_address_range(gKernelArgs.physical_memory_range, + &gKernelArgs.num_physical_memory_ranges, MAX_PHYSICAL_MEMORY_RANGE, + start, size); +} + + +status_t +insert_physical_allocated_range(addr_t start, uint32 size) +{ + return insert_address_range(gKernelArgs.physical_allocated_range, + &gKernelArgs.num_physical_allocated_ranges, MAX_PHYSICAL_ALLOCATED_RANGE, + start, size); +} + + +status_t +insert_virtual_allocated_range(addr_t start, uint32 size) +{ + return insert_address_range(gKernelArgs.virtual_allocated_range, + &gKernelArgs.num_virtual_allocated_ranges, MAX_VIRTUAL_ALLOCATED_RANGE, + start, size); +} + + +// #pragma mark - kernel_args allocations + + /** This function can be used to allocate memory that is going * to be passed over to the kernel. For example, the preloaded_image * structures are allocated this way. diff --git a/src/system/boot/platform/bios_ia32/mmu.cpp b/src/system/boot/platform/bios_ia32/mmu.cpp index f9ad031c7c..77ff574449 100644 --- a/src/system/boot/platform/bios_ia32/mmu.cpp +++ b/src/system/boot/platform/bios_ia32/mmu.cpp @@ -9,7 +9,6 @@ #include "mmu.h" #include "bios.h" -#include #include #include #include @@ -18,6 +17,8 @@ #include #include +#include + #include @@ -279,8 +280,9 @@ init_page_directory(void) gKernelArgs.arch_args.phys_pgdir = (uint32)sPageDirectory; // clear out the pgdir - for (int32 i = 0; i < 1024; i++) + for (int32 i = 0; i < 1024; i++) { sPageDirectory[i] = 0; + } // Identity map the first 8 MB of memory so that their // physical and virtual address are the same. @@ -553,41 +555,39 @@ mmu_init(void) // figure out the memory map if (extMemoryCount > 0) { - uint32 i; - gKernelArgs.num_physical_memory_ranges = 0; - for (i = 0; i < extMemoryCount; i++) { + for (uint32 i = 0; i < extMemoryCount; i++) { + // Type 1 is available memory if (extMemoryBlock[i].type == 1) { - // round everything up to page boundaries, exclusive of pages it partially occupies + // round everything up to page boundaries, exclusive of pages + // it partially occupies extMemoryBlock[i].length -= (extMemoryBlock[i].base_addr % B_PAGE_SIZE) ? (B_PAGE_SIZE - (extMemoryBlock[i].base_addr % B_PAGE_SIZE)) : 0; extMemoryBlock[i].base_addr = ROUNDUP(extMemoryBlock[i].base_addr, B_PAGE_SIZE); extMemoryBlock[i].length = ROUNDOWN(extMemoryBlock[i].length, B_PAGE_SIZE); - // this is mem we can use - if (gKernelArgs.num_physical_memory_ranges == 0) { - gKernelArgs.physical_memory_range[0].start = (addr_t)extMemoryBlock[i].base_addr; - gKernelArgs.physical_memory_range[0].size = (addr_t)extMemoryBlock[i].length; - gKernelArgs.num_physical_memory_ranges++; - } else { - // we might have to extend the previous hole - addr_t previous_end = gKernelArgs.physical_memory_range[gKernelArgs.num_physical_memory_ranges - 1].start - + gKernelArgs.physical_memory_range[gKernelArgs.num_physical_memory_ranges - 1].size; + 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 (previous_end <= extMemoryBlock[i].base_addr - && ((extMemoryBlock[i].base_addr - previous_end) < 0x100000)) { - // extend the previous buffer - gKernelArgs.physical_memory_range[gKernelArgs.num_physical_memory_ranges - 1].size += - (extMemoryBlock[i].base_addr - previous_end) + - extMemoryBlock[i].length; - - // mark the gap between the two allocated ranges in use - gKernelArgs.physical_allocated_range[gKernelArgs.num_physical_allocated_ranges].start = previous_end; - gKernelArgs.physical_allocated_range[gKernelArgs.num_physical_allocated_ranges].size = extMemoryBlock[i].base_addr - previous_end; - gKernelArgs.num_physical_allocated_ranges++; + // 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); } } } else {