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:
@@ -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 */
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user