* Enlarged maximum kernel size to 2 MB - this is the code the boot loader's

MMU code reserves for the kernel, and we hit that limit recently with the
  addition of the boot splash code.
* This fixes the boot crash as triggered by Stippi's recent changes to the
  splash image.
* Cleanup (doxygen comments, line length).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24805 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-04-05 10:16:49 +00:00
parent b04afa2413
commit 355914a2cd
+110 -84
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2007, Axel Dörfler, [email protected]. * Copyright 2004-2008, Axel Dörfler, [email protected].
* Based on code written by Travis Geiselbrecht for NewOS. * Based on code written by Travis Geiselbrecht for NewOS.
* *
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
@@ -22,24 +22,26 @@
#include <string.h> #include <string.h>
/** The (physical) memory layout of the boot loader is currently as follows: /*! The (physical) memory layout of the boot loader is currently as follows:
* 0x0500 - 0x10000 protected mode stack 0x0500 - 0x10000 protected mode stack
* 0x0500 - 0x09000 real mode stack 0x0500 - 0x09000 real mode stack
* 0x10000 - ? code (up to ~500 kB) 0x10000 - ? code (up to ~500 kB)
* 0x90000 1st temporary page table (identity maps 0-4 MB) 0x90000 1st temporary page table (identity maps 0-4 MB)
* 0x91000 2nd (4-8 MB) 0x91000 2nd (4-8 MB)
* 0x92000 - 0x92000 further page tables 0x92000 - 0x92000 further page tables
* 0x9e000 - 0xa0000 SMP trampoline code 0x9e000 - 0xa0000 SMP trampoline code
* [0xa0000 - 0x100000 BIOS/ROM/reserved area] [0xa0000 - 0x100000 BIOS/ROM/reserved area]
* 0x100000 page directory 0x100000 page directory
* ... boot loader heap (32 kB) ... boot loader heap (32 kB)
* ... free physical memory ... free physical memory
*
* The first 8 MB are identity mapped (0x0 - 0x0800000); paging is turned The first 8 MB are identity mapped (0x0 - 0x0800000); paging is turned
* on. The kernel is mapped at 0x80000000, all other stuff mapped by the on. The kernel is mapped at 0x80000000, all other stuff mapped by the
* loader (kernel args, modules, driver settings, ...) comes after loader (kernel args, modules, driver settings, ...) comes after
* 0x81000000 which means that there is currently only 1 MB reserved for 0x80020000 which means that there is currently only 2 MB reserved for
* the kernel itself (see kMaxKernelSize). the kernel itself (see kMaxKernelSize).
The layout in PXE mode differs a bit from this, see definitions below.
*/ */
//#define TRACE_MMU //#define TRACE_MMU
@@ -61,14 +63,15 @@ struct extended_memory {
uint32 type; uint32 type;
}; };
#ifdef _PXE_ENV
static const uint32 kDefaultPageTableFlags = 0x07; // present, user, R/W static const uint32 kDefaultPageTableFlags = 0x07; // present, user, R/W
static const size_t kMaxKernelSize = 0x100000; // 1 MB for the kernel static const size_t kMaxKernelSize = 0x200000; // 2 MB for the kernel
// working page directory and page table // working page directory and page table
static uint32 *sPageDirectory = 0; static uint32 *sPageDirectory = 0;
#ifdef _PXE_ENV
static addr_t sNextPhysicalAddress = 0x112000; static addr_t sNextPhysicalAddress = 0x112000;
static addr_t sNextVirtualAddress = KERNEL_BASE + kMaxKernelSize; static addr_t sNextVirtualAddress = KERNEL_BASE + kMaxKernelSize;
static addr_t sMaxVirtualAddress = KERNEL_BASE + 0x400000; static addr_t sMaxVirtualAddress = KERNEL_BASE + 0x400000;
@@ -79,12 +82,6 @@ static const uint32 kPageTableRegionEnd = 0x8b000;
#else #else
static const uint32 kDefaultPageTableFlags = 0x07; // present, user, R/W
static const size_t kMaxKernelSize = 0x100000; // 1 MB for the kernel
// working page directory and page table
static uint32 *sPageDirectory = 0;
static addr_t sNextPhysicalAddress = 0x100000; static addr_t sNextPhysicalAddress = 0x100000;
static addr_t sNextVirtualAddress = KERNEL_BASE + kMaxKernelSize; static addr_t sNextVirtualAddress = KERNEL_BASE + kMaxKernelSize;
static addr_t sMaxVirtualAddress = KERNEL_BASE + 0x400000; static addr_t sMaxVirtualAddress = KERNEL_BASE + 0x400000;
@@ -133,8 +130,8 @@ get_next_physical_page()
static uint32 * static uint32 *
get_next_page_table() get_next_page_table()
{ {
TRACE(("get_next_page_table, sNextPageTableAddress %p, kPageTableRegionEnd %p\n", TRACE(("get_next_page_table, sNextPageTableAddress %p, kPageTableRegionEnd "
sNextPageTableAddress, kPageTableRegionEnd)); "%p\n", sNextPageTableAddress, kPageTableRegionEnd));
addr_t address = sNextPageTableAddress; addr_t address = sNextPageTableAddress;
if (address >= kPageTableRegionEnd) if (address >= kPageTableRegionEnd)
@@ -145,8 +142,7 @@ get_next_page_table()
} }
/** Adds a new page table for the specified base address */ /*! Adds a new page table for the specified base address */
static void static void
add_page_table(addr_t base) add_page_table(addr_t base)
{ {
@@ -154,16 +150,20 @@ add_page_table(addr_t base)
// Get new page table and clear it out // Get new page table and clear it out
uint32 *pageTable = get_next_page_table(); uint32 *pageTable = get_next_page_table();
if (pageTable > (uint32 *)(8 * 1024 * 1024)) if (pageTable > (uint32 *)(8 * 1024 * 1024)) {
panic("tried to add page table beyond the indentity mapped 8 MB region\n"); panic("tried to add page table beyond the indentity mapped 8 MB "
"region\n");
}
gKernelArgs.arch_args.pgtables[gKernelArgs.arch_args.num_pgtables++] = (uint32)pageTable; gKernelArgs.arch_args.pgtables[gKernelArgs.arch_args.num_pgtables++]
= (uint32)pageTable;
for (int32 i = 0; i < 1024; i++) for (int32 i = 0; i < 1024; i++)
pageTable[i] = 0; pageTable[i] = 0;
// put the new page table into the page directory // put the new page table into the page directory
sPageDirectory[base/(4*1024*1024)] = (uint32)pageTable | kDefaultPageTableFlags; sPageDirectory[base / (4 * 1024 * 1024)]
= (uint32)pageTable | kDefaultPageTableFlags;
} }
@@ -172,8 +172,10 @@ unmap_page(addr_t virtualAddress)
{ {
TRACE(("unmap_page(virtualAddress = %p)\n", (void *)virtualAddress)); TRACE(("unmap_page(virtualAddress = %p)\n", (void *)virtualAddress));
if (virtualAddress < KERNEL_BASE) if (virtualAddress < KERNEL_BASE) {
panic("unmap_page: asked to unmap invalid page %p!\n", (void *)virtualAddress); panic("unmap_page: asked to unmap invalid page %p!\n",
(void *)virtualAddress);
}
// unmap the page from the correct page table // unmap the page from the correct page table
uint32 *pageTable = (uint32 *)(sPageDirectory[virtualAddress uint32 *pageTable = (uint32 *)(sPageDirectory[virtualAddress
@@ -184,19 +186,20 @@ unmap_page(addr_t virtualAddress)
} }
/** Creates an entry to map the specified virtualAddress to the given /*! Creates an entry to map the specified virtualAddress to the given
* physicalAddress. physicalAddress.
* If the mapping goes beyond the current page table, it will allocate If the mapping goes beyond the current page table, it will allocate
* a new one. If it cannot map the requested page, it panics. a new one. If it cannot map the requested page, it panics.
*/ */
static void static void
map_page(addr_t virtualAddress, addr_t physicalAddress, uint32 flags) map_page(addr_t virtualAddress, addr_t physicalAddress, uint32 flags)
{ {
TRACE(("map_page: vaddr 0x%lx, paddr 0x%lx\n", virtualAddress, physicalAddress)); TRACE(("map_page: vaddr 0x%lx, paddr 0x%lx\n", virtualAddress, physicalAddress));
if (virtualAddress < KERNEL_BASE) if (virtualAddress < KERNEL_BASE) {
panic("map_page: asked to map invalid page %p!\n", (void *)virtualAddress); panic("map_page: asked to map invalid page %p!\n",
(void *)virtualAddress);
}
if (virtualAddress >= sMaxVirtualAddress) { if (virtualAddress >= sMaxVirtualAddress) {
// we need to add a new page table // we need to add a new page table
@@ -204,8 +207,10 @@ map_page(addr_t virtualAddress, addr_t physicalAddress, uint32 flags)
add_page_table(sMaxVirtualAddress); add_page_table(sMaxVirtualAddress);
sMaxVirtualAddress += B_PAGE_SIZE * 1024; sMaxVirtualAddress += B_PAGE_SIZE * 1024;
if (virtualAddress >= sMaxVirtualAddress) if (virtualAddress >= sMaxVirtualAddress) {
panic("map_page: asked to map a page to %p\n", (void *)virtualAddress); panic("map_page: asked to map a page to %p\n",
(void *)virtualAddress);
}
} }
physicalAddress &= ~(B_PAGE_SIZE - 1); physicalAddress &= ~(B_PAGE_SIZE - 1);
@@ -215,8 +220,8 @@ map_page(addr_t virtualAddress, addr_t physicalAddress, uint32 flags)
/ (B_PAGE_SIZE * 1024)] & 0xfffff000); / (B_PAGE_SIZE * 1024)] & 0xfffff000);
uint32 tableEntry = (virtualAddress % (B_PAGE_SIZE * 1024)) / B_PAGE_SIZE; uint32 tableEntry = (virtualAddress % (B_PAGE_SIZE * 1024)) / B_PAGE_SIZE;
TRACE(("map_page: inserting pageTable %p, tableEntry %ld, physicalAddress %p\n", TRACE(("map_page: inserting pageTable %p, tableEntry %ld, physicalAddress "
pageTable, tableEntry, physicalAddress)); "%p\n", pageTable, tableEntry, physicalAddress));
pageTable[tableEntry] = physicalAddress | flags; pageTable[tableEntry] = physicalAddress | flags;
@@ -351,8 +356,8 @@ mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags)
extern "C" void * extern "C" void *
mmu_allocate(void *virtualAddress, size_t size) mmu_allocate(void *virtualAddress, size_t size)
{ {
TRACE(("mmu_allocate: requested vaddr: %p, next free vaddr: 0x%lx, size: %ld\n", TRACE(("mmu_allocate: requested vaddr: %p, next free vaddr: 0x%lx, size: "
virtualAddress, sNextVirtualAddress, size)); "%ld\n", virtualAddress, sNextVirtualAddress, size));
size = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE; size = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE;
// get number of pages to map // get number of pages to map
@@ -360,13 +365,14 @@ mmu_allocate(void *virtualAddress, size_t size)
if (virtualAddress != NULL) { if (virtualAddress != NULL) {
// This special path is almost only useful for loading the // This special path is almost only useful for loading the
// kernel into memory; it will only allow you to map the // kernel into memory; it will only allow you to map the
// 1 MB following the kernel base address. // 'kMaxKernelSize' bytes following the kernel base address.
// Also, it won't check for already mapped addresses, so // Also, it won't check for already mapped addresses, so
// you better know why you are here :) // you better know why you are here :)
addr_t address = (addr_t)virtualAddress; addr_t address = (addr_t)virtualAddress;
// is the address within the valid range? // is the address within the valid range?
if (address < KERNEL_BASE || address + size >= KERNEL_BASE + kMaxKernelSize) if (address < KERNEL_BASE
|| address + size >= KERNEL_BASE + kMaxKernelSize)
return NULL; return NULL;
for (uint32 i = 0; i < size; i++) { for (uint32 i = 0; i < size; i++) {
@@ -380,18 +386,18 @@ mmu_allocate(void *virtualAddress, size_t size)
void *address = (void *)sNextVirtualAddress; void *address = (void *)sNextVirtualAddress;
for (uint32 i = 0; i < size; i++) { for (uint32 i = 0; i < size; i++) {
map_page(get_next_virtual_page(), get_next_physical_page(), kDefaultPageFlags); map_page(get_next_virtual_page(), get_next_physical_page(),
kDefaultPageFlags);
} }
return address; return address;
} }
/** 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.
*/ */
extern "C" void extern "C" void
mmu_free(void *virtualAddress, size_t size) mmu_free(void *virtualAddress, size_t size)
{ {
@@ -421,11 +427,10 @@ mmu_free(void *virtualAddress, size_t size)
} }
/** Sets up the final and kernel accessible GDT and IDT tables. /*! Sets up the final and kernel accessible GDT and IDT tables.
* BIOS calls won't work any longer after this function has BIOS calls won't work any longer after this function has
* been called. been called.
*/ */
extern "C" void extern "C" void
mmu_init_for_kernel(void) mmu_init_for_kernel(void)
{ {
@@ -511,17 +516,23 @@ mmu_init_for_kernel(void)
} }
// save the memory we've physically allocated // save the memory we've physically allocated
gKernelArgs.physical_allocated_range[0].size = sNextPhysicalAddress - gKernelArgs.physical_allocated_range[0].start; gKernelArgs.physical_allocated_range[0].size
= sNextPhysicalAddress - gKernelArgs.physical_allocated_range[0].start;
// save the memory we've virtually allocated (for the kernel and other stuff) // Save the memory we've virtually allocated (for the kernel and other
// stuff)
gKernelArgs.virtual_allocated_range[0].start = KERNEL_BASE; gKernelArgs.virtual_allocated_range[0].start = KERNEL_BASE;
gKernelArgs.virtual_allocated_range[0].size = sNextVirtualAddress - KERNEL_BASE; gKernelArgs.virtual_allocated_range[0].size
= sNextVirtualAddress - KERNEL_BASE;
gKernelArgs.num_virtual_allocated_ranges = 1; gKernelArgs.num_virtual_allocated_ranges = 1;
// sort the address ranges // sort the address ranges
sort_addr_range(gKernelArgs.physical_memory_range, gKernelArgs.num_physical_memory_ranges); sort_addr_range(gKernelArgs.physical_memory_range,
sort_addr_range(gKernelArgs.physical_allocated_range, gKernelArgs.num_physical_allocated_ranges); gKernelArgs.num_physical_memory_ranges);
sort_addr_range(gKernelArgs.virtual_allocated_range, gKernelArgs.num_virtual_allocated_ranges); sort_addr_range(gKernelArgs.physical_allocated_range,
gKernelArgs.num_physical_allocated_ranges);
sort_addr_range(gKernelArgs.virtual_allocated_range,
gKernelArgs.num_virtual_allocated_ranges);
#ifdef TRACE_MMU #ifdef TRACE_MMU
{ {
@@ -566,10 +577,12 @@ mmu_init(void)
// also map it on the next vpage // also map it on the next vpage
gKernelArgs.arch_args.vir_pgdir = get_next_virtual_page(); gKernelArgs.arch_args.vir_pgdir = get_next_virtual_page();
map_page(gKernelArgs.arch_args.vir_pgdir, (uint32)sPageDirectory, kDefaultPageFlags); map_page(gKernelArgs.arch_args.vir_pgdir, (uint32)sPageDirectory,
kDefaultPageFlags);
// map in a kernel stack // map in a kernel stack
gKernelArgs.cpu_kstack[0].start = (addr_t)mmu_allocate(NULL, KERNEL_STACK_SIZE); gKernelArgs.cpu_kstack[0].start = (addr_t)mmu_allocate(NULL,
KERNEL_STACK_SIZE);
gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE; gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE;
TRACE(("kernel stack at 0x%lx to 0x%lx\n", gKernelArgs.cpu_kstack[0].start, TRACE(("kernel stack at 0x%lx to 0x%lx\n", gKernelArgs.cpu_kstack[0].start,
@@ -587,16 +600,24 @@ mmu_init(void)
if (extMemoryBlock[i].type == 1) { if (extMemoryBlock[i].type == 1) {
// round everything up to page boundaries, exclusive of pages // round everything up to page boundaries, exclusive of pages
// it partially occupies // it partially occupies
extMemoryBlock[i].length -= (extMemoryBlock[i].base_addr % B_PAGE_SIZE) if ((extMemoryBlock[i].base_addr % B_PAGE_SIZE) != 0) {
? (B_PAGE_SIZE - (extMemoryBlock[i].base_addr % B_PAGE_SIZE)) : 0; extMemoryBlock[i].length -= B_PAGE_SIZE
extMemoryBlock[i].base_addr = ROUNDUP(extMemoryBlock[i].base_addr, B_PAGE_SIZE); - extMemoryBlock[i].base_addr % B_PAGE_SIZE;
extMemoryBlock[i].length = ROUNDOWN(extMemoryBlock[i].length, 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);
// we ignore all memory beyond 4 GB // we ignore all memory beyond 4 GB
if (extMemoryBlock[i].base_addr > 0xffffffffULL) if (extMemoryBlock[i].base_addr > 0xffffffffULL)
continue; continue;
if (extMemoryBlock[i].base_addr + extMemoryBlock[i].length > 0xffffffffULL)
extMemoryBlock[i].length = 0x100000000ULL - extMemoryBlock[i].base_addr; if (extMemoryBlock[i].base_addr + extMemoryBlock[i].length
> 0xffffffffULL) {
extMemoryBlock[i].length
= 0x100000000ULL - extMemoryBlock[i].base_addr;
}
if (gKernelArgs.num_physical_memory_ranges > 0) { if (gKernelArgs.num_physical_memory_ranges > 0) {
// we might want to extend a previous hole // we might want to extend a previous hole
@@ -606,14 +627,16 @@ mmu_init(void)
gKernelArgs.num_physical_memory_ranges - 1].size; gKernelArgs.num_physical_memory_ranges - 1].size;
addr_t holeSize = extMemoryBlock[i].base_addr - previousEnd; addr_t holeSize = extMemoryBlock[i].base_addr - previousEnd;
// if the hole is smaller than 1 MB, we try to mark the memory // If the hole is smaller than 1 MB, we try to mark the
// as allocated and extend the previous memory range // memory as allocated and extend the previous memory range
if (previousEnd <= extMemoryBlock[i].base_addr if (previousEnd <= extMemoryBlock[i].base_addr
&& holeSize < 0x100000 && holeSize < 0x100000
&& insert_physical_allocated_range(previousEnd, && insert_physical_allocated_range(previousEnd,
extMemoryBlock[i].base_addr - previousEnd) == B_OK) { extMemoryBlock[i].base_addr - previousEnd)
== B_OK) {
gKernelArgs.physical_memory_range[ gKernelArgs.physical_memory_range[
gKernelArgs.num_physical_memory_ranges - 1].size += holeSize; gKernelArgs.num_physical_memory_ranges - 1].size
+= holeSize;
} }
} }
@@ -622,19 +645,22 @@ mmu_init(void)
} }
} }
} else { } else {
// ToDo: for now! // TODO: for now!
dprintf("No extended memory block - using 32 MB (fix me!)\n"); dprintf("No extended memory block - using 32 MB (fix me!)\n");
uint32 memSize = 32 * 1024 * 1024; uint32 memSize = 32 * 1024 * 1024;
// we dont have an extended map, assume memory is contiguously mapped at 0x0 // We dont have an extended map, assume memory is contiguously mapped
// at 0x0
gKernelArgs.physical_memory_range[0].start = 0; gKernelArgs.physical_memory_range[0].start = 0;
gKernelArgs.physical_memory_range[0].size = memSize; gKernelArgs.physical_memory_range[0].size = memSize;
gKernelArgs.num_physical_memory_ranges = 1; gKernelArgs.num_physical_memory_ranges = 1;
// mark the bios area allocated // mark the bios area allocated
gKernelArgs.physical_allocated_range[gKernelArgs.num_physical_allocated_ranges].start = 0x9f000; // 640k - 1 page uint32 biosRange = gKernelArgs.num_physical_allocated_ranges++;
gKernelArgs.physical_allocated_range[gKernelArgs.num_physical_allocated_ranges].size = 0x61000;
gKernelArgs.num_physical_allocated_ranges++; gKernelArgs.physical_allocated_range[biosRange].start = 0x9f000;
// 640k - 1 page
gKernelArgs.physical_allocated_range[biosRange].size = 0x61000;
} }
gKernelArgs.arch_args.page_hole = 0xffc00000; gKernelArgs.arch_args.page_hole = 0xffc00000;