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

Last change on this file since 383 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
Line 
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
11// physicals addresses can have up to 40 bits, and use the (unsigned long long) type.
12// It natively supports clusterised shared mmemory multi-processors architectures,
13// where each processor is identified by a composite index [x,y,lpid],
14// and where there is one physical memory bank per cluster.
15//
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.
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
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
113///////////////////////////////////////////////////////////////////////////////////
114// array of pointers on the page tables (virtual addresses)
115///////////////////////////////////////////////////////////////////////////////////
116
117__attribute__((section (".kdata"))) 
118volatile unsigned int _ptabs_vaddr[GIET_NB_VSPACE_MAX];    // virtual addresses
119
120__attribute__((section (".kdata")))       
121volatile unsigned int _ptabs_ptprs[GIET_NB_VSPACE_MAX];    // physical addresses >> 13
122
123///////////////////////////////////////////////////////////////////////////////////
124// array of pointers on the schedulers (physical addresses)
125///////////////////////////////////////////////////////////////////////////////////
126
127__attribute__((section (".kdata"))) 
128volatile static_scheduler_t* _schedulers[NB_PROCS_MAX<<(X_WIDTH+Y_WIDTH)]; 
129
130////////////////////////////////////////////////////////////////////////////////////
131// staks for the "idle" tasks (512 bytes for each processor)
132////////////////////////////////////////////////////////////////////////////////////
133
134__attribute__((section (".kdata"))) 
135volatile unsigned int _idle_stack[X_SIZE * Y_SIZE * NB_PROCS_MAX * 16 ]; 
136
137////////////////////////////////////////////////////////////////////////////////////
138// Synchonisation Barrier before jumping to user code
139////////////////////////////////////////////////////////////////////////////////////
140
141__attribute__((section (".kdata"))) 
142volatile unsigned int _init_barrier = 0;
143
144///////////////////////////////////////////////////////////////////////////////////
145__attribute__((section (".kinit"))) void kernel_init() 
146{
147    unsigned int global_pid = _get_procid();
148    unsigned int cluster_xy = global_pid / NB_PROCS_MAX;
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;
152    unsigned int pid        = ((( x * Y_SIZE) + y) * NB_PROCS_MAX) + lpid;
153
154    // This last initialisation phase is done sequencially:
155    while( pid != _init_barrier ) asm volatile ( "nop" );
156
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
166_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] starts kernel init\n"
167        " - scheduler vbase = %x\n"
168        " - tasks           = %d\n",
169        x, y, lpid, (unsigned int)psched, tasks );
170#endif
171
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.
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
189        // initialize PTABS arrays
190        _ptabs_vaddr[vsid] = ptab;
191        _ptabs_ptprs[vsid] = ptpr;
192
193#if GIET_DEBUG_INIT
194_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] contributes to PTABS arrays\n"
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
205        unsigned int ctx_ra = (unsigned int)(&_ctx_eret);
206        _set_task_slot( global_pid, ltid, CTX_RA_ID, ctx_ra );
207
208        // compute ctx_epc
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
213_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] updates context for task %d\n"
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 ) );
219#endif
220
221    }  // end for tasks
222
223    // step 4 : compute and set ICU or XCU masks
224
225    unsigned int isr_switch_index = 0xFFFFFFFF;
226    unsigned int hwi_mask = 0;
227    unsigned int pti_mask = 0;
228    unsigned int wti_mask = 0;
229    unsigned int irq_id;            // IN_IRQ index
230    unsigned int entry;             // interrupt vector entry
231
232    for (irq_id = 0; irq_id < 32; irq_id++) 
233    {
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;
237
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;
245    }
246
247#if GIET_DEBUG_INIT
248_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] sets XCU masks\n"
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 );
253#endif
254
255    unsigned int channel = lpid * IRQ_PER_PROCESSOR; 
256
257#if USE_XCU
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 );
261#else
262    _icu_set_mask( cluster_xy, channel, hwi_mask );   
263#endif
264
265    // step 5 : start TICK timer if at least one task
266    if (tasks > 0) 
267    {
268        // one ISR_TICK must be defined for each proc
269        if (isr_switch_index == 0xFFFFFFFF) 
270        {
271            _printf("\n[GIET ERROR] ISR_TICK not found for processor[%d,%d,%d]\n",
272                    x, y, lpid );
273            _exit();
274        }
275
276        // start system timer
277
278#if USE_XCU
279        _xcu_timer_start( cluster_xy, isr_switch_index, GIET_TICK_VALUE ); 
280#else
281        _timer_start( cluster_xy, isr_switch_index, GIET_TICK_VALUE ); 
282#endif
283
284    }
285
286#if GIET_DEBUG_INIT
287_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] starts TICK timer\n",
288        x, y, lpid );
289#endif
290
291    // step 6 : each processor updates the idle_task context:
292    //          (only CTX_SP, CTX_RA, CTX_EPC).
293    //          The stack size is 512 bytes, reserved in seg_kdata.
294    //          The PTPR register, the CTX_PTPR and CTX_PTAB slots
295    //          have been initialised in boot code.
296
297    unsigned int p = ((x * Y_SIZE) + y) * NB_PROCS_MAX + lpid; 
298
299    unsigned int stack = (unsigned int)_idle_stack + ((p + 1)<<9);
300
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
306_printf("\n[GIET DEBUG INIT] Processor[%d,%d,%d] initializes IDLE task\n",
307        x, y, lpid );
308#endif
309
310    // step 7 : when all processors reach the synchronisation barrier,
311    //          each processor set registers SP, SR, PTPR, EPC,
312    //          with the values corresponding to the first allocated task,
313    //          or to the idle_task if there is no task allocated,
314    //          and jump to user code
315
316    if (tasks == 0) 
317    {
318        ltid = IDLE_TASK_INDEX;
319
320        _printf("\n[GIET WARNING] No task allocated to processor[%d,%d,%d]\n",
321                x, y, lpid );
322    }
323    else
324    {
325        ltid = 0;
326    }
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
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
337
338    // increment barrier counter
339    _init_barrier++;
340
341    // busy waiting until all processors synchronized
342    while ( _init_barrier != NB_TOTAL_PROCS );
343
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)
353                   : "$29", "memory" );
354
355} // end kernel_init()
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.