* Changed/fixed mmu_map_physical_memory() semantics: It does now always

allocate all pages the given range intersects with. When not page aligned
  it could fail to allocate the last page.
* mmu_free():
  - Adjusted semantics to be compatible with mmu_map_physical_memory().
  - The validity check was broken, because page number and addresses were
    mixed, and because KERNEL_BASE + kMaxKernelSize doesn't mark the end of
    the allocated virtual ranges.
  - The final check against sNextVirtualAddress was broken.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34947 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2010-01-08 15:58:08 +00:00
parent 7aa1ecffe5
commit 7f051b5710
+15 -6
View File
@@ -361,6 +361,12 @@ init_page_directory(void)
// #pragma mark - // #pragma mark -
/*!
Neither \a virtualAddress nor \a size need to be aligned, but the function
will map all pages the range intersects with.
If physicalAddress is not page-aligned, the returned virtual address will
have the same "misalignment".
*/
extern "C" addr_t extern "C" addr_t
mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags) mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags)
{ {
@@ -368,6 +374,7 @@ mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags)
addr_t pageOffset = physicalAddress & (B_PAGE_SIZE - 1); addr_t pageOffset = physicalAddress & (B_PAGE_SIZE - 1);
physicalAddress -= pageOffset; physicalAddress -= pageOffset;
size += pageOffset;
for (addr_t offset = 0; offset < size; offset += B_PAGE_SIZE) { for (addr_t offset = 0; offset < size; offset += B_PAGE_SIZE) {
map_page(get_next_virtual_page(), physicalAddress + offset, flags); map_page(get_next_virtual_page(), physicalAddress + offset, flags);
@@ -421,6 +428,8 @@ mmu_allocate(void *virtualAddress, size_t size)
/*! This will unmap the allocated chunk of memory from the virtual /*! This will unmap the allocated chunk of memory from the virtual
address space. It might not actually free memory (as its implementation address space. It might not actually free memory (as its implementation
is very simple), but it might. is very simple), but it might.
Neither \a virtualAddress nor \a size need to be aligned, but the function
will unmap all pages the range intersects with.
*/ */
extern "C" void extern "C" void
mmu_free(void *virtualAddress, size_t size) mmu_free(void *virtualAddress, size_t size)
@@ -428,23 +437,23 @@ mmu_free(void *virtualAddress, size_t size)
TRACE(("mmu_free(virtualAddress = %p, size: %ld)\n", virtualAddress, size)); TRACE(("mmu_free(virtualAddress = %p, size: %ld)\n", virtualAddress, size));
addr_t address = (addr_t)virtualAddress; addr_t address = (addr_t)virtualAddress;
size = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE; addr_t pageOffset = address % B_PAGE_SIZE;
// get number of pages to map address -= pageOffset;
size = (size + pageOffset + B_PAGE_SIZE - 1) / B_PAGE_SIZE * B_PAGE_SIZE;
// is the address within the valid range? // is the address within the valid range?
if (address < KERNEL_BASE if (address < KERNEL_BASE || address + size > sNextVirtualAddress) {
|| address + size >= KERNEL_BASE + kMaxKernelSize) {
panic("mmu_free: asked to unmap out of range region (%p, size %lx)\n", panic("mmu_free: asked to unmap out of range region (%p, size %lx)\n",
(void *)address, size); (void *)address, size);
} }
// unmap all pages within the range // unmap all pages within the range
for (uint32 i = 0; i < size; i++) { for (size_t i = 0; i < size; i += B_PAGE_SIZE) {
unmap_page(address); unmap_page(address);
address += B_PAGE_SIZE; address += B_PAGE_SIZE;
} }
if (address == sNextVirtualAddress) { if (address + size == sNextVirtualAddress) {
// we can actually reuse the virtual address space // we can actually reuse the virtual address space
sNextVirtualAddress -= size; sNextVirtualAddress -= size;
} }