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

Last change on this file since 384 was 379, checked in by alain, 10 years ago

reduce the idle task stack to 64 bytes to reduce the kernel.elf size in case of big meshes

  • 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////////////////////////////////////////////////////////////////////////////////////
7// The kernel_init.c file is part of the GIET-VM nano-kernel.
8//
9// This nano-kernel has been written for the MIPS32 processor.
10// The virtual adresses are on 32 bits and use the (unsigned int) type, but the
[310]11// physicals addresses can have up to 40 bits, and use the (unsigned long long) type.
[258]12// It natively supports clusterised shared mmemory multi-processors architectures,
[310]13// where each processor is identified by a composite index [x,y,lpid],
[258]14// and where there is one physical memory bank per cluster.
15//
[310]16// The kernel_init() function is executed in parallel by all procesors,
17// and completes the system initialisation that has been started by processor[0,0,0]
18// in the boot_init() function. It makes the following assuptions, regarding the work
19// bone by the boot code:
20//
21// 1) The page tables associated to the various vspaces have been build
22//    in physical memory, and can be used by the kernel code.
23//
24// 2) All schedulers (this include all task contexts) have been initialised,
25//    Both the virtual and the physical base addresses of the page tables
26//    are available in the CTX_PTAB and CTX_PTPR slots.
27//
28// 3) The CP0_SCHED register of each processor contains a pointer on its
29//    private scheduler (virtual address).
30//
31// 4) The CP2_PTPR register of each processor contains a pointer on
32//    the vspace_0 page table (physical address>>13).
33//
34// 5) For all processors, the MMU is activated (CP2_MODE contains 0xF).
35//
36// This code must be loaded in .kinit section, in order to control seg_kinit_base,
37// as this address is used by the boot code to jump into kernel code.
38//
39// Each processor performs the following actions:
40// 1/ contribute to _schedulers_paddr[] array initialisation.
41// 2/ contribute to _ptabs_paddr[] and _ptabs_vaddr arrays initialisation
42// 3/ completes task context initialisation for ech allocated task
43// 4/ compute and set the ICU mask for its private ICU channel
44// 5/ initialise its private TICK timer (if tasks > 0)
45// 6/ initialise the "idle" task context in its private scheduler
46// 7/ initialise SP, SR, PTPR, EPC registers and jump to user code with an eret.
[258]47////////////////////////////////////////////////////////////////////////////////////
48
49#include <giet_config.h>
50
51// kernel libraries
52#include <utils.h>
53#include <fat32.h>
54
55//for peripheral initialisation
56#include <dma_driver.h>
57#include <fbf_driver.h>
58#include <tty_driver.h>
59#include <icu_driver.h>
60#include <xcu_driver.h>
61#include <ioc_driver.h>
62#include <mmc_driver.h>
63#include <mwr_driver.h>
64#include <nic_driver.h>
65#include <tim_driver.h>
66
67#include <ctx_handler.h>
68#include <irq_handler.h>
69
70#include <mapping_info.h>
71#include <mips32_registers.h>
72
[322]73#if !defined(X_SIZE)
74# error: You must define X_SIZE in the hard_config.h file
75#endif
76
77#if !defined(Y_SIZE)
78# error: You must define Y_SIZE in the hard_config.h file
79#endif
80
81#if !defined(Y_WIDTH)
82# error: You must define Y_WIDTH in the hard_config.h file
83#endif
84
85#if !defined(Y_WIDTH)
86# error: You must define Y_WIDTH in the hard_config.h file
87#endif
88
89#if !defined(NB_PROCS_MAX)
90# error: You must define NB_PROCS_MAX in the hard_config.h file
91#endif
92
93#if !defined(NB_TOTAL_PROCS)
94# error: You must define NB_TOTAL_PROCS in the hard_config.h file
95#endif
96
97#if !defined(USE_XCU)
98# error: You must define USE_XCU in the hard_config.h file
99#endif
100
101#if !defined(IDLE_TASK_INDEX)
102# error: You must define IDLE_TASK_INDEX in the giet_config.h file
103#endif
104
105#if !defined(GIET_TICK_VALUE)
106# error: You must define GIET_TICK_VALUE in the giet_config.h file
107#endif
108
109#if !defined(GIET_NB_VSPACE_MAX)
110# error: You must define GIET_NB_VSPACE_MAX in the giet_config.h file
111#endif
112
[258]113///////////////////////////////////////////////////////////////////////////////////
114// array of pointers on the page tables (virtual addresses)
115///////////////////////////////////////////////////////////////////////////////////
116
117__attribute__((section (".kdata"))) 
[345]118volatile unsigned int _ptabs_vaddr[GIET_NB_VSPACE_MAX];    // virtual addresses
[258]119
120__attribute__((section (".kdata")))       
[345]121volatile unsigned int _ptabs_ptprs[GIET_NB_VSPACE_MAX];    // physical addresses >> 13
[258]122
123///////////////////////////////////////////////////////////////////////////////////
124// array of pointers on the schedulers (physical addresses)
125///////////////////////////////////////////////////////////////////////////////////
126
127__attribute__((section (".kdata"))) 
[373]128volatile static_scheduler_t* _schedulers[NB_PROCS_MAX<<(X_WIDTH+Y_WIDTH)]; 
[258]129
130////////////////////////////////////////////////////////////////////////////////////
[289]131// staks for the "idle" tasks (512 bytes for each processor)
[258]132////////////////////////////////////////////////////////////////////////////////////
133
134__attribute__((section (".kdata"))) 
[379]135volatile unsigned int _idle_stack[X_SIZE * Y_SIZE * NB_PROCS_MAX * 16 ]; 
[258]136
137////////////////////////////////////////////////////////////////////////////////////
[294]138// Synchonisation Barrier before jumping to user code
139////////////////////////////////////////////////////////////////////////////////////
140
141__attribute__((section (".kdata"))) 
[345]142volatile unsigned int _init_barrier = 0;
[294]143
[310]144///////////////////////////////////////////////////////////////////////////////////
145__attribute__((section (".kinit"))) void kernel_init() 
[258]146{
147    unsigned int global_pid = _get_procid();
[263]148    unsigned int cluster_xy = global_pid / NB_PROCS_MAX;
[294]149    unsigned int x          = cluster_xy >> Y_WIDTH;
150    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
151    unsigned int lpid       = global_pid % NB_PROCS_MAX;
[310]152    unsigned int pid        = ((( x * Y_SIZE) + y) * NB_PROCS_MAX) + lpid;
[258]153
[310]154    // This last initialisation phase is done sequencially:
155    while( pid != _init_barrier ) asm volatile ( "nop" );
156
[258]157    // Step 1 : each processor get its scheduler virtual address
158    //          and contribute to initialise the _schedulers[] array
159
160    static_scheduler_t* psched     = (static_scheduler_t*)_get_sched();
161    unsigned int        tasks      = psched->tasks;
162
163    _schedulers[global_pid] = psched;
164
165#if GIET_DEBUG_INIT
[310]166_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] starts kernel init\n"
[294]167        " - scheduler vbase = %x\n"
168        " - tasks           = %d\n",
169        x, y, lpid, (unsigned int)psched, tasks );
[258]170#endif
171
[294]172    // step 2 : each processor that is allocated at least one task loops
173    //          on all allocated tasks:
174    //          - contributes to _ptabs_vaddr[] & _ptabs_ptprs[] initialisation.
175    //          - set CTX_RA slot  with the kernel _ctx_eret() virtual address.
176    //          - set CTX_EPC slot that must contain the task entry point,
177    //            and contain only at this point the virtual address of the memory
178    //            location containing this entry point. We must switch the PTPR
179    //            to use the page table corresponding to the task.
[258]180
181    unsigned int ltid;
182
183    for (ltid = 0; ltid < tasks; ltid++) 
184    {
185        unsigned int vsid = _get_task_slot( global_pid, ltid , CTX_VSID_ID ); 
186        unsigned int ptab = _get_task_slot( global_pid, ltid , CTX_PTAB_ID ); 
187        unsigned int ptpr = _get_task_slot( global_pid, ltid , CTX_PTPR_ID ); 
188
[294]189        // initialize PTABS arrays
[258]190        _ptabs_vaddr[vsid] = ptab;
191        _ptabs_ptprs[vsid] = ptpr;
192
[294]193#if GIET_DEBUG_INIT
[299]194_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] contributes to PTABS arrays\n"
[294]195        " - ptabs_vaddr[%d] = %x / ptpr_paddr[%d] = %l\n",
196        x, y, lpid, 
197        vsid, ptab, vsid, ((unsigned long long)ptpr)<<13 );
198#endif
199
200        // set the ptpr to use the task page table
201        asm volatile( "mtc2    %0,   $0   \n"
202                      : : "r" (ptpr) );
203
204        // compute ctx_ra
[258]205        unsigned int ctx_ra = (unsigned int)(&_ctx_eret);
206        _set_task_slot( global_pid, ltid, CTX_RA_ID, ctx_ra );
207
[294]208        // compute ctx_epc
[258]209        unsigned int* ptr = (unsigned int*)_get_task_slot( global_pid, ltid, CTX_EPC_ID );
210        _set_task_slot( global_pid, ltid, CTX_EPC_ID, *ptr );
211
212#if GIET_DEBUG_INIT
[310]213_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] updates context for task %d\n"
[294]214        " - ctx_epc   = %x\n"
215        " - ctx_ra    = %x\n",
216        x, y, lpid, ltid,
217        _get_task_slot( global_pid, ltid, CTX_EPC_ID ),
218        _get_task_slot( global_pid, ltid, CTX_RA_ID ) );
[258]219#endif
220
[294]221    }  // end for tasks
[258]222
[294]223    // step 4 : compute and set ICU or XCU masks
[258]224
[263]225    unsigned int isr_switch_index = 0xFFFFFFFF;
[258]226    unsigned int hwi_mask = 0;
227    unsigned int pti_mask = 0;
[294]228    unsigned int wti_mask = 0;
229    unsigned int irq_id;            // IN_IRQ index
230    unsigned int entry;             // interrupt vector entry
[258]231
232    for (irq_id = 0; irq_id < 32; irq_id++) 
233    {
[294]234        entry = psched->hwi_vector[irq_id];
235        if ( entry & 0x80000000 ) hwi_mask = hwi_mask | (1<<irq_id);
236        if ( (entry & 0x0000FFFF) == ISR_TICK ) isr_switch_index = irq_id;
[258]237
[294]238        entry = psched->pti_vector[irq_id];
239        if ( entry & 0x80000000 ) pti_mask = pti_mask | (1<<irq_id);
240        if ( (entry & 0x0000FFFF) == ISR_TICK ) isr_switch_index = irq_id;
241
242        entry = psched->wti_vector[irq_id];
243        if ( entry & 0x80000000 ) wti_mask = wti_mask | (1<<irq_id);
244        if ( (entry & 0x0000FFFF) == ISR_TICK ) isr_switch_index = irq_id;
[258]245    }
246
247#if GIET_DEBUG_INIT
[310]248_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] sets XCU masks\n"
[294]249        " - ICU HWI_MASK = %x\n"
250        " - ICU WTI_MASK = %x\n"
251        " - ICU PTI_MASK = %x\n",
252        x, y, lpid, hwi_mask, wti_mask, pti_mask );
[258]253#endif
254
[294]255    unsigned int channel = lpid * IRQ_PER_PROCESSOR; 
[258]256
[322]257#if USE_XCU
[294]258    _xcu_set_mask( cluster_xy, channel, hwi_mask, IRQ_TYPE_HWI ); 
259    _xcu_set_mask( cluster_xy, channel, wti_mask, IRQ_TYPE_WTI );
260    _xcu_set_mask( cluster_xy, channel, pti_mask, IRQ_TYPE_PTI );
[258]261#else
[294]262    _icu_set_mask( cluster_xy, channel, hwi_mask );   
[258]263#endif
264
[294]265    // step 5 : start TICK timer if at least one task
[258]266    if (tasks > 0) 
267    {
[294]268        // one ISR_TICK must be defined for each proc
[263]269        if (isr_switch_index == 0xFFFFFFFF) 
[258]270        {
[294]271            _printf("\n[GIET ERROR] ISR_TICK not found for processor[%d,%d,%d]\n",
272                    x, y, lpid );
[258]273            _exit();
274        }
275
[294]276        // start system timer
[271]277
[322]278#if USE_XCU
[294]279        _xcu_timer_start( cluster_xy, isr_switch_index, GIET_TICK_VALUE ); 
[258]280#else
[294]281        _timer_start( cluster_xy, isr_switch_index, GIET_TICK_VALUE ); 
[258]282#endif
283
[294]284    }
285
[258]286#if GIET_DEBUG_INIT
[310]287_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] starts TICK timer\n",
[294]288        x, y, lpid );
[258]289#endif
290
[294]291    // step 6 : each processor updates the idle_task context:
[258]292    //          (only CTX_SP, CTX_RA, CTX_EPC).
[289]293    //          The stack size is 512 bytes, reserved in seg_kdata.
[258]294    //          The PTPR register, the CTX_PTPR and CTX_PTAB slots
295    //          have been initialised in boot code.
296
[294]297    unsigned int p = ((x * Y_SIZE) + y) * NB_PROCS_MAX + lpid; 
[258]298
[289]299    unsigned int stack = (unsigned int)_idle_stack + ((p + 1)<<9);
300
[258]301    _set_task_slot( global_pid, IDLE_TASK_INDEX, CTX_SP_ID,  stack);
302    _set_task_slot( global_pid, IDLE_TASK_INDEX, CTX_RA_ID,  (unsigned int) &_ctx_eret);
303    _set_task_slot( global_pid, IDLE_TASK_INDEX, CTX_EPC_ID, (unsigned int) &_idle_task);
304
305#if GIET_DEBUG_INIT
[310]306_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] initializes IDLE task\n",
[294]307        x, y, lpid );
[258]308#endif
309
[294]310    // step 7 : when all processors reach the synchronisation barrier,
311    //          each processor set registers SP, SR, PTPR, EPC,
[258]312    //          with the values corresponding to the first allocated task,
[294]313    //          or to the idle_task if there is no task allocated,
314    //          and jump to user code
[258]315
316    if (tasks == 0) 
317    {
318        ltid = IDLE_TASK_INDEX;
319
[294]320        _printf("\n[GIET WARNING] No task allocated to processor[%d,%d,%d]\n",
321                x, y, lpid );
[258]322    }
[294]323    else
324    {
325        ltid = 0;
326    }
[258]327
328    unsigned int sp_value   = _get_task_slot(global_pid, ltid, CTX_SP_ID);
329    unsigned int sr_value   = _get_task_slot(global_pid, ltid, CTX_SR_ID);
330    unsigned int ptpr_value = _get_task_slot(global_pid, ltid, CTX_PTPR_ID);
331    unsigned int epc_value  = _get_task_slot(global_pid, ltid, CTX_EPC_ID);
332
[330]333#if GIET_DEBUG_INIT
334_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] reach barrier at cycle %d\n",
335        x, y, lpid, _get_proctime() );
336#endif
[258]337
[310]338    // increment barrier counter
339    _init_barrier++;
340
341    // busy waiting until all processors synchronized
[345]342    while ( _init_barrier != NB_TOTAL_PROCS );
[310]343
[294]344    // set registers and jump to user code
345    asm volatile ( "move  $29,  %0                  \n"   /* SP <= ctx[CTX_SP_ID] */
346                   "mtc0  %1,   $12                 \n"   /* SR <= ctx[CTX_SR_ID] */
347                   "mtc2  %2,   $0                  \n"   /* PTPR <= ctx[CTX_PTPR] */
348                   "mtc0  %3,   $14                 \n"   /* EPC <= ctx[CTX_EPC]  */
349                   "eret                            \n"   /* jump to user code  */
350                   "nop                             \n"
351                   : 
352                   : "r"(sp_value), "r"(sr_value), "r"(ptpr_value), "r"(epc_value)
[345]353                   : "$29", "memory" );
[294]354
[310]355} // end kernel_init()
[258]356
357
358// Local Variables:
359// tab-width: 4
360// c-basic-offset: 4
361// c-file-offsets:((innamespace . 0)(inline-open . 0))
362// indent-tabs-mode: nil
363// End:
364// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
365
Note: See TracBrowser for help on using the repository browser.