mirror of
https://github.com/drasko/codezero.git
synced 2026-01-13 19:33:15 +01:00
282 lines
6.8 KiB
C
282 lines
6.8 KiB
C
/*
|
|
* Main initialisation code for the ARM kernel
|
|
*
|
|
* Copyright (C) 2007 - 2010 B Labs Ltd.
|
|
*/
|
|
#include <l4/lib/mutex.h>
|
|
#include <l4/lib/printk.h>
|
|
#include <l4/lib/string.h>
|
|
#include <l4/lib/idpool.h>
|
|
#include <l4/generic/platform.h>
|
|
#include <l4/generic/scheduler.h>
|
|
#include <l4/generic/space.h>
|
|
#include <l4/generic/tcb.h>
|
|
#include <l4/generic/bootmem.h>
|
|
#include <l4/generic/resource.h>
|
|
#include <l4/generic/container.h>
|
|
#include INC_ARCH(linker.h)
|
|
#include INC_ARCH(asm.h)
|
|
#include INC_SUBARCH(mm.h)
|
|
#include INC_SUBARCH(cpu.h)
|
|
#include INC_SUBARCH(mmu_ops.h)
|
|
#include INC_SUBARCH(perfmon.h)
|
|
#include INC_GLUE(memlayout.h)
|
|
#include INC_GLUE(memory.h)
|
|
#include INC_GLUE(mapping.h)
|
|
#include INC_GLUE(message.h)
|
|
#include INC_GLUE(syscall.h)
|
|
#include INC_GLUE(init.h)
|
|
#include INC_GLUE(smp.h)
|
|
#include INC_PLAT(platform.h)
|
|
#include INC_API(syscall.h)
|
|
#include INC_API(kip.h)
|
|
#include INC_API(mutex.h)
|
|
|
|
unsigned int kernel_mapping_end;
|
|
|
|
void print_sections(void)
|
|
{
|
|
dprintk("_start_kernel: ",(unsigned int)_start_kernel);
|
|
dprintk("_start_text: ",(unsigned int)_start_text);
|
|
dprintk("_end_text: ", (unsigned int)_end_text);
|
|
dprintk("_start_data: ", (unsigned int)_start_data);
|
|
dprintk("_end_data: ", (unsigned int)_end_data);
|
|
dprintk("_start_vectors: ",(unsigned int)_start_vectors);
|
|
dprintk("arm_high_vector: ",(unsigned int)arm_high_vector);
|
|
dprintk("_end_vectors: ",(unsigned int)_end_vectors);
|
|
dprintk("_start_kip: ", (unsigned int) _start_kip);
|
|
dprintk("_end_kip: ", (unsigned int) _end_kip);
|
|
dprintk("_start_syscalls: ", (unsigned int) _start_syscalls);
|
|
dprintk("_end_syscalls: ", (unsigned int) _end_syscalls);
|
|
dprintk("_start_bootstack: ", (unsigned int)_start_bootstack);
|
|
dprintk("_end_bootstack: ", (unsigned int)_end_bootstack);
|
|
dprintk("_start_bootstack: ", (unsigned int)_start_bootstack);
|
|
dprintk("_end_bootstack: ", (unsigned int)_end_bootstack);
|
|
dprintk("_start_init_pgd: ", (unsigned int)_start_init_pgd);
|
|
dprintk("_end_init_pgd: ", (unsigned int)_end_init_pgd);
|
|
dprintk("_end_kernel: ", (unsigned int)_end_kernel);
|
|
dprintk("_start_init: ", (unsigned int)_start_init);
|
|
dprintk("_end_init: ", (unsigned int)_end_init);
|
|
dprintk("_end: ", (unsigned int)_end);
|
|
}
|
|
|
|
/* This calculates what address the kip field would have in userspace. */
|
|
#define KIP_USR_OFFSETOF(kip, field) ((void *)(((unsigned long)&kip.field - \
|
|
(unsigned long)&kip) + USER_KIP_PAGE))
|
|
|
|
/* The kip is non-standard, using 0xBB to indicate mine for now ;-) */
|
|
void kip_init()
|
|
{
|
|
struct utcb **utcb_ref;
|
|
|
|
/*
|
|
* TODO: Adding utcb size might be useful
|
|
*/
|
|
memset(&kip, 0, PAGE_SIZE);
|
|
memcpy(&kip, "L4\230K", 4); /* Name field = l4uK */
|
|
kip.api_version = 0xBB;
|
|
kip.api_subversion = 1;
|
|
kip.api_flags = 0; /* LE, 32-bit architecture */
|
|
kip.kdesc.magic = 0xBBB;
|
|
kip.kdesc.version = CODEZERO_VERSION;
|
|
kip.kdesc.subversion = CODEZERO_SUBVERSION;
|
|
strncpy(kip.kdesc.date, __DATE__, KDESC_DATE_SIZE);
|
|
strncpy(kip.kdesc.time, __TIME__, KDESC_TIME_SIZE);
|
|
|
|
kip_init_syscalls();
|
|
|
|
/* KIP + 0xFF0 is pointer to UTCB segment start address */
|
|
utcb_ref = (struct utcb **)((unsigned long)&kip + UTCB_KIP_OFFSET);
|
|
|
|
add_boot_mapping(virt_to_phys(&kip), USER_KIP_PAGE, PAGE_SIZE,
|
|
MAP_USR_RO);
|
|
printk("%s: Kernel built on %s, %s\n", __KERNELNAME__,
|
|
kip.kdesc.date, kip.kdesc.time);
|
|
}
|
|
|
|
void vectors_init()
|
|
{
|
|
unsigned int size = ((u32)_end_vectors - (u32)arm_high_vector);
|
|
|
|
/* Map the vectors in high vector page */
|
|
add_boot_mapping(virt_to_phys(arm_high_vector),
|
|
ARM_HIGH_VECTOR, size, MAP_KERN_RWX);
|
|
|
|
/* Kernel memory trapping is enabled at this point. */
|
|
}
|
|
|
|
|
|
#include <l4/generic/cap-types.h>
|
|
#include <l4/api/capability.h>
|
|
#include <l4/generic/capability.h>
|
|
|
|
/* This is what an idle task needs */
|
|
static DECLARE_PERCPU(struct capability, pmd_cap);
|
|
|
|
/*
|
|
* FIXME: Add this when initializing kernel resources
|
|
* This is a hack.
|
|
*/
|
|
void setup_idle_caps()
|
|
{
|
|
struct capability *cap = &per_cpu(pmd_cap);
|
|
|
|
cap_list_init(¤t->cap_list);
|
|
cap->type = CAP_RTYPE_MAPPOOL | CAP_TYPE_QUANTITY;
|
|
cap->size = 50;
|
|
|
|
link_init(&cap->list);
|
|
cap_list_insert(cap, ¤t->cap_list);
|
|
}
|
|
|
|
/*
|
|
* Set up current stack's beginning, and initial page tables
|
|
* as a valid task environment for idle task for current cpu
|
|
*/
|
|
void setup_idle_task()
|
|
{
|
|
memset(current, 0, sizeof(struct ktcb));
|
|
|
|
current->space = &init_space;
|
|
TASK_PGD(current) = &init_pgd;
|
|
|
|
/* Initialize space caps list */
|
|
cap_list_init(¤t->space->cap_list);
|
|
|
|
#if 0
|
|
/*
|
|
* Unneeded stuff
|
|
*/
|
|
/*
|
|
* Set up idle context.
|
|
*/
|
|
current->context.spsr = ARM_MODE_SVC;
|
|
current->context.pc = (u32)idle_task;
|
|
current->context.sp = (u32)align((unsigned long)current + PAGE_SIZE,
|
|
STACK_ALIGNMENT);
|
|
#endif
|
|
|
|
/*
|
|
* FIXME: This must go to kernel resources init.
|
|
*/
|
|
|
|
/*
|
|
* If using split page tables, kernel
|
|
* resources must point at the global pgd
|
|
* TODO: We may need this for V6, in the future
|
|
*/
|
|
#if defined(CONFIG_SUBARCH_V7)
|
|
kernel_resources.pgd_global = &init_global_pgd;
|
|
#endif
|
|
}
|
|
|
|
void remove_initial_mapping(void)
|
|
{
|
|
/* At this point, execution is on virtual addresses. */
|
|
remove_section_mapping(virt_to_phys(_start_kernel));
|
|
}
|
|
|
|
void init_finalize(void)
|
|
{
|
|
/* Set up idle task capabilities */
|
|
setup_idle_caps();
|
|
|
|
platform_timer_start();
|
|
|
|
#if defined (CONFIG_SMP)
|
|
/* Tell other cores to continue */
|
|
secondary_run_signal = 1;
|
|
dmb();
|
|
#endif
|
|
|
|
idle_task();
|
|
}
|
|
|
|
void start_kernel(void)
|
|
{
|
|
print_early("\n"__KERNELNAME__": start kernel...\n");
|
|
|
|
// print_sections();
|
|
|
|
/* Early cpu initialization */
|
|
cpu_startup();
|
|
|
|
/*
|
|
* Initialise section mappings
|
|
* for the kernel area
|
|
*/
|
|
init_kernel_mappings();
|
|
|
|
print_early("\n"__KERNELNAME__": Init kernel mappings...\n");
|
|
|
|
/*
|
|
* Enable virtual memory
|
|
* and jump to virtual addresses
|
|
*/
|
|
start_virtual_memory();
|
|
|
|
/*
|
|
* Set up initial page tables and ktcb
|
|
* as a valid environment for idle task
|
|
*/
|
|
setup_idle_task();
|
|
|
|
/*
|
|
* Initialise platform-specific
|
|
* page mappings, and peripherals
|
|
*/
|
|
platform_init();
|
|
|
|
/* Can only print when uart is mapped */
|
|
printk("%s: Virtual memory enabled.\n",
|
|
__KERNELNAME__);
|
|
|
|
/* Identify CPUs and system */
|
|
system_identify();
|
|
|
|
sched_init();
|
|
|
|
/* Try to initialize secondary cores if there are any */
|
|
smp_start_cores();
|
|
|
|
/* Remove one-to-one kernel mapping */
|
|
remove_initial_mapping();
|
|
|
|
/*
|
|
* Map and enable high vector page.
|
|
* Faults can be handled after here.
|
|
*/
|
|
vectors_init();
|
|
|
|
/* Remap 1MB kernel sections as 4Kb pages. */
|
|
remap_as_pages((void *)page_align(_start_kernel),
|
|
(void *)page_align_up(_end_kernel));
|
|
|
|
/*
|
|
* Initialise kip and map
|
|
* for userspace access
|
|
*/
|
|
kip_init();
|
|
|
|
/* Initialise system call page */
|
|
syscall_init();
|
|
|
|
/* Init performance monitor, if enabled */
|
|
perfmon_init();
|
|
|
|
/*
|
|
* Evaluate system resources
|
|
* and set up resource pools
|
|
*/
|
|
init_system_resources(&kernel_resources);
|
|
|
|
/*
|
|
* Free boot memory, switch to first
|
|
* task's stack and start scheduler
|
|
*/
|
|
init_finalize();
|
|
|
|
BUG();
|
|
}
|
|
|