* 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
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2004-2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
** Distributed under the terms of the Haiku License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef KERNEL_BOOT_ADDR_RANGE_H
|
#ifndef KERNEL_BOOT_ADDR_RANGE_H
|
||||||
#define KERNEL_BOOT_ADDR_RANGE_H
|
#define KERNEL_BOOT_ADDR_RANGE_H
|
||||||
|
|
||||||
@@ -14,10 +14,22 @@ typedef struct addr_range {
|
|||||||
addr_t size;
|
addr_t size;
|
||||||
} addr_range;
|
} addr_range;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
status_t insert_address_range(addr_range *ranges, uint32 *_numRanges, uint32 maxRanges,
|
status_t insert_address_range(addr_range *ranges, uint32 *_numRanges, uint32 maxRanges,
|
||||||
addr_t start, uint32 size);
|
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 */
|
#endif /* KERNEL_BOOT_ADDR_RANGE_H */
|
||||||
|
|||||||
@@ -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
|
/** Inserts the specified (start, size) pair (aka range) in the
|
||||||
* addr_range array.
|
* addr_range array.
|
||||||
* It will extend existing ranges in order to have as little
|
* 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
|
extern "C" status_t
|
||||||
add_kernel_args_range(void *start, uint32 size)
|
remove_address_range(addr_range *ranges, uint32 *_numRanges, uint32 maxRanges,
|
||||||
|
addr_t start, uint32 size)
|
||||||
{
|
{
|
||||||
return insert_address_range(gKernelArgs.kernel_args_range,
|
uint32 numRanges = *_numRanges;
|
||||||
&gKernelArgs.num_kernel_args_ranges, MAX_KERNEL_ARGS_RANGE,
|
|
||||||
(addr_t)start, size);
|
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
|
/** This function can be used to allocate memory that is going
|
||||||
* to be passed over to the kernel. For example, the preloaded_image
|
* to be passed over to the kernel. For example, the preloaded_image
|
||||||
* structures are allocated this way.
|
* structures are allocated this way.
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
#include "bios.h"
|
#include "bios.h"
|
||||||
|
|
||||||
#include <OS.h>
|
|
||||||
#include <boot/platform.h>
|
#include <boot/platform.h>
|
||||||
#include <boot/stdio.h>
|
#include <boot/stdio.h>
|
||||||
#include <boot/kernel_args.h>
|
#include <boot/kernel_args.h>
|
||||||
@@ -18,6 +17,8 @@
|
|||||||
#include <arch_kernel.h>
|
#include <arch_kernel.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -279,8 +280,9 @@ init_page_directory(void)
|
|||||||
gKernelArgs.arch_args.phys_pgdir = (uint32)sPageDirectory;
|
gKernelArgs.arch_args.phys_pgdir = (uint32)sPageDirectory;
|
||||||
|
|
||||||
// clear out the pgdir
|
// clear out the pgdir
|
||||||
for (int32 i = 0; i < 1024; i++)
|
for (int32 i = 0; i < 1024; i++) {
|
||||||
sPageDirectory[i] = 0;
|
sPageDirectory[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Identity map the first 8 MB of memory so that their
|
// Identity map the first 8 MB of memory so that their
|
||||||
// physical and virtual address are the same.
|
// physical and virtual address are the same.
|
||||||
@@ -553,41 +555,39 @@ mmu_init(void)
|
|||||||
|
|
||||||
// figure out the memory map
|
// figure out the memory map
|
||||||
if (extMemoryCount > 0) {
|
if (extMemoryCount > 0) {
|
||||||
uint32 i;
|
|
||||||
|
|
||||||
gKernelArgs.num_physical_memory_ranges = 0;
|
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) {
|
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)
|
extMemoryBlock[i].length -= (extMemoryBlock[i].base_addr % B_PAGE_SIZE)
|
||||||
? (B_PAGE_SIZE - (extMemoryBlock[i].base_addr % B_PAGE_SIZE)) : 0;
|
? (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].base_addr = ROUNDUP(extMemoryBlock[i].base_addr, B_PAGE_SIZE);
|
||||||
extMemoryBlock[i].length = ROUNDOWN(extMemoryBlock[i].length, 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) {
|
||||||
if (gKernelArgs.num_physical_memory_ranges == 0) {
|
// we might want to extend a previous hole
|
||||||
gKernelArgs.physical_memory_range[0].start = (addr_t)extMemoryBlock[i].base_addr;
|
addr_t previousEnd = gKernelArgs.physical_memory_range[
|
||||||
gKernelArgs.physical_memory_range[0].size = (addr_t)extMemoryBlock[i].length;
|
gKernelArgs.num_physical_memory_ranges - 1].start
|
||||||
gKernelArgs.num_physical_memory_ranges++;
|
+ gKernelArgs.physical_memory_range[
|
||||||
} else {
|
gKernelArgs.num_physical_memory_ranges - 1].size;
|
||||||
// we might have to extend the previous hole
|
addr_t holeSize = extMemoryBlock[i].base_addr - previousEnd;
|
||||||
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 (previous_end <= extMemoryBlock[i].base_addr
|
// if the hole is smaller than 1 MB, we try to mark the memory
|
||||||
&& ((extMemoryBlock[i].base_addr - previous_end) < 0x100000)) {
|
// as allocated and extend the previous memory range
|
||||||
// extend the previous buffer
|
if (previousEnd <= extMemoryBlock[i].base_addr
|
||||||
gKernelArgs.physical_memory_range[gKernelArgs.num_physical_memory_ranges - 1].size +=
|
&& holeSize < 0x100000
|
||||||
(extMemoryBlock[i].base_addr - previous_end) +
|
&& insert_physical_allocated_range(previousEnd,
|
||||||
extMemoryBlock[i].length;
|
extMemoryBlock[i].base_addr - previousEnd) == B_OK) {
|
||||||
|
gKernelArgs.physical_memory_range[
|
||||||
// mark the gap between the two allocated ranges in use
|
gKernelArgs.num_physical_memory_ranges - 1].size += holeSize;
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insert_physical_memory_range(extMemoryBlock[i].base_addr,
|
||||||
|
extMemoryBlock[i].length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user