/////////////////////////////////////////////////////////////////////////////////// // File : kernel_init.c // Date : 26/05/2012 // Authors : alain greiner & mohamed karaoui // Copyright (c) UPMC-LIP6 //////////////////////////////////////////////////////////////////////////////////// // The kernel_init.c files is part of the GIET-VM nano-kernel. // It contains the kernel entry point for the last step of system initialisation. // All procs in this phase have their MMU activated, and are running in parallel. // Each processor perform the following actions: // 1/ contributes to _schedulers_paddr[] initialisation // 2/ contributes to _ptabs_paddr[] and _ptabs_vaddr arrays initialisation // 3/ computes and set the ICU mask for its private ICU channel // 4/ initialises its private TICK timer (if required) // 5/ initialises the "idle" task context in its private scheduler // 6/ initialises the SP, SR, PTPR, EPC registers // 7/ jumps to the user code with an eret. //////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////////// // Kernel Global variables /////////////////////////////////////////////////////////////////////////////////// __attribute__((section (".kdata"))) unsigned int _ptabs_paddr[GIET_NB_VSPACE_MAX]; __attribute__((section (".kdata"))) unsigned int _ptabs_vaddr[GIET_NB_VSPACE_MAX]; __attribute__((section (".kdata"))) static_scheduler_t* _schedulers_paddr[NB_CLUSTERS*NB_PROCS_MAX]; __attribute__((section (".kdata"))) unsigned int _idle_stack[NB_CLUSTERS*NB_PROCS_MAX*64]; ////////////////////////////////////////////////////////////////////////////////// // This function is the entry point for the last step of the boot sequence. ////////////////////////////////////////////////////////////////////////////////// __attribute__((section (".kinit"))) void _kernel_init() { // compute cluster and local processor index unsigned int proc_id = _procid(); unsigned int cluster_id = proc_id / NB_PROCS_MAX; unsigned int lpid = proc_id % NB_PROCS_MAX; // step 1 : Initialise scheduler physical addresses array // get scheduler physical address from register static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); _schedulers_paddr[proc_id] = psched; #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] step 1 for processor "); _putd( proc_id ); _puts(" / scheduler pbase = "); _putw( (unsigned int)psched ); _puts("\n"); _release_lock(&_tty_put_lock); #endif // step 2 : initialise page table addresse arrays // it scans all tasks contexts in the scheduler // and get VSID, PTAB and PTPR values unsigned int ltid; unsigned int tasks = _get_tasks_number(); for ( ltid = 0 ; ltid < tasks ; ltid++ ) { unsigned int vspace_id = _get_context_slot( ltid , CTX_VSID_ID ); unsigned int ptab_vaddr = _get_context_slot( ltid , CTX_PTAB_ID ); unsigned int ptab_paddr = _get_context_slot( ltid , CTX_PTPR_ID ) << 13; _ptabs_vaddr[vspace_id] = ptab_vaddr; _ptabs_paddr[vspace_id] = ptab_paddr; #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] step 2 for processor "); _putd( proc_id ); _puts(" / vspace "); _putd( vspace_id ); _puts("\n- ptab vbase = "); _putw( ptab_vaddr ); _puts("\n- ptab pbase = "); _putw( ptab_paddr ); _puts("\n"); _release_lock(&_tty_put_lock); #endif } // step 3 : compute and set ICU mask unsigned int irq_id; unsigned int mask = 0; for ( irq_id = 0 ; irq_id < 32 ; irq_id++ ) { unsigned int entry = _get_interrupt_vector_entry(irq_id); if ( entry ) mask = mask | 0x1<< irq_id; } _icu_write( cluster_id, lpid, ICU_MASK_SET, mask ); #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] step 3 for processor "); _putd( proc_id ); _puts(" / ICU mask = "); _putw( mask ); _puts("\n"); _release_lock(&_tty_put_lock); #endif // step 4 : start TICK timer if more than one task if ( tasks > 1 ) { unsigned int period = GIET_TICK_VALUE; unsigned int mode = 0x3; _timer_access( 0, // write access cluster_id, proc_id, TIMER_PERIOD, &period ); _timer_access( 0, // write access cluster_id, proc_id, TIMER_MODE, &mode ); #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] Step 4 for processor "); _putd( proc_id ); _puts(" / TICK activated\n"); _release_lock(&_tty_put_lock); #endif } // step 5 : initialise the "idle" task context // the SR initialisation value is 0xFF03 because // the task _ctx_idle() executes in kernel mode... // it uses the page table of vspace[0] _set_context_slot( IDLE_TASK_INDEX, CTX_RUN_ID, 1 ); _set_context_slot( IDLE_TASK_INDEX, CTX_SR_ID, 0xFF03 ); _set_context_slot( IDLE_TASK_INDEX, CTX_SP_ID, (unsigned int)&_idle_stack[proc_id] + 64 ); _set_context_slot( IDLE_TASK_INDEX, CTX_RA_ID, (unsigned int)&_ctx_eret ); _set_context_slot( IDLE_TASK_INDEX, CTX_EPC_ID, (unsigned int)&_ctx_idle ); _set_context_slot( IDLE_TASK_INDEX, CTX_LTID_ID, IDLE_TASK_INDEX ); _set_context_slot( IDLE_TASK_INDEX, CTX_PTPR_ID, _ptabs_paddr[0] >> 13 ); #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] Step 5 for processor "); _putd( proc_id ); _puts(" / idle task context set\n"); _release_lock(&_tty_put_lock); #endif // step 6 : each processor initialises SP, SR, PTPR, EPC, registers // with the values corresponding to the first allocated task, // and starts the "idle" task if there is no task allocated. unsigned int task_id; if ( tasks == 0 ) { task_id = IDLE_TASK_INDEX; _get_lock( &_tty_put_lock ); _puts("\n [GIET WARNING] No task allocated to processor "); _putw( proc_id ); _puts(" => idle\n"); _release_lock ( &_tty_put_lock ); } else { task_id = 0; } unsigned int sp_value = _get_context_slot( task_id, CTX_SP_ID ); unsigned int sr_value = _get_context_slot( task_id, CTX_SR_ID ); unsigned int ptpr_value = _get_context_slot( task_id, CTX_PTPR_ID ); unsigned int epc_value = _get_context_slot( task_id, CTX_EPC_ID ); #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] step 6 for processor "); _putd( proc_id ); _puts(" / registers initialised \n"); _puts("- sp = "); _putw( sp_value ); _puts("\n"); _puts("- sr = "); _putw( sr_value ); _puts("\n"); _puts("- ptpr = "); _putw( ptpr_value<<13 ); _puts("\n"); _puts("- epc = "); _putw( epc_value ); _puts("\n"); _release_lock(&_tty_put_lock); #endif // set registers and jump to user code asm volatile ( "move $29, %0 \n" /* SP <= ctx[CTX_SP_ID] */ "mtc0 %1, $12 \n" /* SR <= ctx[CTX_SR_ID] */ "mtc2 %2, $0 \n" /* PTPR <= ctx[CTX_PTPR_ID] */ "mtc0 %3, $14 \n" /* EPC <= ctx[CTX_EPC_ID] */ "eret \n" /* jump to user code */ "nop \n" : : "r"(sp_value), "r"(sr_value), "r"(ptpr_value), "r"(epc_value) ); } // end _kernel_init()