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
uint32 phys_pgdir;
uint32 vir_pgdir;
uint32 next_pagetable;
} arch_kernel_args;
#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, ...
static const size_t kMaxKernelSize = 0x800000;
// Base address for loader
static const size_t kLoaderBaseAddress = KERNEL_LOAD_BASE + kMaxKernelSize;
// Start and end of ourselfs
// Start and end of ourselfs (from ld script)
extern int _start, _end;
/*
@@ -95,18 +92,6 @@ static struct memblock LOADER_MEMORYMAP[] = {
KERNEL_LOAD_BASE + kMaxKernelSize - 1,
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
{
@@ -127,7 +112,7 @@ static addr_t sNextVirtualAddress = 0;
static addr_t sNextPageTableAddress = 0;
//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;
@@ -137,16 +122,6 @@ static uint32 *sPageDirectory = 0 ;
//some arm processors
static addr_t
get_next_virtual_address(size_t size)
{
addr_t address = sNextVirtualAddress;
sNextVirtualAddress += size;
return address;
}
static addr_t
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
get_next_physical_address_aligned(size_t size, uint32 mask)
{
@@ -246,8 +211,8 @@ static uint32 *
get_next_page_table(uint32 type)
{
TRACE(("get_next_page_table, sNextPageTableAddress 0x%" B_PRIxADDR
", kPageTableRegionEnd 0x%" B_PRIxADDR ", type 0x%" B_PRIx32 "\n",
sNextPageTableAddress, kPageTableRegionEnd, type));
", sPageTableRegionEnd 0x%" B_PRIxADDR ", type 0x%" B_PRIx32 "\n",
sNextPageTableAddress, sPageTableRegionEnd, type));
size_t size = 0;
size_t entryCount = 0;
@@ -266,7 +231,7 @@ get_next_page_table(uint32 type)
}
addr_t address = sNextPageTableAddress;
if (address < kPageTableRegionEnd)
if (address < sPageTableRegionEnd)
sNextPageTableAddress += size;
else {
TRACE(("page table allocation outside of pagetable region!\n"));
@@ -337,7 +302,8 @@ init_page_directory()
{
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
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
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++) {
TRACE(("BLOCK: %s START: %lx END %lx\n", LOADER_MEMORYMAP[i].name,
@@ -358,10 +327,6 @@ init_page_directory()
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();
/* set up the translation table base */
@@ -374,10 +339,6 @@ init_page_directory()
/* turn on the mmu */
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"));
// 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
int index = gKernelArgs.num_physical_allocated_ranges;
gKernelArgs.physical_allocated_range[index].start = SDRAM_BASE;
gKernelArgs.physical_allocated_range[index].size = sNextPhysicalAddress - SDRAM_BASE;
gKernelArgs.num_physical_allocated_ranges++;
insert_physical_allocated_range((addr_t)sPageDirectory, sNextPhysicalAddress - (addr_t)sPageDirectory);
// Save the memory we've virtually allocated (for the kernel and other
// stuff)
gKernelArgs.virtual_allocated_range[0].start = KERNEL_LOAD_BASE;
gKernelArgs.virtual_allocated_range[0].size
= sNextVirtualAddress - KERNEL_LOAD_BASE;
gKernelArgs.num_virtual_allocated_ranges = 1;
insert_virtual_allocated_range(KERNEL_LOAD_BASE, sNextVirtualAddress - KERNEL_LOAD_BASE);
#ifdef TRACE_MEMORY_MAP
{
@@ -601,32 +560,18 @@ mmu_init(void)
mmu_write_C1(mmu_read_C1() & ~((1 << 29) | (1 << 28) | (1 << 0)));
// 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
for (uint32 i = 0; i < ARRAY_SIZE(LOADER_MEMORYMAP); i++) {
if (strcmp("RAM_free", LOADER_MEMORYMAP[i].name) == 0) {
sNextPhysicalAddress = LOADER_MEMORYMAP[i].start;
sNextVirtualAddress = LOADER_MEMORYMAP[i].start;
}
// Mark start for dynamic allocation
sNextPhysicalAddress =
sNextVirtualAddress = sPageTableRegionEnd;
if (strcmp("RAM_pt", LOADER_MEMORYMAP[i].name) == 0) {
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
// mark allocated ranges, so they don't get overwritten
insert_physical_allocated_range((addr_t)&_start, (addr_t)&_end - (addr_t)&_start);
insert_physical_allocated_range((addr_t)sPageDirectory, 0x200000);
init_page_directory();
@@ -678,7 +623,7 @@ platform_release_heap(struct stage2_args *args, void *base)
status_t
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)
return B_NO_MEMORY;
@@ -134,6 +134,10 @@ _start(void)
// Flick on "OK" led, use pre-mmu firmware base
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
insert_physical_allocated_range(BOOT_ARCHIVE_BASE, BOOT_ARCHIVE_SIZE);
@@ -19,6 +19,7 @@
#include <arch/cpu.h>
#include <platform_arch.h>
#include <platform/openfirmware/openfirmware.h>
#include <board_config.h>
#include <string.h>
@@ -272,6 +273,10 @@ start_raw(int argc, const char **argv)
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();
// 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
ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress,
phys_addr_t physicalAddress, uint8 attributes,
@@ -357,9 +366,7 @@ ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress,
phys_addr_t pgtable;
page_directory_entry *e;
// we need to allocate a pgtable
pgtable = get_free_page(args);
// pgtable is in pages, convert to physical address
pgtable *= B_PAGE_SIZE;
pgtable = get_free_pgtable(args);
TRACE("ARMPagingMethod32Bit::MapEarly(): asked for free page for "
"pgtable. %#" B_PRIxPHYSADDR "\n", pgtable);