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

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

Introducing a new release where all initialisation
is done in the boot code.

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