source: soft/giet_vm/giet_kernel/kernel_init.c @ 508

Last change on this file since 508 was 494, checked in by alain, 10 years ago

Introduce a fully parallel procedure for the kernel initialisation.

  • Property svn:executable set to *
File size: 13.3 KB
RevLine 
[258]1///////////////////////////////////////////////////////////////////////////////////
2// File     : kernel_init.c
3// Date     : 26/05/2012
4// Authors  : alain greiner & mohamed karaoui
5// Copyright (c) UPMC-LIP6
6////////////////////////////////////////////////////////////////////////////////////
[440]7// This kernel_init.c file is part of the GIET-VM nano-kernel.
[258]8////////////////////////////////////////////////////////////////////////////////////
9
10#include <giet_config.h>
[440]11#include <hard_config.h>
[258]12#include <utils.h>
[459]13#include <tty0.h>
[467]14#include <kernel_malloc.h>
[494]15#include <kernel_locks.h>
16#include <kernel_barriers.h>
[258]17#include <fat32.h>
18#include <xcu_driver.h>
[459]19#include <ioc_driver.h>
[478]20#include <mmc_driver.h>
[258]21#include <ctx_handler.h>
22#include <irq_handler.h>
23#include <mapping_info.h>
24#include <mips32_registers.h>
25
[322]26#if !defined(X_SIZE)
27# error: You must define X_SIZE in the hard_config.h file
28#endif
29
30#if !defined(Y_SIZE)
31# error: You must define Y_SIZE in the hard_config.h file
32#endif
33
34#if !defined(Y_WIDTH)
35# error: You must define Y_WIDTH in the hard_config.h file
36#endif
37
38#if !defined(Y_WIDTH)
39# error: You must define Y_WIDTH in the hard_config.h file
40#endif
41
42#if !defined(NB_PROCS_MAX)
43# error: You must define NB_PROCS_MAX in the hard_config.h file
44#endif
45
46#if !defined(NB_TOTAL_PROCS)
47# error: You must define NB_TOTAL_PROCS in the hard_config.h file
48#endif
49
50#if !defined(USE_XCU)
51# error: You must define USE_XCU in the hard_config.h file
52#endif
53
54#if !defined(IDLE_TASK_INDEX)
[391]55# error: You must define IDLE_TASK_INDEX in the ctx_handler.h file
[322]56#endif
57
58#if !defined(GIET_TICK_VALUE)
59# error: You must define GIET_TICK_VALUE in the giet_config.h file
60#endif
61
62#if !defined(GIET_NB_VSPACE_MAX)
63# error: You must define GIET_NB_VSPACE_MAX in the giet_config.h file
64#endif
65
[467]66#if !defined(NB_TTY_CHANNELS)
67# error: You must define NB_TTY_CHANNELS in the hard_config.h file
68#endif
69
70#if (NB_TTY_CHANNELS < 1)
71# error: NB_TTY_CHANNELS cannot be smaller than 1
72#endif
73
74
75
[494]76// Distributed kernel heap descriptors array
77// __attribute__((section(".kdata")))
78// kernel_heap_t  kernel_heap[X_SIZE][Y_SIZE];
[467]79
[410]80// FAT internal representation for kernel code
[494]81__attribute__((section(".kdata")))
[467]82fat32_fs_t     fat      __attribute__((aligned(512)));
[410]83
[494]84// array of page tables virtual addresses
85__attribute__((section(".kdata")))
86volatile unsigned int _ptabs_vaddr[GIET_NB_VSPACE_MAX]; 
[258]87
[494]88// array of page tables PTPR values (physical addresses >> 13)
89__attribute__((section(".kdata")))
90volatile unsigned int _ptabs_ptprs[GIET_NB_VSPACE_MAX]; 
[258]91
[494]92// Array of pointers on the schedulers
93__attribute__((section(".kdata")))
[467]94volatile static_scheduler_t*    _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX]; 
[258]95
[494]96// Synchonisation before entering parallel execution
97__attribute__((section(".kdata")))
98volatile unsigned int _kernel_init_done = 0;
[258]99
[494]100// Kernel uses sqt_lock to protect TTY0       
101__attribute__((section(".kdata")))
102unsigned int   _tty0_boot_mode = 0;
[294]103
[494]104// Distributed synchronisation barrier for parallel init by all processors     
105__attribute__((section(".kdata")))
106sqt_barrier_t  _all_procs_barrier  __attribute__((aligned(64)));
[467]107
108
109
[494]110// this variable is defined in tty0.c file
111extern sqt_lock_t _tty0_sqt_lock;
[467]112
[494]113
114
[310]115///////////////////////////////////////////////////////////////////////////////////
[494]116// This kernel_init() function completes the kernel initialisation in 7 steps.
117// Step 0 is done by processor[0,0,0]. Steps 1 to 6 are executed in parallel
118// by all procesors.
119// - step 0 : P[0,0,0] Initialise fat, heap descriptors, barrier and TTY0 lock.
120// - step 1 : Each processor initialises scheduler pointers array.
121// - step 2 : Each processor initialises PTAB pointers arrays.
122// - step 3 : Each processor initialises its private XCU masks.
123// - step 4 : Each processor starts its private TICK timer.
124// - step 5 : Each processor initialises its private idle task context.
125// - step 6 : Each processor set sp, sr, ptpr, epc registers values.
[467]126///////////////////////////////////////////////////////////////////////////////////
[310]127__attribute__((section (".kinit"))) void kernel_init() 
[258]128{
[494]129    // gpid  : hardware processor index (fixed format: X_WIDTH|Y_WIDTH|P_WIDTH)
130    // x,y,p : processor coordinates ( x<X_SIZE / y<Y_SIZE / p<NB_PROCS_MAX )
[428]131
132    unsigned int gpid       = _get_procid();
133    unsigned int cluster_xy = gpid >> P_WIDTH;
134    unsigned int x          = cluster_xy >> Y_WIDTH & ((1<<X_WIDTH)-1);
[294]135    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
[440]136    unsigned int p          = gpid & ((1<<P_WIDTH)-1);
[258]137
[494]138    ////////////////////////////////////////////////////////////////////////////
139    // Step 0 : P[0,0,0] initialises various structures
[428]140
[467]141    if ( gpid == 0 )
142    {
[494]143        // distributed kernel heaps
[467]144        _heap_init();
145       
146#if GIET_DEBUG_INIT
147_nolock_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] completes kernel HEAP init\n", x, y, p );
148#endif
[494]149        // kernel FAT
150        _fat_init( IOC_BOOT_MODE ); 
[478]151
152#if GIET_DEBUG_INIT
[494]153_nolock_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] completes kernel FAT init\n", x, y, p );
[478]154#endif
[494]155        // distributed lock for TTY0
156        _sqt_lock_init( &_tty0_sqt_lock );
[459]157
[467]158#if GIET_DEBUG_INIT
[494]159_nolock_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] completes TTY0 lock init\n", 
160               x , y , p );
[467]161#endif
[494]162        // distributed kernel barrier between all processors
163        _sqt_barrier_init( &_all_procs_barrier );
[467]164
165#if GIET_DEBUG_INIT
[494]166_nolock_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] completes barrier init\n", 
167               x , y , p );
[467]168#endif
169
[494]170        // release other processors
171        _kernel_init_done = 1;
[467]172    }
[494]173    else 
174    {
175        while( _kernel_init_done == 0 )  asm volatile ( "nop" );
176    }
[467]177
[494]178    ///////////////////////////////////////////////////////////////////
179    // Step 1 : each processor get its scheduler vaddr from CP0_SCHED,
180    //          contributes to _schedulers[] array initialisation,
181    //          and wait completion of array initialisation.
[258]182
183    static_scheduler_t* psched     = (static_scheduler_t*)_get_sched();
184    unsigned int        tasks      = psched->tasks;
185
[440]186    _schedulers[x][y][p] = psched;
[258]187
188#if GIET_DEBUG_INIT
[494]189_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] initialises SCHED array\n"
190        " - scheduler vbase = %x\n"
191        " - tasks           = %d\n",
192        x, y, p, (unsigned int)psched, tasks );
[258]193#endif
194
[494]195    _sqt_barrier_wait( &_all_procs_barrier );   
196
197    ////////////////////////////////////////////////////////////////////////////
[294]198    // step 2 : each processor that is allocated at least one task loops
199    //          on all allocated tasks:
200    //          - contributes to _ptabs_vaddr[] & _ptabs_ptprs[] initialisation.
201    //          - set CTX_RA slot  with the kernel _ctx_eret() virtual address.
202    //          - set CTX_EPC slot that must contain the task entry point,
203    //            and contain only at this point the virtual address of the memory
[440]204    //            location containing this entry point.
[258]205
206    unsigned int ltid;
207
208    for (ltid = 0; ltid < tasks; ltid++) 
209    {
[440]210        unsigned int vsid = _get_task_slot( x, y, p, ltid , CTX_VSID_ID ); 
211        unsigned int ptab = _get_task_slot( x, y, p, ltid , CTX_PTAB_ID ); 
212        unsigned int ptpr = _get_task_slot( x, y, p, ltid , CTX_PTPR_ID ); 
[258]213
[294]214        // initialize PTABS arrays
[258]215        _ptabs_vaddr[vsid] = ptab;
216        _ptabs_ptprs[vsid] = ptpr;
217
[294]218#if GIET_DEBUG_INIT
[494]219_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] initialises PTABS arrays\n"
[294]220        " - ptabs_vaddr[%d] = %x / ptpr_paddr[%d] = %l\n",
[440]221        x, y, p, 
[294]222        vsid, ptab, vsid, ((unsigned long long)ptpr)<<13 );
223#endif
224
225        // set the ptpr to use the task page table
226        asm volatile( "mtc2    %0,   $0   \n"
227                      : : "r" (ptpr) );
228
229        // compute ctx_ra
[258]230        unsigned int ctx_ra = (unsigned int)(&_ctx_eret);
[440]231        _set_task_slot( x, y, p, ltid, CTX_RA_ID, ctx_ra );
[258]232
[294]233        // compute ctx_epc
[440]234        unsigned int* ptr = (unsigned int*)_get_task_slot( x, y, p, ltid, CTX_EPC_ID );
235        _set_task_slot( x, y, p, ltid, CTX_EPC_ID, *ptr );
[258]236
237#if GIET_DEBUG_INIT
[494]238_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] updates context for task %d\n"
239        " - ctx_epc   = %x\n"
240        " - ctx_ra    = %x\n",
241        x, y, p, ltid,
242        _get_task_slot( x, y, p, ltid, CTX_EPC_ID ),
243        _get_task_slot( x, y, p, ltid, CTX_RA_ID ) );
[258]244#endif
245
[294]246    }  // end for tasks
[258]247
[494]248    _sqt_barrier_wait( &_all_procs_barrier );   
[258]249
[494]250    ////////////////////////////////////////////////////////////////////////////
251    // step 3 : compute and set XCU masks for HWI / PTI / WTI interrupts
252
[263]253    unsigned int isr_switch_index = 0xFFFFFFFF;
[258]254    unsigned int hwi_mask = 0;
255    unsigned int pti_mask = 0;
[294]256    unsigned int wti_mask = 0;
257    unsigned int irq_id;            // IN_IRQ index
258    unsigned int entry;             // interrupt vector entry
[258]259
260    for (irq_id = 0; irq_id < 32; irq_id++) 
261    {
[294]262        entry = psched->hwi_vector[irq_id];
263        if ( entry & 0x80000000 ) hwi_mask = hwi_mask | (1<<irq_id);
264        if ( (entry & 0x0000FFFF) == ISR_TICK ) isr_switch_index = irq_id;
[258]265
[294]266        entry = psched->pti_vector[irq_id];
267        if ( entry & 0x80000000 ) pti_mask = pti_mask | (1<<irq_id);
268        if ( (entry & 0x0000FFFF) == ISR_TICK ) isr_switch_index = irq_id;
269
270        entry = psched->wti_vector[irq_id];
271        if ( entry & 0x80000000 ) wti_mask = wti_mask | (1<<irq_id);
272        if ( (entry & 0x0000FFFF) == ISR_TICK ) isr_switch_index = irq_id;
[258]273    }
274
275#if GIET_DEBUG_INIT
[494]276_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] sets XCU masks\n"
277        " - ISR_TICK_INDEX = %d\n"
278        " - XCU HWI_MASK   = %x\n"
279        " - XCU WTI_MASK   = %x\n"
280        " - XCU PTI_MASK   = %x\n",
281        x, y, p, 
282        isr_switch_index,
283        hwi_mask, wti_mask, pti_mask );
[258]284#endif
285
[440]286    unsigned int channel = p * IRQ_PER_PROCESSOR; 
[258]287
[294]288    _xcu_set_mask( cluster_xy, channel, hwi_mask, IRQ_TYPE_HWI ); 
289    _xcu_set_mask( cluster_xy, channel, wti_mask, IRQ_TYPE_WTI );
290    _xcu_set_mask( cluster_xy, channel, pti_mask, IRQ_TYPE_PTI );
[258]291
[494]292    ////////////////////////////////////////////////////////////////////////////
293    // step 4 : Each processor start TICK timer if at least one task
294
[258]295    if (tasks > 0) 
296    {
[294]297        // one ISR_TICK must be defined for each proc
[263]298        if (isr_switch_index == 0xFFFFFFFF) 
[258]299        {
[494]300            _printf("\n[GIET ERROR] ISR_TICK not found for processor[%d,%d,%d]\n",
[467]301                           x, y, p );
[258]302            _exit();
303        }
304
[294]305        // start system timer
306        _xcu_timer_start( cluster_xy, isr_switch_index, GIET_TICK_VALUE ); 
[258]307
[294]308    }
309
[258]310#if GIET_DEBUG_INIT
[494]311_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] starts TICK timer\n",
312        x, y, p );
[258]313#endif
314
[494]315    ////////////////////////////////////////////////////////////////////////////
[449]316    // step 5 : each processor updates the idle_task context:
[391]317    //          (CTX_SP, CTX_RA, CTX_EPC).
318    //          The 4 Kbytes idle stack is implemented in the scheduler.
[258]319    //          The PTPR register, the CTX_PTPR and CTX_PTAB slots
320    //          have been initialised in boot code.
321
[391]322    unsigned int pstack = ((unsigned int)psched) + 0x2000;
[258]323
[440]324    _set_task_slot( x, y, p, IDLE_TASK_INDEX, CTX_SP_ID,  pstack);
325    _set_task_slot( x, y, p, IDLE_TASK_INDEX, CTX_RA_ID,  (unsigned int) &_ctx_eret);
326    _set_task_slot( x, y, p, IDLE_TASK_INDEX, CTX_EPC_ID, (unsigned int) &_idle_task);
[258]327
328#if GIET_DEBUG_INIT
[494]329_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] initializes IDLE task\n"
330        " - stack_base = %x\n"
331        " - stack_size = 0x1000\n",
332        x, y, p, pstack - 0x1000 );
[258]333#endif
334
[494]335    _sqt_barrier_wait( &_all_procs_barrier );   
[258]336
[494]337    ////////////////////////////////////////////////////////////////////////////
338    // step 6 : Each processor compute values for registers SP, SR, PTPR, EPC,
339    //          corresponding to the first allocated task (can be idle task)
340    //          and jump to user code when barrier is reached
341
342    if (tasks == 0)
[258]343    {
344        ltid = IDLE_TASK_INDEX;
[494]345        _printf("\n[GIET WARNING] No task allocated to processor[%d,%d,%d]\n",
346                x, y, p );
[258]347    }
[294]348    else
349    {
350        ltid = 0;
351    }
[258]352
[440]353    unsigned int sp_value   = _get_task_slot( x, y, p, ltid, CTX_SP_ID);
354    unsigned int sr_value   = _get_task_slot( x, y, p, ltid, CTX_SR_ID);
355    unsigned int ptpr_value = _get_task_slot( x, y, p, ltid, CTX_PTPR_ID);
356    unsigned int epc_value  = _get_task_slot( x, y, p, ltid, CTX_EPC_ID);
[258]357
[494]358    _sqt_barrier_wait( &_all_procs_barrier );
[258]359
[391]360#if GIET_DEBUG_INIT
[494]361_printf("\n[DEBUG KERNEL_INIT] P[%d,%d,%d] jumps to user code at cycle %d\n"
362        "  sp = %x / sr = %x / ptpr = %x / epc = %x\n",
[440]363        x, y, p, _get_proctime(),
[391]364        sp_value, sr_value, ptpr_value, epc_value );
365#endif
366
[294]367    // set registers and jump to user code
368    asm volatile ( "move  $29,  %0                  \n"   /* SP <= ctx[CTX_SP_ID] */
369                   "mtc0  %1,   $12                 \n"   /* SR <= ctx[CTX_SR_ID] */
370                   "mtc2  %2,   $0                  \n"   /* PTPR <= ctx[CTX_PTPR] */
371                   "mtc0  %3,   $14                 \n"   /* EPC <= ctx[CTX_EPC]  */
372                   "eret                            \n"   /* jump to user code  */
373                   "nop                             \n"
374                   : 
375                   : "r"(sp_value), "r"(sr_value), "r"(ptpr_value), "r"(epc_value)
[345]376                   : "$29", "memory" );
[294]377
[310]378} // end kernel_init()
[258]379
380
381// Local Variables:
382// tab-width: 4
383// c-basic-offset: 4
384// c-file-offsets:((innamespace . 0)(inline-open . 0))
385// indent-tabs-mode: nil
386// End:
387// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
388
Note: See TracBrowser for help on using the repository browser.