/////////////////////////////////////////////////////////////////////////////////// // 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 /////////////////////////////////////////////////////////////////////////////////// // array of pointers on the page tables (virtual addresses) /////////////////////////////////////////////////////////////////////////////////// __attribute__((section (".kdata"))) unsigned int _ptabs[GIET_NB_VSPACE_MAX]; // virtual addresses __attribute__((section (".kdata"))) unsigned int _ptprs[GIET_NB_VSPACE_MAX]; // physical addresses >> 13 /////////////////////////////////////////////////////////////////////////////////// // array of pointers on the schedulers (physical addresses) /////////////////////////////////////////////////////////////////////////////////// __attribute__((section (".kdata"))) static_scheduler_t* _schedulers[NB_CLUSTERS * NB_PROCS_MAX]; /////////////////////////////////////////////////////////////////////////////////// // staks for the "idle" tasks (256 bytes for each processor) /////////////////////////////////////////////////////////////////////////////////// __attribute__((section (".kdata"))) unsigned int _idle_stack[NB_CLUSTERS * NB_PROCS_MAX * 64]; //////////////// void _sys_exit() { while (1); } ////////////////////////////////////////////////////////////////////////////////// // This function is the entry point for the last step of the boot sequence. // that is done in parallel by all processors, with MMU activated. ////////////////////////////////////////////////////////////////////////////////// __attribute__((section (".kinit"))) void _kernel_init() { // Step 1 : get processor index, // get scheduler address // initialise _schedulers[] array unsigned int global_pid = _procid(); unsigned int cluster_id = global_pid / NB_PROCS_MAX; unsigned int proc_id = global_pid % NB_PROCS_MAX; static_scheduler_t* psched = _get_sched(); unsigned int tasks = psched->tasks; _schedulers[global_pid] = psched; #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] step 1 for processor "); _putd(global_pid); _puts(" : tasks = "); _putd(tasks); _puts(" / scheduler vbase = "); _putx((unsigned int) psched); _puts("\n"); _release_lock(&_tty_put_lock); #endif // step 2 : initialise ptabs[] & ptprs[] arrays // each processor scans all tasks contexts in its // private scheduler and get VSID, PTAB and PTPR values unsigned int ltid; for (ltid = 0; ltid < tasks; ltid++) { unsigned int vsid = _get_task_slot(ltid , CTX_VSID_ID); unsigned int ptab = _get_task_slot(ltid , CTX_PTAB_ID); unsigned int ptpr = _get_task_slot(ltid , CTX_PTPR_ID); _ptabs[vsid] = ptab; _ptprs[vsid] = ptpr; #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] step 2 for processor "); _putd(global_pid); _puts(" / vspace "); _putd(vsid); _puts("\n- ptab = "); _putx(ptab); _puts("\n- ptpr = "); _putx(ptpr); _puts("\n"); _release_lock(&_tty_put_lock); #endif } // step 3 : compute and set ICU masks // there is at most 32 interrupts per processor // software interrupts are not supported yet unsigned int isr_switch_channel = 0xFFFFFFFF; unsigned int irq_id; // IN_IRQ index unsigned int hwi_mask = 0; unsigned int pti_mask = 0; for (irq_id = 0; irq_id < 32; irq_id++) { unsigned int entry = psched->interrupt_vector[irq_id]; unsigned int isr = entry & 0x000000FF; if ((isr == ISR_DMA) || (isr == ISR_IOC) || (isr == ISR_TTY)) { hwi_mask = hwi_mask | 0x1 << irq_id; } else if ((isr == ISR_SWITCH)) { pti_mask = pti_mask | 0x1 << irq_id; isr_switch_channel = irq_id; } else if ((isr == ISR_TIMER)) { pti_mask = pti_mask | 0x1 << irq_id; } } #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] step 3 for processor "); _putd(global_pid); _puts("\n - ICU HWI_MASK = "); _putx(hwi_mask); _puts("\n - ICU PTI_MASK = "); _putx(pti_mask); _puts("\n"); _release_lock(&_tty_put_lock); #endif _icu_set_mask(cluster_id, proc_id, hwi_mask, 0); // set HWI_MASK _icu_set_mask(cluster_id, proc_id, pti_mask, 1); // set PTI_MASK // step 4 : start TICK timer if more than one task if (tasks > 1) { if (isr_switch_channel == 0xFFFFFFFF) { _get_lock(&_tty_put_lock); _puts("\n[GIET ERROR] ISR_SWITCH not found on proc "); _putd(proc_id); _puts("\n"); _release_lock(&_tty_put_lock); _sys_exit(); } if (_timer_start( cluster_id, isr_switch_channel, GIET_TICK_VALUE)) { _get_lock(&_tty_put_lock); _puts("\n[GIET ERROR] ISR_SWITCH init error for proc "); _putd(proc_id); _puts("\n"); _release_lock(&_tty_put_lock); _sys_exit(); } #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] Step 4 for processor "); _putd(global_pid); _puts(" / context switch activated\n"); _release_lock(&_tty_put_lock); #endif } // step 5 : initialise, for each processor, 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] // the stack size is 256 bytes unsigned int stack = (unsigned int)_idle_stack + ((global_pid + 1)<<8); _set_task_slot( IDLE_TASK_INDEX, CTX_RUN_ID, 1); _set_task_slot( IDLE_TASK_INDEX, CTX_SR_ID, 0xFF03); _set_task_slot( IDLE_TASK_INDEX, CTX_SP_ID, stack); _set_task_slot( IDLE_TASK_INDEX, CTX_RA_ID, (unsigned int) &_ctx_eret); _set_task_slot( IDLE_TASK_INDEX, CTX_EPC_ID, (unsigned int) &_ctx_idle); _set_task_slot( IDLE_TASK_INDEX, CTX_LTID_ID, IDLE_TASK_INDEX); _set_task_slot( IDLE_TASK_INDEX, CTX_PTPR_ID, _ptprs[0]); #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] Step 5 for processor "); _putd(global_pid); _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. ltid = 0; if (tasks == 0) { ltid = IDLE_TASK_INDEX; _get_lock(&_tty_put_lock); _puts("\n[GIET WARNING] No task allocated to processor "); _putd(global_pid); _puts(" => idle\n"); _release_lock (&_tty_put_lock); } unsigned int sp_value = _get_task_slot(ltid, CTX_SP_ID); unsigned int sr_value = _get_task_slot(ltid, CTX_SR_ID); unsigned int ptpr_value = _get_task_slot(ltid, CTX_PTPR_ID); unsigned int epc_value = _get_task_slot(ltid, CTX_EPC_ID); _set_task_slot( ltid, CTX_LTID_ID, ltid); #if GIET_DEBUG_INIT _get_lock(&_tty_put_lock); _puts("\n[GIET DEBUG] step 6 for processor "); _putd(global_pid); _puts(" / registers initialised \n"); _puts("- sp = "); _putx(sp_value); _puts("\n"); _puts("- sr = "); _putx(sr_value); _puts("\n"); _puts("- ptpr = "); _putx(ptpr_value); _puts("\n"); _puts("- epc = "); _putx(epc_value); _puts("\n"); _release_lock(&_tty_put_lock); #endif _get_lock(&_tty_put_lock); _puts("\n[GIET] Processor "); _putd( global_pid ); _puts(" starting user code at cycle "); _putd( _proctime() ); _puts("\n"); _release_lock(&_tty_put_lock); // 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() // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4