ARM: cleanup of bootloader memory mapping

* Removes default mapping of a portion of the RAM (will be done
  as needed)
* Passes on the page directory area to kernel, so on early vm init
  the kernel can use the area for pagetable allocation.
* Leaves it to the platform to pass in physical memory range(s). This
  will ultimately come from FDT.
* Fix long standing issue with allocation of the heap, potentially
  causing other part of the bootloader to overwrite the heap.
* Implements pagetable allocator in kernel for early vm mapping.

This fixes the first PANIC seen, we now just get the same one later
on when the VM is up... more to come...
This commit is contained in:
Ithamar R. Adema
2014-09-07 20:56:15 +02:00
parent 3e450daa1c
commit eea45d0a32
5 changed files with 46 additions and 84 deletions
@@ -20,6 +20,7 @@ typedef struct {
// architecture specific // architecture specific
uint32 phys_pgdir; uint32 phys_pgdir;
uint32 vir_pgdir; uint32 vir_pgdir;
uint32 next_pagetable;
} arch_kernel_args; } arch_kernel_args;
#endif /* KERNEL_ARCH_ARM_KERNEL_ARGS_H */ #endif /* KERNEL_ARCH_ARM_KERNEL_ARGS_H */
+26 -81
View File
@@ -61,10 +61,7 @@ TODO:
// 8 MB for the kernel, kernel args, modules, driver settings, ... // 8 MB for the kernel, kernel args, modules, driver settings, ...
static const size_t kMaxKernelSize = 0x800000; static const size_t kMaxKernelSize = 0x800000;
// Base address for loader // Start and end of ourselfs (from ld script)
static const size_t kLoaderBaseAddress = KERNEL_LOAD_BASE + kMaxKernelSize;
// Start and end of ourselfs
extern int _start, _end; extern int _start, _end;
/* /*
@@ -95,18 +92,6 @@ static struct memblock LOADER_MEMORYMAP[] = {
KERNEL_LOAD_BASE + kMaxKernelSize - 1, KERNEL_LOAD_BASE + kMaxKernelSize - 1,
ARM_MMU_L2_FLAG_C, ARM_MMU_L2_FLAG_C,
}, },
{
"RAM_pt", // Page Table 1MB
kLoaderBaseAddress + 0x100000,
kLoaderBaseAddress + 0x1FFFFF,
ARM_MMU_L2_FLAG_C,
},
{
"RAM_free", // 16MB free RAM (more but we don't map it automaticaly)
kLoaderBaseAddress + 0x0200000,
kLoaderBaseAddress + 0x11FFFFF,
ARM_MMU_L2_FLAG_C,
},
#ifdef FB_BASE #ifdef FB_BASE
{ {
@@ -127,7 +112,7 @@ static addr_t sNextVirtualAddress = 0;
static addr_t sNextPageTableAddress = 0; static addr_t sNextPageTableAddress = 0;
//the page directory is in front of the pagetable //the page directory is in front of the pagetable
static uint32 kPageTableRegionEnd = 0; static uint32 sPageTableRegionEnd = 0;
static uint32 sSmallPageType = ARM_MMU_L2_TYPE_SMALLEXT; static uint32 sSmallPageType = ARM_MMU_L2_TYPE_SMALLEXT;
@@ -137,16 +122,6 @@ static uint32 *sPageDirectory = 0 ;
//some arm processors //some arm processors
static addr_t
get_next_virtual_address(size_t size)
{
addr_t address = sNextVirtualAddress;
sNextVirtualAddress += size;
return address;
}
static addr_t static addr_t
get_next_virtual_address_aligned(size_t size, uint32 mask) get_next_virtual_address_aligned(size_t size, uint32 mask)
{ {
@@ -157,16 +132,6 @@ get_next_virtual_address_aligned(size_t size, uint32 mask)
} }
static addr_t
get_next_physical_address(size_t size)
{
addr_t address = sNextPhysicalAddress;
sNextPhysicalAddress += size;
return address;
}
static addr_t static addr_t
get_next_physical_address_aligned(size_t size, uint32 mask) get_next_physical_address_aligned(size_t size, uint32 mask)
{ {
@@ -246,8 +211,8 @@ static uint32 *
get_next_page_table(uint32 type) get_next_page_table(uint32 type)
{ {
TRACE(("get_next_page_table, sNextPageTableAddress 0x%" B_PRIxADDR TRACE(("get_next_page_table, sNextPageTableAddress 0x%" B_PRIxADDR
", kPageTableRegionEnd 0x%" B_PRIxADDR ", type 0x%" B_PRIx32 "\n", ", sPageTableRegionEnd 0x%" B_PRIxADDR ", type 0x%" B_PRIx32 "\n",
sNextPageTableAddress, kPageTableRegionEnd, type)); sNextPageTableAddress, sPageTableRegionEnd, type));
size_t size = 0; size_t size = 0;
size_t entryCount = 0; size_t entryCount = 0;
@@ -266,7 +231,7 @@ get_next_page_table(uint32 type)
} }
addr_t address = sNextPageTableAddress; addr_t address = sNextPageTableAddress;
if (address < kPageTableRegionEnd) if (address < sPageTableRegionEnd)
sNextPageTableAddress += size; sNextPageTableAddress += size;
else { else {
TRACE(("page table allocation outside of pagetable region!\n")); TRACE(("page table allocation outside of pagetable region!\n"));
@@ -337,7 +302,8 @@ init_page_directory()
{ {
TRACE(("init_page_directory\n")); TRACE(("init_page_directory\n"));
gKernelArgs.arch_args.phys_pgdir = (uint32)sPageDirectory; gKernelArgs.arch_args.phys_pgdir =
gKernelArgs.arch_args.vir_pgdir = (uint32)sPageDirectory;
// clear out the page directory // clear out the page directory
for (uint32 i = 0; i < ARM_MMU_L1_TABLE_ENTRY_COUNT; i++) for (uint32 i = 0; i < ARM_MMU_L1_TABLE_ENTRY_COUNT; i++)
@@ -346,6 +312,9 @@ init_page_directory()
// map ourselfs first... just to make sure // map ourselfs first... just to make sure
mmu_map_identity((addr_t)&_start, (addr_t)&_end, ARM_MMU_L2_FLAG_C); mmu_map_identity((addr_t)&_start, (addr_t)&_end, ARM_MMU_L2_FLAG_C);
// map our page directory region (TODO should not be identity mapped)
mmu_map_identity((addr_t)sPageDirectory, sPageTableRegionEnd, ARM_MMU_L2_FLAG_C);
for (uint32 i = 0; i < ARRAY_SIZE(LOADER_MEMORYMAP); i++) { for (uint32 i = 0; i < ARRAY_SIZE(LOADER_MEMORYMAP); i++) {
TRACE(("BLOCK: %s START: %lx END %lx\n", LOADER_MEMORYMAP[i].name, TRACE(("BLOCK: %s START: %lx END %lx\n", LOADER_MEMORYMAP[i].name,
@@ -358,10 +327,6 @@ init_page_directory()
LOADER_MEMORYMAP[i].flags); LOADER_MEMORYMAP[i].flags);
} }
// Map the page directory itself.
addr_t virtualPageDirectory = mmu_map_physical_memory(
(addr_t)sPageDirectory, ARM_MMU_L1_TABLE_SIZE, kDefaultPageFlags);
mmu_flush_TLB(); mmu_flush_TLB();
/* set up the translation table base */ /* set up the translation table base */
@@ -374,10 +339,6 @@ init_page_directory()
/* turn on the mmu */ /* turn on the mmu */
mmu_write_C1(mmu_read_C1() | 0x1); mmu_write_C1(mmu_read_C1() | 0x1);
// Use the mapped page directory from now on.
sPageDirectory = (uint32 *)virtualPageDirectory;
gKernelArgs.arch_args.vir_pgdir = virtualPageDirectory;
} }
@@ -547,18 +508,16 @@ mmu_init_for_kernel(void)
{ {
TRACE(("mmu_init_for_kernel\n")); TRACE(("mmu_init_for_kernel\n"));
// store next available pagetable in our pagedir mapping, for
// the kernel to use in early vm setup
gKernelArgs.arch_args.next_pagetable = sNextPageTableAddress - (addr_t)sPageDirectory;
// save the memory we've physically allocated // save the memory we've physically allocated
int index = gKernelArgs.num_physical_allocated_ranges; insert_physical_allocated_range((addr_t)sPageDirectory, sNextPhysicalAddress - (addr_t)sPageDirectory);
gKernelArgs.physical_allocated_range[index].start = SDRAM_BASE;
gKernelArgs.physical_allocated_range[index].size = sNextPhysicalAddress - SDRAM_BASE;
gKernelArgs.num_physical_allocated_ranges++;
// Save the memory we've virtually allocated (for the kernel and other // Save the memory we've virtually allocated (for the kernel and other
// stuff) // stuff)
gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE; insert_virtual_allocated_range(KERNEL_LOAD_BASE, sNextVirtualAddress - KERNEL_LOAD_BASE);
gKernelArgs.virtual_allocated_range[0].size
= sNextVirtualAddress - KERNEL_LOAD_BASE;
gKernelArgs.num_virtual_allocated_ranges = 1;
#ifdef TRACE_MEMORY_MAP #ifdef TRACE_MEMORY_MAP
{ {
@@ -601,32 +560,18 @@ mmu_init(void)
mmu_write_C1(mmu_read_C1() & ~((1 << 29) | (1 << 28) | (1 << 0))); mmu_write_C1(mmu_read_C1() & ~((1 << 29) | (1 << 28) | (1 << 0)));
// access flag disabled, TEX remap disabled, mmu disabled // access flag disabled, TEX remap disabled, mmu disabled
uint32 highestRAMAddress = SDRAM_BASE; // allocate page directory in memory after loader
sPageDirectory = (uint32 *)ROUNDUP((addr_t)&_end, 0x100000);
sNextPageTableAddress = (addr_t)sPageDirectory + ARM_MMU_L1_TABLE_SIZE;
sPageTableRegionEnd = (addr_t)sPageDirectory + 0x200000;
// calculate lowest RAM adress from MEMORYMAP // Mark start for dynamic allocation
for (uint32 i = 0; i < ARRAY_SIZE(LOADER_MEMORYMAP); i++) { sNextPhysicalAddress =
if (strcmp("RAM_free", LOADER_MEMORYMAP[i].name) == 0) { sNextVirtualAddress = sPageTableRegionEnd;
sNextPhysicalAddress = LOADER_MEMORYMAP[i].start;
sNextVirtualAddress = LOADER_MEMORYMAP[i].start;
}
if (strcmp("RAM_pt", LOADER_MEMORYMAP[i].name) == 0) { // mark allocated ranges, so they don't get overwritten
sNextPageTableAddress = LOADER_MEMORYMAP[i].start
+ ARM_MMU_L1_TABLE_SIZE;
kPageTableRegionEnd = LOADER_MEMORYMAP[i].end;
sPageDirectory = (uint32 *)LOADER_MEMORYMAP[i].start;
}
if (strncmp("RAM_", LOADER_MEMORYMAP[i].name, 4) == 0) {
if (LOADER_MEMORYMAP[i].end > highestRAMAddress)
highestRAMAddress = LOADER_MEMORYMAP[i].end;
}
}
insert_physical_memory_range(SDRAM_BASE, highestRAMAddress - SDRAM_BASE);
// mark ourselfs as allocated, so init_page_directory doesn't overwrite us
insert_physical_allocated_range((addr_t)&_start, (addr_t)&_end - (addr_t)&_start); insert_physical_allocated_range((addr_t)&_start, (addr_t)&_end - (addr_t)&_start);
insert_physical_allocated_range((addr_t)sPageDirectory, 0x200000);
init_page_directory(); init_page_directory();
@@ -678,7 +623,7 @@ platform_release_heap(struct stage2_args *args, void *base)
status_t status_t
platform_init_heap(struct stage2_args *args, void **_base, void **_top) platform_init_heap(struct stage2_args *args, void **_base, void **_top)
{ {
void *heap = (void *)get_next_physical_address(args->heap_size); void *heap = mmu_allocate(NULL, args->heap_size);
if (heap == NULL) if (heap == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -134,6 +134,10 @@ _start(void)
// Flick on "OK" led, use pre-mmu firmware base // Flick on "OK" led, use pre-mmu firmware base
gpio_write(gPeripheralBase + GPIO_BASE, 16, 0); gpio_write(gPeripheralBase + GPIO_BASE, 16, 0);
// specify available physical memory, using 128MB for now
// TODO: support CPU/GPU memory split options
insert_physical_memory_range(SDRAM_BASE, 128 * 1024 * 1024);
// Reserve memory for boot archive before switching on MMU // Reserve memory for boot archive before switching on MMU
insert_physical_allocated_range(BOOT_ARCHIVE_BASE, BOOT_ARCHIVE_SIZE); insert_physical_allocated_range(BOOT_ARCHIVE_BASE, BOOT_ARCHIVE_SIZE);
@@ -19,6 +19,7 @@
#include <arch/cpu.h> #include <arch/cpu.h>
#include <platform_arch.h> #include <platform_arch.h>
#include <platform/openfirmware/openfirmware.h> #include <platform/openfirmware/openfirmware.h>
#include <board_config.h>
#include <string.h> #include <string.h>
@@ -272,6 +273,10 @@ start_raw(int argc, const char **argv)
args.platform.boot_tgz_size); args.platform.boot_tgz_size);
} }
// specify available physical memory, using 32MB for now, since our
// ARMv5 targets have very little by default. TODO get from FDT!
insert_physical_memory_range(SDRAM_BASE, 32 * 1024 * 1024);
mmu_init(); mmu_init();
// Handle our tarFS post-mmu // Handle our tarFS post-mmu
@@ -346,6 +346,15 @@ ARMPagingMethod32Bit::CreateTranslationMap(bool kernel, VMTranslationMap** _map)
} }
static phys_addr_t
get_free_pgtable(kernel_args* args)
{
phys_addr_t phys = args->arch_args.phys_pgdir + args->arch_args.next_pagetable;
//addr_t virt = args->arch_args.vir_pgdir + args->arch_args.next_pagetable;
args->arch_args.next_pagetable += ARM_MMU_L2_COARSE_TABLE_SIZE;
return phys;
}
status_t status_t
ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress, ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress,
phys_addr_t physicalAddress, uint8 attributes, phys_addr_t physicalAddress, uint8 attributes,
@@ -357,9 +366,7 @@ ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress,
phys_addr_t pgtable; phys_addr_t pgtable;
page_directory_entry *e; page_directory_entry *e;
// we need to allocate a pgtable // we need to allocate a pgtable
pgtable = get_free_page(args); pgtable = get_free_pgtable(args);
// pgtable is in pages, convert to physical address
pgtable *= B_PAGE_SIZE;
TRACE("ARMPagingMethod32Bit::MapEarly(): asked for free page for " TRACE("ARMPagingMethod32Bit::MapEarly(): asked for free page for "
"pgtable. %#" B_PRIxPHYSADDR "\n", pgtable); "pgtable. %#" B_PRIxPHYSADDR "\n", pgtable);