source: soft/giet_vm/boot/boot_init.c @ 203

Last change on this file since 203 was 203, checked in by alain, 12 years ago

Introducing support for XICU

File size: 66.3 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : boot_init.c
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The boot_init.c file is part of the GIET-VM nano-kernel.
8// This code is executed in the boot phase by proc[0] to initialize the
9//  peripherals and the kernel data structures:
10// - pages tables for the various vspaces
11// - shedulers for processors (including the tasks contexts and interrupt vectors)
12//
13// The GIET-VM uses the paged virtual memory and the MAPPING_INFO binary file
14// to provides two services:
15// 1) classical memory protection, when several independant applications compiled
16//    in different virtual spaces are executing on the same hardware platform.
17// 2) data placement in NUMA architectures, when we want to control the placement
18//    of the software objects (virtual segments) on the physical memory banks.
19//
20// The MAPPING_INFO binary data structure must be loaded in the the seg_boot_mapping
21// segment (at address seg_mapping_base).
22// This MAPPING_INFO data structure defines both the hardware architecture
23// and the mapping:
24// - physical segmentation of the physical address space,
25// - virtual spaces definition (one multi-task application per vspace),
26// - placement of virtual objects (vobj) in the virtual segments (vseg).
27// - placement of virtual segments (vseg) in the physical segments (pseg).
28// - placement of tasks on the processors,
29//
30// The page table are statically build in the boot phase, and they do not
31// change during execution. The GIET uses only 4 Kbytes pages.
32// As most applications use only a limited number of segments, the number of PT2s
33// actually used by a given virtual space is generally smaller than 2048, and is
34// computed during the boot phase.
35// The max number of virtual spaces (GIET_NB_VSPACE_MAX) is a configuration parameter.
36//
37// Each page table (one page table per virtual space) is monolithic, and
38// contains one PT1 and (GIET_NB_PT2_MAX) PT2s. The PT1 is addressed using the ix1 field
39// (11 bits) of the VPN, and the selected PT2 is addressed using the ix2 field (9 bits).
40// - PT1[2048] : a first 8K aligned array of unsigned int, indexed by the (ix1) field of VPN.
41//   Each entry in the PT1 contains a 32 bits PTD. The MSB bit PTD[31] is
42//   the PTD valid bit, and LSB bits PTD[19:0] are the 20 MSB bits of the physical base
43//   address of the selected PT2.
44//   The PT1 contains 2048 PTD of 4 bytes => 8K bytes.
45// - PT2[1024][GIET_NB_PT2_MAX] : an array of array of unsigned int.
46//   Each PT2[1024] must be 4K aligned,  and each entry in a PT2 contains two unsigned int:
47//   the first word contains the protection flags, and the second word contains the PPN.
48//   Each PT2 contains 512 PTE2 of 8bytes => 4K bytes.
49// The total size of a page table is finally = 8K + (GIET_NB_PT2_MAX)*4K bytes.
50////////////////////////////////////////////////////////////////////////////////////
51
52#include <common.h>
53#include <mips32_registers.h>
54#include <giet_config.h>
55#include <mapping_info.h>
56#include <mwmr_channel.h>
57#include <barrier.h>
58#include <irq_handler.h>
59#include <ctx_handler.h>
60#include <vm_handler.h>
61#include <hwr_mapping.h>
62
63#include <stdarg.h>
64
65#if !defined(NB_CLUSTERS)
66# error The NB_CLUSTERS value must be defined in the 'giet_config.h' file !
67#endif
68
69#if !defined(NB_PROCS_MAX)
70# error The NB_PROCS_MAX value must be defined in the 'giet_config.h' file !
71#endif
72
73#if !defined(GIET_NB_VSPACE_MAX)
74# error The GIET_NB_VSPACE_MAX value must be defined in the 'giet_config.h' file !
75#endif
76
77////////////////////////////////////////////////////////////////////////////
78//      Global variables for boot code
79// As both the page tables and the schedulers are physically distributed,
80// these global variables are just arrays of pointers.
81////////////////////////////////////////////////////////////////////////////
82
83// Page table pointers array
84page_table_t*           boot_ptabs_vaddr[GIET_NB_VSPACE_MAX];
85page_table_t*           boot_ptabs_paddr[GIET_NB_VSPACE_MAX];
86
87// Scheduler pointers array
88static_scheduler_t*     boot_schedulers_paddr[NB_CLUSTERS * NB_PROCS_MAX];
89
90// Next free PT2 index array
91unsigned int            boot_next_free_pt2[GIET_NB_VSPACE_MAX] =
92                             { [0 ... GIET_NB_VSPACE_MAX-1] = 0 };
93
94// Max PT2 index
95unsigned int            boot_max_pt2[GIET_NB_VSPACE_MAX] =
96                            { [0 ... GIET_NB_VSPACE_MAX-1] = 0 };
97
98
99//////////////////////////////////////////////////////////////////////////////
100// boot_procid()
101//////////////////////////////////////////////////////////////////////////////
102inline unsigned int boot_procid()
103{
104    unsigned int ret;
105    asm volatile("mfc0 %0, $15, 1" : "=r"(ret));
106    return (ret & 0x3FF);
107}
108//////////////////////////////////////////////////////////////////////////////
109// boot_proctime()
110//////////////////////////////////////////////////////////////////////////////
111inline unsigned int boot_proctime()
112{
113    unsigned int ret;
114    asm volatile("mfc0 %0, $9" : "=r"(ret));
115    return ret;
116}
117//////////////////////////////////////////////////////////////////////////////
118// boot_exit()
119//////////////////////////////////////////////////////////////////////////////
120void boot_exit()
121{
122    while(1) asm volatile("nop");
123}
124//////////////////////////////////////////////////////////////////////////////
125// boot_eret()
126// The address of this function is used to initialise the return address (RA)
127// in all task contexts (when the task has never been executed.
128/////////////////////////////////"/////////////////////////////////////////////
129void boot_eret()
130{
131    asm volatile("eret");
132}
133//////////////////////////////////////////////////////////////////////////////
134// boot_scheduler_set_context()
135// This function set a context slot in a scheduler, after a temporary
136// desactivation of the DTLB (because we use the scheduler physical address).
137// - gpid   : global processor/scheduler index
138// - ltid   : local task index
139// - slotid : context slot index
140// - value  : value to be written
141//////////////////////////////////////////////////////////////////////////////
142inline void boot_scheduler_set_context( unsigned int gpid, 
143                                        unsigned int ltid, 
144                                        unsigned int slotid,
145                                        unsigned int value )
146{
147    // get scheduler physical address
148    static_scheduler_t*     psched = boot_schedulers_paddr[gpid];
149   
150    // get slot physical address
151    unsigned int*           pslot  = &(psched->context[ltid][slotid]);
152
153    asm volatile ( "li      $26,    0xB     \n"
154                   "mtc2    $26,    $1      \n"     /* desactivate DTLB */
155                   "sw      %1,     0(%0)   \n"     /* *pslot <= value  */
156                   "li      $26,    0xF     \n" 
157                   "mtc2    $26,    $1      \n"     /* activate DTLB    */
158                   : 
159                   : "r"(pslot), "r"(value) 
160                   : "$26" );
161}
162//////////////////////////////////////////////////////////////////////////////
163// boot_scheduler_set_itvector()
164// This function set an interrupt vector slot in a scheduler, after a temporary
165// desactivation of the DTLB (because we use the scheduler physical address).
166// - gpid   : global processor/scheduler index
167// - slotid : context slot index
168// - value  : value to be written
169//////////////////////////////////////////////////////////////////////////////
170inline void boot_scheduler_set_itvector( unsigned int gpid, 
171                                         unsigned int slotid,
172                                         unsigned int value )
173{
174    // get scheduler physical address
175    static_scheduler_t*     psched = boot_schedulers_paddr[gpid];
176   
177    // get slot physical address
178    unsigned int*           pslot  = &(psched->interrupt_vector[slotid]);
179
180    asm volatile ( "li      $26,    0xB     \n"
181                   "mtc2    $26,    $1      \n"     /* desactivate DTLB */
182                   "sw      %1,     0(%0)   \n"     /* *pslot <= value  */
183                   "li      $26,    0xF     \n" 
184                   "mtc2    $26,    $1      \n"     /* activate DTLB    */
185                   : 
186                   : "r"(pslot), "r"(value) 
187                   : "$26" );
188}
189//////////////////////////////////////////////////////////////////////////////
190// boot_scheduler_get_tasks()
191// This function returns the "tasks" field of a scheduler, after temporary
192// desactivation of the DTLB (because we use the scheduler physical address).
193// - gpid   : global processor/scheduler index
194//////////////////////////////////////////////////////////////////////////////
195inline unsigned int boot_scheduler_get_tasks( unsigned int gpid )
196{
197    unsigned int    ret; 
198
199    // get scheduler physical address
200    static_scheduler_t*     psched = boot_schedulers_paddr[gpid];
201   
202    // get tasks physical address
203    unsigned int*           ptasks = &(psched->tasks);
204
205    asm volatile ( "li      $26,    0xB     \n"
206                   "mtc2    $26,    $1      \n"     /* desactivate DTLB */
207                   "lw      %0,     0(%1)   \n"     /* ret <= *ptasks   */
208                   "li      $26,    0xF     \n" 
209                   "mtc2    $26,    $1      \n"     /* activate DTLB    */
210                   : "=r"(ret)
211                   : "r"(ptasks) 
212                   : "$26" );
213    return ret;
214}
215//////////////////////////////////////////////////////////////////////////////
216// boot_scheduler_set_tasks()
217// This function set the "tasks" field of a scheduler, after temporary
218// desactivation of the DTLB (because we use the scheduler physical address).
219// - gpid   : global processor/scheduler index
220// - value  : value to be written
221//////////////////////////////////////////////////////////////////////////////
222inline void boot_scheduler_set_tasks( unsigned int gpid,
223                                      unsigned int value )
224{
225    // get scheduler physical address
226    static_scheduler_t*     psched = boot_schedulers_paddr[gpid];
227   
228    // get tasks physical address
229    unsigned int*           ptasks = &(psched->tasks);
230
231    asm volatile ( "li      $26,    0xB     \n"
232                   "mtc2    $26,    $1      \n"     /* desactivate DTLB */
233                   "sw      %1,     0(%0)   \n"     /* *ptasks <= value */
234                   "li      $26,    0xF     \n" 
235                   "mtc2    $26,    $1      \n"     /* activate DTLB    */
236                   : 
237                   : "r"(ptasks), "r"(value) 
238                   : "$26" );
239}
240//////////////////////////////////////////////////////////////////////////////
241// boot_scheduler_set_current()
242// This function set the "current" field of a scheduler, after temporary
243// desactivation of the DTLB (because we use the scheduler physical address).
244// - gpid   : global processor/scheduler index
245// - value  : value to be written
246//////////////////////////////////////////////////////////////////////////////
247inline void boot_scheduler_set_current( unsigned int gpid,
248                                 unsigned int value )
249{
250    // get scheduler physical address
251    static_scheduler_t*     psched = boot_schedulers_paddr[gpid];
252   
253    // get tasks physical address
254    unsigned int*           pcur   = &(psched->current);
255
256    asm volatile ( "li      $26,    0xB     \n"
257                   "mtc2    $26,    $1      \n"     /* desactivate DTLB */
258                   "sw      %1,     0(%0)   \n"     /* *pcur   <= value */
259                   "li      $26,    0xF     \n" 
260                   "mtc2    $26,    $1      \n"     /* activate DTLB    */
261                   : 
262                   : "r"(pcur), "r"(value) 
263                   : "$26" );
264}
265//////////////////////////////////////////////////////////////////////////////
266// boot_set_mmu_ptpr()
267// This function set a new value for the MMU PTPR register.
268//////////////////////////////////////////////////////////////////////////////
269inline void boot_set_mmu_ptpr( unsigned int val )
270{
271    asm volatile("mtc2  %0, $0" : : "r"(val) );
272}
273
274//////////////////////////////////////////////////////////////////////////////
275// boot_set_mmu_mode()
276// This function set a new value for the MMU MODE register.
277//////////////////////////////////////////////////////////////////////////////
278inline void boot_set_mmu_mode( unsigned int val )
279{
280    asm volatile("mtc2  %0, $1" : : "r"(val) );
281}
282////////////////////////////////////////////////////////////////////////////
283// boot_puts()
284// (it uses TTY0)
285////////////////////////////////////////////////////////////////////////////
286void boot_puts(const char *buffer) 
287{
288    unsigned int* tty_address = (unsigned int*)&seg_tty_base;
289    unsigned int n;
290
291    for ( n=0; n<100; n++)
292    {
293        if (buffer[n] == 0) break;
294        tty_address[0] = (unsigned int)buffer[n];
295    }
296   
297} 
298////////////////////////////////////////////////////////////////////////////
299// boot_putw()
300// (it uses TTY0)
301////////////////////////////////////////////////////////////////////////////
302void boot_putw(unsigned int val)
303{
304    static const char   HexaTab[] = "0123456789ABCDEF";
305    char                buf[11];
306    unsigned int        c;
307
308    buf[0]  = '0';
309    buf[1]  = 'x';
310    buf[10] = 0;
311
312    for ( c = 0 ; c < 8 ; c++ )
313    { 
314        buf[9-c] = HexaTab[val&0xF];
315        val = val >> 4;
316    }
317    boot_puts(buf);
318}
319
320/////////////////////////////////////////////////////////////////////////////
321//  mapping_info data structure access functions
322/////////////////////////////////////////////////////////////////////////////
323inline mapping_cluster_t* boot_get_cluster_base( mapping_header_t* header )
324{
325    return   (mapping_cluster_t*) ((char*)header +
326                                  MAPPING_HEADER_SIZE);
327}
328/////////////////////////////////////////////////////////////////////////////
329inline mapping_pseg_t* boot_get_pseg_base( mapping_header_t* header )
330{
331    return   (mapping_pseg_t*)    ((char*)header +
332                                  MAPPING_HEADER_SIZE +
333                                  MAPPING_CLUSTER_SIZE*header->clusters);
334}
335/////////////////////////////////////////////////////////////////////////////
336inline mapping_vspace_t* boot_get_vspace_base( mapping_header_t* header )
337{
338    return   (mapping_vspace_t*)  ((char*)header +
339                                  MAPPING_HEADER_SIZE +
340                                  MAPPING_CLUSTER_SIZE*header->clusters +
341                                  MAPPING_PSEG_SIZE*header->psegs);
342}
343/////////////////////////////////////////////////////////////////////////////
344inline mapping_vseg_t* boot_get_vseg_base( mapping_header_t* header )
345{
346    return   (mapping_vseg_t*)    ((char*)header +
347                                  MAPPING_HEADER_SIZE +
348                                  MAPPING_CLUSTER_SIZE*header->clusters +
349                                  MAPPING_PSEG_SIZE*header->psegs +
350                                  MAPPING_VSPACE_SIZE*header->vspaces);
351}
352/////////////////////////////////////////////////////////////////////////////
353inline mapping_vobj_t* boot_get_vobj_base( mapping_header_t* header )
354{
355    return   (mapping_vobj_t*)   ((char*)header +
356                                  MAPPING_HEADER_SIZE +
357                                  MAPPING_CLUSTER_SIZE*header->clusters +
358                                  MAPPING_PSEG_SIZE*header->psegs +
359                                  MAPPING_VSPACE_SIZE*header->vspaces +
360                                  MAPPING_VSEG_SIZE*header->vsegs );
361}
362/////////////////////////////////////////////////////////////////////////////
363inline mapping_task_t* boot_get_task_base( mapping_header_t* header )
364{
365    return   (mapping_task_t*)    ((char*)header +
366                                  MAPPING_HEADER_SIZE +
367                                  MAPPING_CLUSTER_SIZE*header->clusters +
368                                  MAPPING_PSEG_SIZE*header->psegs +
369                                  MAPPING_VSPACE_SIZE*header->vspaces +
370                                  MAPPING_VSEG_SIZE*header->vsegs +
371                                  MAPPING_VOBJ_SIZE*header->vobjs );
372}
373/////////////////////////////////////////////////////////////////////////////
374inline mapping_proc_t* boot_get_proc_base( mapping_header_t* header )
375{
376    return   (mapping_proc_t*)    ((char*)header +
377                                  MAPPING_HEADER_SIZE +
378                                  MAPPING_CLUSTER_SIZE*header->clusters +
379                                  MAPPING_PSEG_SIZE*header->psegs +
380                                  MAPPING_VSPACE_SIZE*header->vspaces +
381                                  MAPPING_VSEG_SIZE*header->vsegs +
382                                  MAPPING_VOBJ_SIZE*header->vobjs +
383                                  MAPPING_TASK_SIZE*header->tasks );
384}
385/////////////////////////////////////////////////////////////////////////////
386inline mapping_irq_t* boot_get_irq_base( mapping_header_t* header )
387{
388    return   (mapping_irq_t*)     ((char*)header +
389                                  MAPPING_HEADER_SIZE +
390                                  MAPPING_CLUSTER_SIZE*header->clusters +
391                                  MAPPING_PSEG_SIZE*header->psegs +
392                                  MAPPING_VSPACE_SIZE*header->vspaces +
393                                  MAPPING_VSEG_SIZE*header->vsegs +
394                                  MAPPING_VOBJ_SIZE*header->vobjs +
395                                  MAPPING_TASK_SIZE*header->tasks +
396                                  MAPPING_PROC_SIZE*header->procs );
397}
398/////////////////////////////////////////////////////////////////////////////
399inline mapping_coproc_t* boot_get_coproc_base( mapping_header_t* header )
400{
401    return  (mapping_coproc_t*)   ((char*)header +
402                                  MAPPING_HEADER_SIZE +
403                                  MAPPING_CLUSTER_SIZE*header->clusters +
404                                  MAPPING_PSEG_SIZE*header->psegs +
405                                  MAPPING_VSPACE_SIZE*header->vspaces +
406                                  MAPPING_VOBJ_SIZE*header->vobjs +
407                                  MAPPING_VSEG_SIZE*header->vsegs +
408                                  MAPPING_TASK_SIZE*header->tasks +
409                                  MAPPING_PROC_SIZE*header->procs +
410                                  MAPPING_IRQ_SIZE*header->irqs );
411}
412///////////////////////////////////////////////////////////////////////////////////
413inline mapping_cp_port_t* boot_get_cp_port_base( mapping_header_t* header )
414{
415    return (mapping_cp_port_t*)   ((char*)header +
416                                  MAPPING_HEADER_SIZE +
417                                  MAPPING_CLUSTER_SIZE*header->clusters +
418                                  MAPPING_PSEG_SIZE*header->psegs +
419                                  MAPPING_VSPACE_SIZE*header->vspaces +
420                                  MAPPING_VOBJ_SIZE*header->vobjs +
421                                  MAPPING_VSEG_SIZE*header->vsegs +
422                                  MAPPING_TASK_SIZE*header->tasks +
423                                  MAPPING_PROC_SIZE*header->procs +
424                                  MAPPING_IRQ_SIZE*header->irqs +
425                                  MAPPING_COPROC_SIZE*header->coprocs );
426}
427///////////////////////////////////////////////////////////////////////////////////
428inline mapping_periph_t* boot_get_periph_base( mapping_header_t* header )
429{
430    return (mapping_periph_t*)    ((char*)header +
431                                  MAPPING_HEADER_SIZE +
432                                  MAPPING_CLUSTER_SIZE*header->clusters +
433                                  MAPPING_PSEG_SIZE*header->psegs +
434                                  MAPPING_VSPACE_SIZE*header->vspaces +
435                                  MAPPING_VOBJ_SIZE*header->vobjs +
436                                  MAPPING_VSEG_SIZE*header->vsegs +
437                                  MAPPING_TASK_SIZE*header->tasks +
438                                  MAPPING_PROC_SIZE*header->procs +
439                                  MAPPING_IRQ_SIZE*header->irqs +
440                                  MAPPING_COPROC_SIZE*header->coprocs +
441                                  MAPPING_CP_PORT_SIZE*header->cp_ports );
442}
443
444//////////////////////////////////////////////////////////////////////////////
445//     boot_pseg_get()
446// This function returns the pointer on a physical segment
447// identified  by the pseg index.
448//////////////////////////////////////////////////////////////////////////////
449mapping_pseg_t* boot_pseg_get( unsigned int seg_id)
450{
451    mapping_header_t* header = (mapping_header_t*)&seg_mapping_base;
452    mapping_pseg_t*   pseg   = boot_get_pseg_base( header );
453
454    // checking argument
455    if ( seg_id >= header->psegs )
456    {
457        boot_puts("\n[BOOT ERROR] : seg_id argument too large\n");
458        boot_puts("               in function boot_pseg_get()\n");
459        boot_exit();
460    }
461
462    return &pseg[seg_id];                                   
463} // end boot_pseg_get()
464
465//////////////////////////////////////////////////////////////////////////////
466// boot_add_pte()
467// This function registers a new PTE in the page table pointed
468// by the vspace_id argument, and updates both PT1 and PT2.
469// A new PT2 is used when required.
470// As the set of PT2s is implemented as a fixed size array (no dynamic
471// allocation), this function checks a possible overflow of the PT2 array.
472//
473// The global parameter is a boolean indicating wether a global vseg is
474// being mapped.
475//////////////////////////////////////////////////////////////////////////////
476void boot_add_pte( unsigned int    vspace_id,   
477                   unsigned int    vpn,           
478                   unsigned int    flags,
479                   unsigned int    ppn )
480{
481    unsigned int    ix1;
482    unsigned int    ix2;
483    unsigned int    ptba;       // PT2 base address
484    unsigned int    pt2_id;     // PT2 index
485    unsigned int*   pt_flags;   // pointer on the pte_flags = &PT2[2*ix2]   
486    unsigned int*   pt_ppn;     // pointer on the pte_ppn   = &PT2[2*ix2+1] 
487
488    ix1 = vpn >> 9;             // 11 bits
489    ix2 = vpn  & 0x1FF;         //  9 bits
490
491    // check that the boot_max_pt2[vspace_id] has been set
492    unsigned int max_pt2   = boot_max_pt2[vspace_id];
493
494    if(max_pt2 == 0)
495    {
496        boot_puts("Unfound page table for vspace ");
497        boot_putw(vspace_id);
498        boot_puts("\n");
499        boot_exit();
500    }
501
502    // get page table physical address
503    page_table_t* pt = boot_ptabs_paddr[vspace_id];
504
505    if ( (pt->pt1[ix1] & PTE_V) == 0 )   // set a new PTD in PT1
506    {
507        pt2_id = boot_next_free_pt2[vspace_id];
508        if ( pt2_id == max_pt2 )
509        {
510            boot_puts("\n[BOOT ERROR] in boot_add_pte() function\n");
511            boot_puts("the length of the ptab vobj is too small\n"); 
512            boot_exit();
513        }
514        else
515        {
516            ptba = (unsigned int)pt + PT1_SIZE + PT2_SIZE*pt2_id;
517            pt->pt1[ix1] = PTE_V | PTE_T | (ptba >> 12);   
518            boot_next_free_pt2[vspace_id] = pt2_id + 1;
519        }
520    }
521    else
522    {
523        ptba = pt->pt1[ix1] << 12;
524    }
525
526    // set PTE2 after checking double mapping error
527    pt_flags = (unsigned int*)(ptba + 8*ix2);
528    pt_ppn   = (unsigned int*)(ptba + 8*ix2 + 4);
529
530    if ( ( *pt_flags & PTE_V) != 0 )    // page already mapped
531    {
532        boot_puts("\n[BOOT ERROR] in boot_add_pte() function\n");
533        boot_puts("page already mapped\n");
534        boot_exit();
535    }
536
537    // set PTE2
538    *pt_flags = flags;
539    *pt_ppn   = ppn;
540
541} // end boot_add_pte()
542               
543/////////////////////////////////////////////////////////////////////
544// This function build the page table for a given vspace.
545// The physical base addresses for all vsegs (global and private)
546// must have been previously computed.
547// It initializes the MWMR channels.
548/////////////////////////////////////////////////////////////////////
549void boot_vspace_pt_build( unsigned int vspace_id )
550{
551    unsigned int    vseg_id;
552    unsigned int    npages;
553    unsigned int    ppn;
554    unsigned int    vpn;
555    unsigned int    flags;
556    unsigned int    page_id;
557
558    mapping_header_t*  header = (mapping_header_t*)&seg_mapping_base; 
559    mapping_vspace_t*  vspace = boot_get_vspace_base( header );
560    mapping_vseg_t*    vseg   = boot_get_vseg_base( header );
561   
562    // private segments
563    for ( vseg_id = vspace[vspace_id].vseg_offset ; 
564          vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs) ; 
565          vseg_id++ )
566    {
567        vpn       = vseg[vseg_id].vbase >> 12;
568        ppn       = vseg[vseg_id].pbase >> 12;
569        npages    = vseg[vseg_id].length >> 12;
570        if ( (vseg[vseg_id].length & 0xFFF) != 0 ) npages++;
571
572        flags = PTE_V;
573        if ( vseg[vseg_id].mode & C_MODE_MASK )  flags = flags | PTE_C;
574        if ( vseg[vseg_id].mode & X_MODE_MASK )  flags = flags | PTE_X;
575        if ( vseg[vseg_id].mode & W_MODE_MASK )  flags = flags | PTE_W;
576        if ( vseg[vseg_id].mode & U_MODE_MASK )  flags = flags | PTE_U;
577
578#if BOOT_DEBUG_PT
579boot_puts( vseg[vseg_id].name );
580boot_puts(" : flags = ");
581boot_putw( flags );
582boot_puts(" / npages = ");
583boot_putw( npages );
584boot_puts(" / pbase = ");
585boot_putw( vseg[vseg_id].pbase );
586boot_puts("\n");
587#endif       
588        // loop on 4K pages
589        for ( page_id = 0 ; page_id < npages ; page_id++ )
590        {
591            boot_add_pte( vspace_id,
592                          vpn,
593                          flags,
594                          ppn );
595            vpn++;
596            ppn++;
597        }
598    }
599
600    // global segments
601    for ( vseg_id = 0 ; vseg_id < header->globals ; vseg_id++ )
602    {
603        vpn       = vseg[vseg_id].vbase >> 12;
604        ppn       = vseg[vseg_id].pbase >> 12;
605        npages    = vseg[vseg_id].length >> 12;
606        if ( (vseg[vseg_id].length & 0xFFF) != 0 ) npages++;
607
608        flags = PTE_V;
609        if ( vseg[vseg_id].mode & C_MODE_MASK )  flags = flags | PTE_C;
610        if ( vseg[vseg_id].mode & X_MODE_MASK )  flags = flags | PTE_X;
611        if ( vseg[vseg_id].mode & W_MODE_MASK )  flags = flags | PTE_W;
612        if ( vseg[vseg_id].mode & U_MODE_MASK )  flags = flags | PTE_U;
613
614#if BOOT_DEBUG_PT
615boot_puts( vseg[vseg_id].name );
616boot_puts(" / flags = ");
617boot_putw( flags );
618boot_puts(" / npages = ");
619boot_putw( npages );
620boot_puts(" / pbase = ");
621boot_putw( vseg[vseg_id].pbase );
622boot_puts("\n");
623#endif       
624        // loop on 4K pages
625        for ( page_id = 0 ; page_id < npages ; page_id++ )
626        {
627            boot_add_pte( vspace_id,
628                          vpn,
629                          flags,
630                          ppn );
631            vpn++;
632            ppn++;
633        }
634    }
635
636} // end boot_vspace_pt_build()
637
638///////////////////////////////////////////////////////////////////////////
639// Align the value "toAlign" to the required alignement indicated by
640// alignPow2 ( the logarithme of 2 the alignement).
641///////////////////////////////////////////////////////////////////////////
642unsigned int align_to( unsigned int toAlign, 
643                       unsigned int alignPow2)
644{
645    unsigned int    mask = (1 << alignPow2) - 1;
646    return ((toAlign + mask ) & ~mask ); 
647}
648
649///////////////////////////////////////////////////////////////////////////
650// This function compute the physical base address for a vseg
651// as specified in the mapping info data structure.
652// It updates the pbase and the length fields of the vseg.
653// It updates the pbase and vbase fields of all vobjs in the vseg.
654// It updates the next_base field of the pseg, and checks overflow.
655// It updates the boot_ptabs_paddr[] and boot_ptabs_vaddr[] arrays.
656// It is a global vseg if vspace_id = (-1).
657///////////////////////////////////////////////////////////////////////////
658void boot_vseg_map( mapping_vseg_t*     vseg, 
659                    unsigned int        vspace_id ) 
660{
661    unsigned int        vobj_id;
662    unsigned int        cur_vaddr;
663    unsigned int        cur_paddr;
664    mapping_header_t*   header = (mapping_header_t*)&seg_mapping_base; 
665    mapping_vobj_t*     vobj   = boot_get_vobj_base( header );
666 
667    // get physical segment pointer
668    mapping_pseg_t*  pseg = boot_pseg_get( vseg->psegid );
669
670    // compute vseg physical base address
671    if ( vseg->ident != 0 )            // identity mapping required
672    {
673         vseg->pbase = vseg->vbase;
674    }
675    else                                // unconstrained mapping
676    {
677        vseg->pbase = pseg->next_base;
678
679        // test alignment constraint
680        if ( vobj[vseg->vobj_offset].align )
681        {
682            vseg->pbase = align_to( vseg->pbase, vobj[vseg->vobj_offset].align );
683        }
684    }
685   
686    // loop on vobjs contained in vseg to :
687    // (1) computes the length of the vseg,
688    // (2) initialise the vaddr and paddr fields of all vobjs,
689    // (3) initialise the page table pointers arrays
690
691    cur_vaddr = vseg->vbase;
692    cur_paddr = vseg->pbase;
693
694    for( vobj_id = vseg->vobj_offset; 
695         vobj_id < (vseg->vobj_offset + vseg->vobjs); 
696         vobj_id++)
697    {
698        if ( vobj[vobj_id].align )
699        {
700            cur_paddr = align_to(cur_paddr, vobj[vobj_id].align);
701        }
702
703        // set vaddr/paddr for current vobj
704        vobj[vobj_id].vaddr = cur_vaddr;       
705        vobj[vobj_id].paddr = cur_paddr; 
706     
707        // initialise boot_ptabs_vaddr[] if current vobj is a PTAB
708        if ( vobj[vobj_id].type == VOBJ_TYPE_PTAB )
709        {
710            if(vspace_id == ((unsigned int) -1))    // global vseg
711            {
712                boot_puts( "\n[BOOT ERROR] in boot_vseg_map() function: " );
713                boot_puts( "a PTAB vobj cannot be global" );
714                boot_exit();
715            }
716
717            // we need at least one PT2 => ( boot_max_pt2[vspace_id] >= 1)
718            if(vobj[vobj_id].length < (PT1_SIZE + PT2_SIZE) ) 
719            {
720                boot_puts( "\n[BOOT ERROR] in boot_vseg_map() function, " );
721                boot_puts("PTAB too small, minumum size is: ");
722                boot_putw( PT1_SIZE + PT2_SIZE);
723                boot_exit();
724            }
725
726            // register both physical and virtual page table address
727            boot_ptabs_vaddr[vspace_id] = (page_table_t*)vobj[vobj_id].vaddr;
728            boot_ptabs_paddr[vspace_id] = (page_table_t*)vobj[vobj_id].paddr;
729
730            /* computing the number of second level page */
731            boot_max_pt2[vspace_id] = (vobj[vobj_id].length - PT1_SIZE) / PT2_SIZE;
732        }
733
734        // set next vaddr/paddr
735        cur_vaddr += vobj[vobj_id].length;
736        cur_paddr += vobj[vobj_id].length; 
737
738    } // end for vobjs
739   
740    //set the vseg length
741    vseg->length = align_to( (cur_paddr - vseg->pbase), 12);
742
743    // checking pseg overflow
744    if ( (vseg->pbase < pseg->base) || 
745         ((vseg->pbase + vseg->length) > (pseg->base + pseg->length)) )
746    {
747        boot_puts("\n[BOOT ERROR] in boot_vseg_map() function\n");
748        boot_puts("impossible mapping for virtual segment: ");
749        boot_puts( vseg->name ); 
750        boot_puts("\n"); 
751        boot_puts("vseg pbase = ");
752        boot_putw( vseg->pbase ); 
753        boot_puts("\n"); 
754        boot_puts("vseg length = ");
755        boot_putw( vseg->length ); 
756        boot_puts("\n"); 
757        boot_puts("pseg pbase = ");
758        boot_putw( pseg->base ); 
759        boot_puts("\n"); 
760        boot_puts("pseg length = ");
761        boot_putw( pseg->length ); 
762        boot_puts("\n"); 
763        boot_exit();
764    }
765
766    // set the next_base field in vseg
767    if ( vseg->ident == 0 )
768        pseg->next_base = vseg->pbase + vseg->length;
769
770#if BOOT_DEBUG_PT
771boot_puts( vseg->name );
772boot_puts(" : len = ");
773boot_putw( vseg->length );
774boot_puts(" / vbase = ");
775boot_putw( vseg->vbase );
776boot_puts(" / pbase = ");
777boot_putw( vseg->pbase );
778boot_puts("\n");
779#endif 
780
781} // end boot_vseg_map()
782
783/////////////////////////////////////////////////////////////////////
784// This function checks consistence beween the  mapping_info data
785// structure (soft), and the giet_config file (hard).
786/////////////////////////////////////////////////////////////////////
787void boot_check_mapping()
788{
789    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
790    mapping_cluster_t*  cluster = boot_get_cluster_base( header ); 
791    mapping_periph_t*   periph  = boot_get_periph_base( header );
792
793    // checking mapping availability
794    if ( header->signature != IN_MAPPING_SIGNATURE )
795    {
796        boot_puts("\n[BOOT ERROR] Illegal mapping signature: ");
797        boot_putw(header->signature);
798        boot_puts("\n");
799        boot_exit();
800    }
801
802    // checking number of clusters
803    if ( header->clusters != NB_CLUSTERS )
804    {
805        boot_puts("\n[BOOT ERROR] Incoherent NB_CLUSTERS");
806        boot_puts("\n             - In giet_config,  value = ");
807        boot_putw ( NB_CLUSTERS );
808        boot_puts("\n             - In mapping_info, value = ");
809        boot_putw ( header->clusters );
810        boot_puts("\n");
811        boot_exit();
812    }
813
814    // checking number of virtual spaces
815    if ( header->vspaces > GIET_NB_VSPACE_MAX )
816    {
817        boot_puts("\n[BOOT ERROR] : number of vspaces > GIET_NB_VSPACE_MAX\n");
818        boot_puts("\n");
819        boot_exit();
820    }
821
822    // checking hardware
823    unsigned int periph_id;
824    unsigned int cluster_id;
825    unsigned int channels;
826    unsigned int tty_found = 0;
827    unsigned int nic_found = 0;
828    for ( cluster_id = 0 ; cluster_id < NB_CLUSTERS ; cluster_id++ )
829    {
830        // NB_PROCS_MAX
831        if ( cluster[cluster_id].procs > NB_PROCS_MAX )
832        {
833            boot_puts("\n[BOOT ERROR] too much processors in cluster ");
834            boot_putw( cluster_id );
835            boot_puts(" : procs = ");
836            boot_putw ( cluster[cluster_id].procs );
837            boot_puts("\n");
838            boot_exit();
839        }
840
841        for ( periph_id = cluster[cluster_id].periph_offset ;
842              periph_id < cluster[cluster_id].periph_offset + cluster[cluster_id].periphs ;
843              periph_id++ )
844        {
845            // NB_TTYS
846            if ( periph[periph_id].type == PERIPH_TYPE_TTY ) 
847            {
848                if ( tty_found )
849                {
850                    boot_puts("\n[BOOT ERROR] TTY component should not be replicated\n");
851                    boot_exit();
852                }
853                if ( periph[periph_id].channels != NB_TTYS )
854                {
855                    boot_puts("\n[BOOT ERROR] Wrong NB_TTYS in cluster ");
856                    boot_putw( cluster_id );
857                    boot_puts(" : ttys = ");
858                    boot_putw ( periph[periph_id].channels );
859                    boot_puts("\n");
860                    boot_exit();
861                }
862                tty_found = 1;
863            }
864            // NB_NICS
865            if ( periph[periph_id].type == PERIPH_TYPE_NIC ) 
866            {
867                if ( nic_found )
868                {
869                    boot_puts("\n[BOOT ERROR] NIC component should not be replicated\n");
870                    boot_exit();
871                }
872                if ( periph[periph_id].channels != NB_NICS )
873                {
874                    boot_puts("\n[BOOT ERROR] Wrong NB_NICS in cluster ");
875                    boot_putw( cluster_id );
876                    boot_puts(" : nics = ");
877                    boot_putw ( periph[periph_id].channels );
878                    boot_puts("\n");
879                    boot_exit();
880                }
881                nic_found = 1;
882            }
883            // NB_TIMERS
884            if ( periph[periph_id].type == PERIPH_TYPE_TIM ) 
885            {
886                if ( periph[periph_id].channels != (NB_PROCS_MAX + NB_TIMERS_MAX) )
887                {
888                    boot_puts("\n[BOOT ERROR] Too much user timers in cluster ");
889                    boot_putw( cluster_id );
890                    boot_puts(" : timers = ");
891                    boot_putw ( periph[periph_id].channels );
892                    boot_puts("\n");
893                    boot_exit();
894                }
895            }
896            // NB_DMAS
897            if ( periph[periph_id].type == PERIPH_TYPE_DMA ) 
898            {
899                if ( periph[periph_id].channels != NB_DMAS_MAX )
900                {
901                    boot_puts("\n[BOOT ERROR] Too much DMA channels in cluster ");
902                    boot_putw( cluster_id );
903                    boot_puts(" : channels = ");
904                    boot_putw ( periph[periph_id].channels );
905                    boot_puts("\n");
906                    boot_exit();
907                }
908            }
909        } // end for periphs
910    } // end for clusters
911} // end boot_check_mapping()
912
913/////////////////////////////////////////////////////////////////////
914// This function initialises the physical pages table allocators
915// for all psegs (i.e. next_base field of the pseg).
916// In each cluster containing processors, it reserve space for the
917// schedulers in the first RAM pseg found (4k bytes per processor).
918/////////////////////////////////////////////////////////////////////
919void boot_psegs_init()
920{
921    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
922
923    mapping_cluster_t*  cluster = boot_get_cluster_base( header ); 
924    mapping_pseg_t*     pseg    = boot_get_pseg_base( header ); 
925
926    unsigned int cluster_id;
927    unsigned int pseg_id;
928    unsigned int found;
929
930#if BOOT_DEBUG_PT
931boot_puts("\n[BOOT DEBUG] ****** psegs allocators nitialisation ******\n");
932#endif
933
934    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
935    {
936        if ( cluster[cluster_id].procs > NB_PROCS_MAX )
937        {
938            boot_puts("\n[BOOT ERROR] The number of processors in cluster ");
939            boot_putw( cluster_id );
940            boot_puts(" is larger than NB_PROCS_MAX \n");
941            boot_exit();
942        }
943
944        found    = 0;
945
946        for ( pseg_id = cluster[cluster_id].pseg_offset ;
947              pseg_id < cluster[cluster_id].pseg_offset + cluster[cluster_id].psegs ;
948              pseg_id++ )
949        {
950            unsigned int free = pseg[pseg_id].base;
951
952            if ( (pseg[pseg_id].type == PSEG_TYPE_RAM) && (found == 0) )
953            {
954                free = free + (cluster[cluster_id].procs << 12);
955                found = 1;
956            }
957            pseg[pseg_id].next_base = free;
958
959#if BOOT_DEBUG_PT
960boot_puts("cluster ");
961boot_putw(cluster_id);
962boot_puts(" / pseg ");
963boot_puts(pseg[pseg_id].name);
964boot_puts(" : next_base = ");
965boot_putw(pseg[pseg_id].next_base);
966boot_puts("\n");
967#endif
968        }
969    }
970} // end boot_pseg_init()
971
972/////////////////////////////////////////////////////////////////////
973// This function builds the page tables for all virtual spaces
974// defined in the mapping_info data structure.
975// For each virtual space, it maps both the global vsegs
976// (replicated in all vspaces), and the private vsegs.
977/////////////////////////////////////////////////////////////////////
978void boot_pt_init()
979{
980    mapping_header_t*   header = (mapping_header_t*)&seg_mapping_base; 
981
982    mapping_vspace_t*   vspace = boot_get_vspace_base( header );     
983    mapping_vseg_t*     vseg   = boot_get_vseg_base( header );
984
985    unsigned int        vspace_id; 
986    unsigned int        vseg_id;
987
988#if BOOT_DEBUG_PT
989boot_puts("\n[BOOT DEBUG] ****** mapping global vsegs ******\n");
990#endif
991           
992    // step 1 : first loop on virtual spaces to map global vsegs
993    for ( vseg_id = 0 ; vseg_id < header->globals ; vseg_id++ )
994    {
995        boot_vseg_map( &vseg[vseg_id], ((unsigned int)(-1)) );
996    }
997
998    // step 2 : loop on virtual vspaces to map private vsegs
999    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1000    {
1001
1002#if BOOT_DEBUG_PT
1003boot_puts("\n[BOOT DEBUG] ****** mapping private vsegs in vspace ");
1004boot_puts(vspace[vspace_id].name);
1005boot_puts(" ******\n");
1006#endif
1007           
1008        for ( vseg_id = vspace[vspace_id].vseg_offset ; 
1009              vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs) ; 
1010              vseg_id++ )
1011        {
1012            boot_vseg_map( &vseg[vseg_id], vspace_id ); 
1013        }
1014    } 
1015
1016    // step 3 : loop on the vspaces to build the page tables
1017    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1018    {
1019
1020#if BOOT_DEBUG_PT
1021boot_puts("\n[BOOT DEBUG] ****** building page table for vspace ");
1022boot_puts(vspace[vspace_id].name);
1023boot_puts(" ******\n");
1024#endif
1025           
1026        boot_vspace_pt_build( vspace_id );
1027
1028#if BOOT_DEBUG_PT
1029boot_puts("\n>>> page table physical address = ");
1030boot_putw((unsigned int)boot_ptabs_paddr[vspace_id]);
1031boot_puts(", page table number of PT2 = ");
1032boot_putw((unsigned int)boot_max_pt2[vspace_id]);
1033boot_puts("\n");
1034#endif
1035    } 
1036} // end boot_pt_init()
1037
1038///////////////////////////////////////////////////////////////////////////////
1039// This function initializes all private vobjs defined in the vspaces,
1040// such as mwmr channels, barriers and locks, because these vobjs
1041// are not known, and not initialised by the compiler.
1042///////////////////////////////////////////////////////////////////////////////
1043void boot_vobjs_init()
1044{
1045    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
1046    mapping_vspace_t*   vspace  = boot_get_vspace_base( header );     
1047    mapping_vobj_t*     vobj    = boot_get_vobj_base( header );
1048
1049    unsigned int        vspace_id; 
1050    unsigned int        vobj_id;
1051
1052    // loop on the vspaces
1053    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1054    {
1055
1056#if BOOT_DEBUG_VOBJS
1057boot_puts("\n[BOOT DEBUG] ****** vobjs initialisation in vspace "); 
1058boot_puts(vspace[vspace_id].name);
1059boot_puts(" ******\n");
1060#endif
1061
1062        unsigned int ptab_found = 0;
1063
1064        // loop on the vobjs
1065            for(vobj_id= vspace[vspace_id].vobj_offset; 
1066                        vobj_id < (vspace[vspace_id].vobj_offset+ vspace[vspace_id].vobjs);
1067                        vobj_id++)
1068            {
1069            switch( vobj[vobj_id].type )
1070            {
1071                case VOBJ_TYPE_MWMR:    // storage capacity is (vobj.length/4 - 5) words
1072                        {
1073                    mwmr_channel_t* mwmr = (mwmr_channel_t*)(vobj[vobj_id].paddr);
1074                    mwmr->ptw   = 0;
1075                    mwmr->ptr   = 0;
1076                    mwmr->sts   = 0;
1077                    mwmr->width = vobj[vobj_id].init;
1078                    mwmr->depth = (vobj[vobj_id].length>>2) - 6;
1079                    mwmr->lock  = 0;
1080#if BOOT_DEBUG_VOBJS
1081boot_puts("MWMR    : ");
1082boot_puts( vobj[vobj_id].name);
1083boot_puts(" / depth = ");
1084boot_putw( mwmr->depth );
1085boot_puts(" / width = ");
1086boot_putw( mwmr->width );
1087boot_puts("\n");
1088#endif
1089                    break;
1090                }
1091                case VOBJ_TYPE_ELF:             // initialisation done by the loader
1092                {
1093#if BOOT_DEBUG_VOBJS
1094boot_puts("ELF     : ");
1095boot_puts( vobj[vobj_id].name);
1096boot_puts(" / length = ");
1097boot_putw( vobj[vobj_id].length ); 
1098boot_puts("\n");
1099#endif
1100                    break;
1101                }
1102                case VOBJ_TYPE_BLOB:            // initialisation done by the loader
1103                {
1104#if BOOT_DEBUG_VOBJS
1105boot_puts("BLOB     : ");
1106boot_puts( vobj[vobj_id].name);
1107boot_puts(" / length = ");
1108boot_putw( vobj[vobj_id].length ); 
1109boot_puts("\n");
1110#endif
1111                    break;
1112                }
1113                case VOBJ_TYPE_BARRIER: // init is the number of participants
1114                {
1115                    giet_barrier_t* barrier = (giet_barrier_t*)(vobj[vobj_id].paddr);
1116                    barrier->count = 0;
1117                    barrier->init  = vobj[vobj_id].init;
1118#if BOOT_DEBUG_VOBJS
1119boot_puts("BARRIER : ");
1120boot_puts( vobj[vobj_id].name);
1121boot_puts(" / init_value = ");
1122boot_putw( barrier->init );
1123boot_puts("\n");
1124#endif
1125                    break;
1126                }
1127                case VOBJ_TYPE_LOCK:    // init is "not taken"
1128                {
1129                    unsigned int* lock = (unsigned int*)(vobj[vobj_id].paddr);
1130                    *lock = 0;
1131#if BOOT_DEBUG_VOBJS
1132boot_puts("LOCK    : ");
1133boot_puts( vobj[vobj_id].name);
1134boot_puts("\n");
1135#endif
1136                    break;
1137                }
1138                case VOBJ_TYPE_BUFFER:  // nothing to initialise
1139                {
1140#if BOOT_DEBUG_VOBJS
1141boot_puts("BUFFER  : ");
1142boot_puts( vobj[vobj_id].name);
1143boot_puts(" / length = ");
1144boot_putw( vobj[vobj_id].length ); 
1145boot_puts("\n");
1146#endif
1147                    break;
1148                }
1149                case VOBJ_TYPE_PTAB:    // nothing to initialise
1150                {
1151                    ptab_found = 1;
1152#if BOOT_DEBUG_VOBJS
1153boot_puts("PTAB    : ");
1154boot_puts( vobj[vobj_id].name);
1155boot_puts(" / length = ");
1156boot_putw( vobj[vobj_id].length ); 
1157boot_puts("\n");
1158#endif
1159                    break;
1160                }
1161                default:
1162                {
1163                    boot_puts("\n[INIT ERROR] illegal vobj of name ");
1164                    boot_puts(vobj->name);
1165                    boot_puts(" / in vspace = ");
1166                    boot_puts(vobj->name);
1167                    boot_puts("\n ");
1168                    boot_exit();
1169                }
1170            } // end switch type
1171        } // end loop on vobjs
1172        if( ptab_found == 0 )
1173        {
1174            boot_puts("\n[INIT ERROR] Missing PTAB for vspace ");
1175            boot_putw( vspace_id );
1176            boot_exit();
1177        }
1178    } // end loop on vspaces
1179} // end boot_vobjs_init()
1180
1181void
1182mwmr_hw_init( void *coproc, enum mwmrPortDirection way,
1183              unsigned int no, const mwmr_channel_t *pmwmr)
1184{
1185    volatile unsigned int *cbase = (unsigned int*) coproc;
1186   
1187
1188    cbase[MWMR_CONFIG_FIFO_WAY] = way ;
1189    cbase[MWMR_CONFIG_FIFO_NO] = no ;
1190    cbase[MWMR_CONFIG_STATUS_ADDR] = (unsigned int)pmwmr ;
1191    cbase[MWMR_CONFIG_WIDTH] = pmwmr->width ;
1192    cbase[MWMR_CONFIG_DEPTH] = pmwmr->depth;
1193    cbase[MWMR_CONFIG_BUFFER_ADDR] = (unsigned int)&pmwmr->data;
1194    cbase[MWMR_CONFIG_RUNNING] = 1 ;
1195}
1196
1197
1198////////////////////////////////////////////////////////////////////////////////
1199// This function intializes the periherals and coprocessors, as specified
1200// in the mapping_info file.
1201////////////////////////////////////////////////////////////////////////////////
1202void boot_peripherals_init()
1203{
1204    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
1205    mapping_cluster_t*  cluster = boot_get_cluster_base( header );     
1206    mapping_periph_t*   periph  = boot_get_periph_base( header );
1207    mapping_pseg_t*     pseg    = boot_get_pseg_base( header );
1208    mapping_vobj_t*     vobj    = boot_get_vobj_base( header );
1209    mapping_vspace_t*   vspace  = boot_get_vspace_base( header );     
1210    mapping_coproc_t*   coproc  = boot_get_coproc_base( header );
1211    mapping_cp_port_t*  cp_port = boot_get_cp_port_base( header );
1212
1213    unsigned int        cluster_id;
1214    unsigned int        periph_id; 
1215    unsigned int        coproc_id; 
1216    unsigned int        cp_port_id; 
1217    unsigned int        channel_id;
1218
1219    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
1220    {
1221
1222#if BOOT_DEBUG_PERI
1223boot_puts("\n[BOOT DEBUG] ****** peripheral initialisation in cluster "); 
1224boot_putw( cluster_id );
1225boot_puts(" ******\n");
1226#endif
1227
1228        for ( periph_id = cluster[cluster_id].periph_offset ;
1229              periph_id < cluster[cluster_id].periph_offset + cluster[cluster_id].periphs ;
1230              periph_id++ )
1231        {
1232            unsigned int    type      = periph[periph_id].type;
1233            unsigned int    channels  = periph[periph_id].channels;
1234            unsigned int    pseg_id   = periph[periph_id].psegid;
1235
1236            unsigned int*   pseg_base = (unsigned int*)pseg[pseg_id].base;
1237
1238            //////// vci_block_device component
1239            if      ( type == PERIPH_TYPE_IOC )
1240            {
1241
1242                // activate interrupts
1243                pseg_base[BLOCK_DEVICE_IRQ_ENABLE] = 1; 
1244
1245#if BOOT_DEBUG_PERI
1246boot_puts("- IOC initialised : ");
1247boot_putw( channels );
1248boot_puts(" channels\n");
1249#endif
1250            }
1251
1252            //////// vci_multi_dma component
1253            else if ( type == PERIPH_TYPE_DMA )
1254            {
1255                for ( channel_id = 0 ; channel_id < channels ; channel_id++ )
1256                { 
1257                    // activate interrupts
1258                    pseg_base[DMA_IRQ_DISABLE + channel_id*DMA_SPAN] = 0;
1259                }
1260
1261#if BOOT_DEBUG_PERI
1262boot_puts("- DMA initialised : ");
1263boot_putw( channels );
1264boot_puts(" channels\n");
1265#endif
1266            }
1267
1268            //////// vci_multi_nic component
1269            else if ( type == PERIPH_TYPE_NIC  )
1270            {
1271                for ( channel_id = 0 ; channel_id < channels ; channel_id++ )
1272                { 
1273                // TODO
1274                }
1275
1276#if BOOT_DEBUG_PERI
1277boot_puts("- NIC initialised : ");
1278boot_putw( channels );
1279boot_puts(" channels\n");
1280#endif
1281            }
1282
1283            //////// vci_io_bridge component
1284            else if ( (type == PERIPH_TYPE_IOB) && GIET_IOMMU_ACTIVE )
1285            {
1286                // get the iommu page table physical address
1287                // TODO
1288
1289                // define IPI address mapping the IOC interrupt
1290                // TODO
1291
1292                // set IOMMU page table address
1293                // pseg_base[IOB_IOMMU_PTPR] = ptab_pbase;   
1294
1295                // activate IOMMU
1296                // pseg_base[IOB_IOMMU_ACTIVE] = 1;       
1297
1298#if BOOT_DEBUG_PERI
1299boot_puts("- IOB initialised : ");
1300boot_putw( channels );
1301boot_puts(" channels\n");
1302#endif
1303            }
1304
1305        } // end for periphs
1306/*
1307        for ( coproc_id = cluster[cluster_id].coproc_offset ;
1308              coproc_id < cluster[cluster_id].coproc_offset + cluster[cluster_id].coprocs ;
1309              coproc_id++ )
1310        {
1311            unsigned no_fifo_to  = 0;       //FIXME: should it be the map.xml who define the order?
1312            unsigned no_fifo_from = 0;
1313            unsigned int cpseg = pseg[coproc[coproc_id].psegid].base;
1314
1315#if BOOT_DEBUG_PERI
1316boot_puts("[BOOT] mwmr coproc initialisation of ");
1317boot_putw((unsigned int) coproc[coproc_id].name);
1318boot_puts(", nb ports");
1319boot_putw((unsigned int)coproc[coproc_id].ports);
1320boot_puts("\n");
1321#endif
1322
1323            for ( cp_port_id = coproc[coproc_id].port_offset ;
1324                  cp_port_id < coproc[coproc_id].port_offset + coproc[coproc_id].ports ;
1325                  cp_port_id++ )
1326            {
1327                //FIXME: should the same for all ports: put it in the coproc
1328                unsigned int vspace_id  = cp_port[cp_port_id].vspaceid;
1329                unsigned int vobj_id    = cp_port[cp_port_id].vobjlocid + vspace[vspace_id].vobj_offset;
1330
1331                mwmr_channel_t *pmwmr = (mwmr_channel_t*)(vobj[vobj_id].paddr);
1332
1333                if( cp_port[cp_port_id].direction == PORT_TO_COPROC)
1334                {
1335
1336#if BOOT_DEBUG_PERI
1337boot_puts("     port direction: PORT_TO_COPROC");
1338#endif
1339                    mwmr_hw_init((void*)cpseg, PORT_TO_COPROC, no_fifo_to, pmwmr );
1340                    no_fifo_to++;
1341                }
1342                else
1343                {
1344#if BOOT_DEBUG_PERI
1345boot_puts("     port direction: PORT_FROM_COPROC");
1346#endif
1347                    mwmr_hw_init((void*)cpseg, PORT_FROM_COPROC, no_fifo_from, pmwmr );
1348                    no_fifo_from++;
1349                }
1350#if BOOT_DEBUG_PERI
1351boot_puts(", with mwmr: ");
1352boot_puts(vobj[vobj_id].name);
1353boot_puts(" of vspace: ");
1354boot_puts(vspace[vspace_id].name);
1355#endif
1356            }
1357        } // end for coprocs
1358*/
1359    } // end for clusters
1360} // end boot_peripherals_init()
1361
1362
1363///////////////////////////////////////////////////////////////////////////////
1364// This function initialises all processors schedulers.
1365// This is done by processor 0, and the MMU must be activated.
1366// It initialises the boot_schedulers_paddr[gpid] pointers array.
1367// Finally, it scan all tasks in all vspaces to initialise the tasks contexts,
1368// as specified in the mapping_info data structure.
1369// For each task, a TTY channel, a TIMER channel, a FBDMA channel, and a NIC
1370// channel can be allocated if required.
1371///////////////////////////////////////////////////////////////////////////////
1372void boot_schedulers_init()
1373{
1374    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
1375    mapping_cluster_t*  cluster = boot_get_cluster_base( header );
1376    mapping_pseg_t*     pseg    = boot_get_pseg_base( header );
1377    mapping_vspace_t*   vspace  = boot_get_vspace_base( header );     
1378    mapping_task_t*     task    = boot_get_task_base( header );
1379    mapping_vobj_t*     vobj    = boot_get_vobj_base( header );
1380    mapping_proc_t*     proc    = boot_get_proc_base( header );
1381    mapping_irq_t*      irq     = boot_get_irq_base( header );
1382
1383    unsigned int        alloc_tty_channel;                 // TTY channel allocator
1384    unsigned int        alloc_nic_channel;                 // NIC channel allocator
1385    unsigned int        alloc_fbdma_channel[NB_CLUSTERS];  // FBDMA channel allocators
1386    unsigned int        alloc_timer_channel[NB_CLUSTERS];  // user TIMER allocators
1387
1388    unsigned int        cluster_id;                        // cluster global index
1389    unsigned int        proc_id;                           // processor global index
1390    unsigned int        irq_id;                            // irq global index
1391    unsigned int        pseg_id;                           // pseg global index
1392    unsigned int        vspace_id;                         // vspace global index
1393    unsigned int        task_id;                           // task global index;
1394
1395    // Step 0 : TTY, NIC, TIMERS and DMA channels allocators initialisation
1396    //          global_id = cluster_id*NB_*_MAX + loc_id
1397    //          - TTY[0] is reserved for the kernel
1398    //          - In all clusters the first NB_PROCS_MAX timers
1399    //            are reserved for the kernel (context switch)
1400
1401    alloc_tty_channel = 1; 
1402    alloc_nic_channel = 0;
1403
1404    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
1405    {
1406        alloc_fbdma_channel[cluster_id] = 0;
1407        alloc_timer_channel[cluster_id] = NB_PROCS_MAX;
1408    }
1409               
1410    // Step 1 : loop on the clusters and on the processors
1411    //          - initialise the boot_schedulers_paddr[] pointers array
1412    //          - initialise the interrupt vectors for each processor.
1413
1414    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
1415    {
1416
1417#if BOOT_DEBUG_SCHED
1418boot_puts("\n[BOOT DEBUG] Initialise schedulers / IT vector in cluster ");
1419boot_putw( cluster_id );
1420boot_puts("\n");
1421#endif
1422        unsigned int found = 0;
1423        unsigned int pseg_pbase;           // pseg base address
1424        unsigned int lpid;                 // processor local index
1425
1426        // get the physical base address of the first PSEG_TYPE_RAM pseg in cluster
1427        for ( pseg_id = cluster[cluster_id].pseg_offset ; 
1428              pseg_id < cluster[cluster_id].pseg_offset + cluster[cluster_id].psegs ; 
1429              pseg_id++ )
1430        {
1431            if ( pseg[pseg_id].type == PSEG_TYPE_RAM ) 
1432            {
1433                pseg_pbase = pseg[pseg_id].base;
1434                found = 1;
1435                break;
1436            }
1437        }
1438
1439        if ( (cluster[cluster_id].procs > 0) && (found == 0) )
1440        {
1441            boot_puts("\n[BOOT ERROR] Missing RAM pseg in cluster ");
1442            boot_putw( cluster_id );
1443            boot_puts("\n");
1444            boot_exit();
1445        }
1446
1447        // 4 Kbytes per scheduler
1448        for ( lpid = 0 ; lpid < cluster[cluster_id].procs ; lpid++ )
1449        {
1450            boot_schedulers_paddr[cluster_id*NB_PROCS_MAX + lpid] =
1451                (static_scheduler_t*)( pseg_pbase + (lpid<<12) );
1452        }
1453
1454        for ( proc_id = cluster[cluster_id].proc_offset ;
1455              proc_id < cluster[cluster_id].proc_offset + cluster[cluster_id].procs ;
1456              proc_id++ )
1457        {
1458
1459#if BOOT_DEBUG_SCHED
1460boot_puts("\nProc ");
1461boot_putw( proc_id );
1462boot_puts(" : scheduler pbase = ");
1463boot_putw( pseg_pbase + (proc_id<<12) );
1464boot_puts("\n");
1465#endif
1466            // initialise the "tasks" variable in scheduler
1467            boot_scheduler_set_tasks( proc_id , 0 );
1468           
1469            // initialise the interrupt_vector with ISR_DEFAULT
1470            unsigned int slot;
1471            for ( slot = 0 ; slot < 32 ; slot++) 
1472            {
1473                boot_scheduler_set_itvector( proc_id, slot, 0);
1474            }
1475
1476            // scan the IRQs actually allocated to current processor
1477            for ( irq_id = proc[proc_id].irq_offset ;
1478                  irq_id < proc[proc_id].irq_offset + proc[proc_id].irqs ;
1479                  irq_id++ )
1480            {
1481                unsigned int type    = irq[irq_id].type;
1482                unsigned int icu_id  = irq[irq_id].icuid;
1483                unsigned int isr_id  = irq[irq_id].isr;
1484                unsigned int channel = irq[irq_id].channel;
1485                unsigned int value   = isr_id | (type<<8) | (channel<<16); 
1486                boot_scheduler_set_itvector( proc_id, icu_id, value );
1487
1488#if BOOT_DEBUG_SCHED
1489boot_puts("- IRQ : icu = ");
1490boot_putw( icu_id );
1491boot_puts(" / type = ");
1492boot_putw( type );
1493boot_puts(" / isr = ");
1494boot_putw( isr_id );
1495boot_puts(" / channel = ");
1496boot_putw( channel );
1497boot_puts("\n");
1498#endif
1499            }
1500        } // end for procs
1501    } // end for clusters
1502
1503    // Step 2 : loop on the vspaces and the tasks
1504    //          to initialise the schedulers and the task contexts.
1505
1506    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1507    {
1508
1509#if BOOT_DEBUG_SCHED
1510boot_puts("\n[BOOT DEBUG] Initialise schedulers / task contexts for vspace ");
1511boot_puts(vspace[vspace_id].name);
1512boot_puts("\n");
1513#endif
1514        // We must set the PTPR depending on the vspace, because the start_vector
1515        // and the stack address are defined in virtual space.
1516        boot_set_mmu_ptpr( (unsigned int)boot_ptabs_paddr[vspace_id] >> 13 );
1517
1518        // loop on the tasks in vspace (task_id is the global index)
1519        for ( task_id = vspace[vspace_id].task_offset ; 
1520              task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks) ; 
1521              task_id++ )
1522        {
1523            // ctx_ra :  the return address is &boot_eret()
1524            unsigned int ctx_ra = (unsigned int)&boot_eret;
1525
1526            // ctx_sr : value required before an eret instruction
1527            unsigned int ctx_sr = 0x0000FF13; 
1528
1529            // ctx_ptpr : page table physical base address (shifted by 13 bit)
1530            unsigned int ctx_ptpr = (unsigned int)boot_ptabs_paddr[vspace_id] >> 13;
1531
1532            // ctx_ptab : page_table virtual base address
1533            unsigned int ctx_ptab = (unsigned int)boot_ptabs_vaddr[vspace_id];
1534
1535            // ctx_tty : terminal global index provided by a global allocator
1536            unsigned int ctx_tty = 0xFFFFFFFF;
1537            if ( task[task_id].use_tty ) 
1538            {
1539                if ( alloc_tty_channel >= NB_TTYS )
1540                {
1541                    boot_puts("\n[BOOT ERROR] TTY index too large for task ");
1542                    boot_puts( task[task_id].name );
1543                    boot_puts(" in vspace ");
1544                    boot_puts( vspace[vspace_id].name );
1545                    boot_puts("\n");
1546                    boot_exit();
1547                }
1548                ctx_tty = alloc_tty_channel;
1549                alloc_tty_channel++;
1550            }
1551
1552            // ctx_nic : NIC channel global index provided by a global allocator
1553            unsigned int ctx_nic = 0xFFFFFFFF;
1554            if ( task[task_id].use_nic ) 
1555            {
1556                if ( alloc_nic_channel >= NB_NICS )
1557                {
1558                    boot_puts("\n[BOOT ERROR] NIC channel index too large for task ");
1559                    boot_puts( task[task_id].name );
1560                    boot_puts(" in vspace ");
1561                    boot_puts( vspace[vspace_id].name );
1562                    boot_puts("\n");
1563                    boot_exit();
1564                }
1565                ctx_nic = alloc_nic_channel;
1566                alloc_nic_channel++;
1567            }
1568
1569            // ctx_timer : user TIMER global index provided by a cluster allocator
1570            unsigned int ctx_timer = 0xFFFFFFFF;
1571            if ( task[task_id].use_timer ) 
1572            {
1573                unsigned int cluster_id = task[task_id].clusterid;
1574                if ( alloc_timer_channel[cluster_id] >= NB_TIMERS_MAX )
1575                {
1576                    boot_puts("\n[BOOT ERROR] local TIMER index too large for task ");
1577                    boot_puts( task[task_id].name );
1578                    boot_puts(" in vspace ");
1579                    boot_puts( vspace[vspace_id].name );
1580                    boot_puts("\n");
1581                    boot_exit();
1582                }
1583                ctx_timer = cluster_id*NB_TIMERS_MAX + alloc_timer_channel[cluster_id];
1584                alloc_timer_channel[cluster_id]++;
1585            }
1586
1587            // ctx_fbdma : DMA global index provided by a cluster allocator 
1588            unsigned int ctx_fbdma = 0xFFFFFFFF;
1589            if ( task[task_id].use_fbdma ) 
1590            {
1591                unsigned int cluster_id = task[task_id].clusterid;
1592                if ( alloc_fbdma_channel[cluster_id] >= NB_DMAS_MAX )
1593                {
1594                    boot_puts("\n[BOOT ERROR] local FBDMA index too large for task ");
1595                    boot_puts( task[task_id].name );
1596                    boot_puts(" in vspace ");
1597                    boot_puts( vspace[vspace_id].name );
1598                    boot_puts("\n");
1599                    boot_exit();
1600                }
1601                ctx_fbdma = cluster_id*NB_DMAS_MAX + alloc_fbdma_channel[cluster_id];
1602                alloc_fbdma_channel[cluster_id]++;
1603            }
1604
1605            // ctx_epc : Get the virtual address of the start function
1606            mapping_vobj_t* pvobj = &vobj[vspace[vspace_id].vobj_offset + 
1607                                          vspace[vspace_id].start_offset]; 
1608            unsigned int* start_vector_vbase = (unsigned int*)pvobj->vaddr;
1609            unsigned int ctx_epc = start_vector_vbase[task[task_id].startid];
1610
1611            // ctx_sp :  Get the vobj containing the stack
1612            unsigned int vobj_id = task[task_id].vobjlocid + vspace[vspace_id].vobj_offset;
1613            unsigned int ctx_sp = vobj[vobj_id].vaddr + vobj[vobj_id].length;
1614
1615            // compute gpid = global processor index
1616            unsigned int gpid = task[task_id].clusterid*NB_PROCS_MAX + 
1617                                task[task_id].proclocid;
1618
1619            // In the code below, we access the scheduler with specific access
1620            // functions, because we only have the physical address of the scheduler,
1621            // and these functions must temporary desactivate the DTLB...
1622
1623            // get local task index in scheduler[gpid]
1624            unsigned int ltid = boot_scheduler_get_tasks( gpid );
1625
1626            if ( ltid >= IDLE_TASK_INDEX )
1627            {
1628                boot_puts("\n[BOOT ERROR] : ");
1629                boot_putw( ltid );
1630                boot_puts(" tasks allocated to processor ");
1631                boot_putw( gpid );
1632                boot_puts(" / max is 15\n");
1633                boot_exit();
1634            }
1635
1636            // update the "tasks" field in scheduler[gpid]
1637            boot_scheduler_set_tasks( gpid, ltid + 1);
1638
1639            // update the "current" field in scheduler[gpid]
1640            boot_scheduler_set_current( gpid, 0 );
1641
1642            // initializes the task context in scheduler[gpid]
1643            boot_scheduler_set_context( gpid, ltid, CTX_SR_ID    , ctx_sr     );
1644            boot_scheduler_set_context( gpid, ltid, CTX_SP_ID    , ctx_sp     );
1645            boot_scheduler_set_context( gpid, ltid, CTX_RA_ID    , ctx_ra     );
1646            boot_scheduler_set_context( gpid, ltid, CTX_EPC_ID   , ctx_epc    );
1647            boot_scheduler_set_context( gpid, ltid, CTX_PTPR_ID  , ctx_ptpr   );
1648            boot_scheduler_set_context( gpid, ltid, CTX_TTY_ID   , ctx_tty    );
1649            boot_scheduler_set_context( gpid, ltid, CTX_FBDMA_ID , ctx_fbdma  );
1650            boot_scheduler_set_context( gpid, ltid, CTX_NIC_ID   , ctx_nic    );
1651            boot_scheduler_set_context( gpid, ltid, CTX_TIMER_ID , ctx_timer  );
1652            boot_scheduler_set_context( gpid, ltid, CTX_PTAB_ID  , ctx_ptab   );
1653            boot_scheduler_set_context( gpid, ltid, CTX_LTID_ID  , ltid       );
1654            boot_scheduler_set_context( gpid, ltid, CTX_VSID_ID  , vspace_id  );
1655            boot_scheduler_set_context( gpid, ltid, CTX_RUN_ID   , 1          );
1656                                       
1657#if BOOT_DEBUG_SCHED
1658boot_puts("\nTask ");
1659boot_puts( task[task_id].name );
1660boot_puts(" allocated to processor ");
1661boot_putw( gpid );
1662boot_puts("  - ctx[LTID]   = ");
1663boot_putw( ltid );
1664boot_puts("\n");
1665
1666boot_puts("  - ctx[SR]     = ");
1667boot_putw( ctx_sr );
1668boot_puts("\n");
1669
1670boot_puts("  - ctx[SR]     = ");
1671boot_putw( ctx_sp );
1672boot_puts("\n");
1673
1674boot_puts("  - ctx[RA]     = ");
1675boot_putw( ctx_ra );
1676boot_puts("\n");
1677
1678boot_puts("  - ctx[EPC]    = ");
1679boot_putw( ctx_epc );
1680boot_puts("\n");
1681
1682boot_puts("  - ctx[PTPR]   = ");
1683boot_putw( ctx_ptpr );
1684boot_puts("\n");
1685
1686boot_puts("  - ctx[TTY]    = ");
1687boot_putw( ctx_tty );
1688boot_puts("\n");
1689
1690boot_puts("  - ctx[NIC]    = ");
1691boot_putw( ctx_nic );
1692boot_puts("\n");
1693
1694boot_puts("  - ctx[TIMER]  = ");
1695boot_putw( ctx_timer );
1696boot_puts("\n");
1697
1698boot_puts("  - ctx[FBDMA]  = ");
1699boot_putw( ctx_fbdma );
1700boot_puts("\n");
1701
1702boot_puts("  - ctx[PTAB]   = ");
1703boot_putw( ctx_ptab );
1704boot_puts("\n");
1705
1706boot_puts("  - ctx[VSID]   = ");
1707boot_putw( vspace_id );
1708boot_puts("\n");
1709
1710#endif
1711
1712        } // end loop on tasks
1713    } // end loop on vspaces
1714} // end boot_schedulers_init()
1715
1716//////////////////////////////////////////////////////////////////////////////////
1717// This function is executed by P[0] to wakeup all processors.
1718//////////////////////////////////////////////////////////////////////////////////
1719void boot_start_all_procs()
1720{
1721    mapping_header_t*   header = (mapping_header_t*)&seg_mapping_base; 
1722    header->signature = OUT_MAPPING_SIGNATURE;
1723}
1724
1725/////////////////////////////////////////////////////////////////////
1726// This function is the entry point of the initialisation procedure
1727/////////////////////////////////////////////////////////////////////
1728void boot_init()
1729{
1730    // mapping_info checking
1731    boot_check_mapping();
1732
1733    boot_puts("\n[BOOT] Mapping check completed at cycle ");
1734    boot_putw( boot_proctime() );
1735    boot_puts("\n");
1736
1737    // pseg allocators initialisation
1738    boot_psegs_init();
1739
1740    boot_puts("\n[BOOT] Pseg allocators initialisation completed at cycle ");
1741    boot_putw( boot_proctime() );
1742    boot_puts("\n");
1743
1744    // page table building
1745    boot_pt_init();
1746
1747    boot_puts("\n[BOOT] Page Tables initialisation completed at cycle ");
1748    boot_putw( boot_proctime() );
1749    boot_puts("\n");
1750
1751    // vobjs initialisation
1752    boot_vobjs_init();
1753
1754    boot_puts("\n[BOOT] Vobjs initialisation completed at cycle : ");
1755    boot_putw( boot_proctime() );
1756    boot_puts("\n");
1757
1758    // peripherals initialisation
1759    boot_peripherals_init();
1760
1761    boot_puts("\n[BOOT] Peripherals initialisation completed at cycle ");
1762    boot_putw( boot_proctime() );
1763    boot_puts("\n");
1764
1765    // mmu activation
1766    boot_set_mmu_ptpr( (unsigned int)boot_ptabs_paddr[0] >> 13 );
1767    boot_set_mmu_mode( 0xF );
1768
1769    boot_puts("\n[BOOT] MMU activation completed at cycle ");
1770    boot_putw( boot_proctime() );
1771    boot_puts("\n");
1772
1773    // schedulers initialisation
1774    boot_schedulers_init();
1775
1776    boot_puts("\n[BOOT] Schedulers initialisation completed at cycle ");
1777    boot_putw( boot_proctime() );
1778    boot_puts("\n");
1779
1780    // start all processors
1781    boot_start_all_procs();
1782
1783} // end boot_init()
1784
1785// Local Variables:
1786// tab-width: 4
1787// c-basic-offset: 4
1788// c-file-offsets:((innamespace . 0)(inline-open . 0))
1789// indent-tabs-mode: nil
1790// End:
1791// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1792
Note: See TracBrowser for help on using the repository browser.