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

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

Activating the distributed scheduler in the memo Makefile.
Fixing a bug in the boot_init.c file (initialisation of "tasks" variable in the schedulers)

File size: 62.2 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    // checking number of virtual spaces
838    if ( header->vspaces > GIET_NB_VSPACE_MAX )
839    {
840        boot_puts("\n[BOOT ERROR] : number of vspaces > GIET_NB_VSPACE_MAX\n");
841        boot_puts("\n");
842        boot_exit();
843    }
844
845    // checking TTY number
846    cluster_id = header->tty_clusterid;
847    for ( periph_id = cluster[cluster_id].periph_offset ;
848          periph_id < cluster[cluster_id].periph_offset + cluster[cluster_id].periphs ;
849          periph_id++ )
850    {
851        if ( periph[periph_id].type == PERIPH_TYPE_TTY ) 
852        {
853            channels = periph[periph_id].channels;
854            break;
855        }
856               
857    } 
858    if ( channels > NB_TTYS )
859    {
860        boot_puts("\n[BOOT ERROR] Incoherent NB_TTYS");
861        boot_puts("\n             - In giet_config,  value = ");
862        boot_putw ( NB_TTYS );
863        boot_puts("\n             - In mapping_info, value = ");
864        boot_putw ( channels );
865        boot_puts("\n");
866        boot_exit();
867    }
868
869    // TODO same type of checking for TIMERS, DMAS, NIC channels
870
871} // end boot_check_mapping()
872
873/////////////////////////////////////////////////////////////////////
874// This function initialises the physical pages table allocators
875// for all psegs (i.e. next_base field of the pseg).
876// In each cluster containing processors, it reserve space for the
877// schedulers in the first RAM pseg found (4k bytes per processor).
878/////////////////////////////////////////////////////////////////////
879void boot_psegs_init()
880{
881    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
882
883    mapping_cluster_t*  cluster = boot_get_cluster_base( header ); 
884    mapping_pseg_t*     pseg    = boot_get_pseg_base( header ); 
885
886    unsigned int cluster_id;
887    unsigned int pseg_id;
888    unsigned int found;
889
890#if BOOT_DEBUG_PT
891boot_puts("\n[BOOT DEBUG] ****** psegs allocators nitialisation ******\n");
892#endif
893
894    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
895    {
896        if ( cluster[cluster_id].procs > NB_PROCS_MAX )
897        {
898            boot_puts("\n[BOOT ERROR] The number of processors in cluster ");
899            boot_putw( cluster_id );
900            boot_puts(" is larger than NB_PROCS_MAX \n");
901            boot_exit();
902        }
903
904        found    = 0;
905
906        for ( pseg_id = cluster[cluster_id].pseg_offset ;
907              pseg_id < cluster[cluster_id].pseg_offset + cluster[cluster_id].psegs ;
908              pseg_id++ )
909        {
910            unsigned int free = pseg[pseg_id].base;
911
912            if ( (pseg[pseg_id].type == PSEG_TYPE_RAM) && (found == 0) )
913            {
914                free = free + (cluster[cluster_id].procs << 12);
915                found = 1;
916            }
917            pseg[pseg_id].next_base = free;
918
919#if BOOT_DEBUG_PT
920boot_puts("cluster ");
921boot_putw(cluster_id);
922boot_puts(" / pseg ");
923boot_puts(pseg[pseg_id].name);
924boot_puts(" : next_base = ");
925boot_putw(pseg[pseg_id].next_base);
926boot_puts("\n");
927#endif
928        }
929    }
930} // end boot_pseg_init()
931
932/////////////////////////////////////////////////////////////////////
933// This function builds the page tables for all virtual spaces
934// defined in the mapping_info data structure.
935// For each virtual space, it maps both the global vsegs
936// (replicated in all vspaces), and the private vsegs.
937/////////////////////////////////////////////////////////////////////
938void boot_pt_init()
939{
940    mapping_header_t*   header = (mapping_header_t*)&seg_mapping_base; 
941
942    mapping_vspace_t*   vspace = boot_get_vspace_base( header );     
943    mapping_vseg_t*     vseg   = boot_get_vseg_base( header );
944
945    unsigned int        vspace_id; 
946    unsigned int        vseg_id;
947
948#if BOOT_DEBUG_PT
949boot_puts("\n[BOOT DEBUG] ****** mapping global vsegs ******\n");
950#endif
951           
952    // step 1 : first loop on virtual spaces to map global vsegs
953    for ( vseg_id = 0 ; vseg_id < header->globals ; vseg_id++ )
954    {
955        boot_vseg_map( &vseg[vseg_id], ((unsigned int)(-1)) );
956    }
957
958    // step 2 : loop on virtual vspaces to map private vsegs
959    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
960    {
961
962#if BOOT_DEBUG_PT
963boot_puts("\n[BOOT DEBUG] ****** mapping private vsegs in vspace ");
964boot_puts(vspace[vspace_id].name);
965boot_puts(" ******\n");
966#endif
967           
968        for ( vseg_id = vspace[vspace_id].vseg_offset ; 
969              vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs) ; 
970              vseg_id++ )
971        {
972            boot_vseg_map( &vseg[vseg_id], vspace_id ); 
973        }
974    } 
975
976    // step 3 : loop on the vspaces to build the page tables
977    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
978    {
979
980#if BOOT_DEBUG_PT
981boot_puts("\n[BOOT DEBUG] ****** building page table for vspace ");
982boot_puts(vspace[vspace_id].name);
983boot_puts(" ******\n");
984#endif
985           
986        boot_vspace_pt_build( vspace_id );
987
988#if BOOT_DEBUG_PT
989boot_puts("\n>>> page table physical address = ");
990boot_putw((unsigned int)boot_ptabs_paddr[vspace_id]);
991boot_puts(", page table number of PT2 = ");
992boot_putw((unsigned int)boot_max_pt2[vspace_id]);
993boot_puts("\n");
994#endif
995    } 
996} // end boot_pt_init()
997
998///////////////////////////////////////////////////////////////////////////////
999// This function initializes all private vobjs defined in the vspaces,
1000// such as mwmr channels, barriers and locks, because these vobjs
1001// are not known, and not initialised by the compiler.
1002///////////////////////////////////////////////////////////////////////////////
1003void boot_vobjs_init()
1004{
1005    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
1006    mapping_vspace_t*   vspace  = boot_get_vspace_base( header );     
1007    mapping_vobj_t*     vobj    = boot_get_vobj_base( header );
1008
1009    unsigned int        vspace_id; 
1010    unsigned int        vobj_id;
1011
1012    // loop on the vspaces
1013    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1014    {
1015
1016#if BOOT_DEBUG_VOBJS
1017boot_puts("\n[BOOT DEBUG] ****** vobjs initialisation in vspace "); 
1018boot_puts(vspace[vspace_id].name);
1019boot_puts(" ******\n");
1020#endif
1021        // We must set the PTPR depending on the vspace, because the addresses
1022        // of mwmmr channels, barriers and locks are defined in virtual space.
1023        boot_set_mmu_ptpr( (unsigned int)boot_ptabs_paddr[vspace_id] >> 13 );
1024
1025        unsigned int ptab_found = 0;
1026
1027        // loop on the vobjs
1028            for(vobj_id= vspace[vspace_id].vobj_offset; 
1029                        vobj_id < (vspace[vspace_id].vobj_offset+ vspace[vspace_id].vobjs);
1030                        vobj_id++)
1031            {
1032            switch( vobj[vobj_id].type )
1033            {
1034                case VOBJ_TYPE_MWMR:    // storage capacity is (vobj.length/4 - 5) words
1035                        {
1036                    mwmr_channel_t* mwmr = (mwmr_channel_t*)(vobj[vobj_id].vaddr);
1037                    mwmr->ptw   = 0;
1038                    mwmr->ptr   = 0;
1039                    mwmr->sts   = 0;
1040                    mwmr->width = vobj[vobj_id].init;
1041                    mwmr->depth = (vobj[vobj_id].length>>2) - 6;
1042                    mwmr->lock  = 0;
1043#if BOOT_DEBUG_VOBJS
1044boot_puts("MWMR    : ");
1045boot_puts( vobj[vobj_id].name);
1046boot_puts(" / depth = ");
1047boot_putw( mwmr->depth );
1048boot_puts(" / width = ");
1049boot_putw( mwmr->width );
1050boot_puts("\n");
1051#endif
1052                    break;
1053                }
1054                case VOBJ_TYPE_ELF:             // initialisation done by the loader
1055                {
1056#if BOOT_DEBUG_VOBJS
1057boot_puts("ELF     : ");
1058boot_puts( vobj[vobj_id].name);
1059boot_puts(" / length = ");
1060boot_putw( vobj[vobj_id].length ); 
1061boot_puts("\n");
1062#endif
1063                    break;
1064                }
1065                case VOBJ_TYPE_BLOB:            // initialisation done by the loader
1066                {
1067#if BOOT_DEBUG_VOBJS
1068boot_puts("BLOB     : ");
1069boot_puts( vobj[vobj_id].name);
1070boot_puts(" / length = ");
1071boot_putw( vobj[vobj_id].length ); 
1072boot_puts("\n");
1073#endif
1074                    break;
1075                }
1076                case VOBJ_TYPE_BARRIER: // init is the number of participants
1077                {
1078                    giet_barrier_t* barrier = (giet_barrier_t*)(vobj[vobj_id].vaddr);
1079                    barrier->count = 0;
1080                    barrier->init  = vobj[vobj_id].init;
1081#if BOOT_DEBUG_VOBJS
1082boot_puts("BARRIER : ");
1083boot_puts( vobj[vobj_id].name);
1084boot_puts(" / init_value = ");
1085boot_putw( barrier->init );
1086boot_puts("\n");
1087#endif
1088                    break;
1089                }
1090                case VOBJ_TYPE_LOCK:    // init is "not taken"
1091                {
1092                    unsigned int* lock = (unsigned int*)(vobj[vobj_id].vaddr);
1093                    *lock = 0;
1094#if BOOT_DEBUG_VOBJS
1095boot_puts("LOCK    : ");
1096boot_puts( vobj[vobj_id].name);
1097boot_puts("\n");
1098#endif
1099                    break;
1100                }
1101                case VOBJ_TYPE_BUFFER:  // nothing to initialise
1102                {
1103#if BOOT_DEBUG_VOBJS
1104boot_puts("BUFFER  : ");
1105boot_puts( vobj[vobj_id].name);
1106boot_puts(" / length = ");
1107boot_putw( vobj[vobj_id].length ); 
1108boot_puts("\n");
1109#endif
1110                    break;
1111                }
1112                case VOBJ_TYPE_PTAB:    // nothing to initialise
1113                {
1114                    ptab_found = 1;
1115#if BOOT_DEBUG_VOBJS
1116boot_puts("PTAB    : ");
1117boot_puts( vobj[vobj_id].name);
1118boot_puts(" / length = ");
1119boot_putw( vobj[vobj_id].length ); 
1120boot_puts("\n");
1121#endif
1122                    break;
1123                }
1124                default:
1125                {
1126                    boot_puts("\n[INIT ERROR] illegal vobj of name ");
1127                    boot_puts(vobj->name);
1128                    boot_puts(" / in vspace = ");
1129                    boot_puts(vobj->name);
1130                    boot_puts("\n ");
1131                    boot_exit();
1132                }
1133            } // end switch type
1134        } // end loop on vobjs
1135        if( ptab_found == 0 )
1136        {
1137            boot_puts("\n[INIT ERROR] Missing PTAB for vspace ");
1138            boot_putw( vspace_id );
1139            boot_exit();
1140        }
1141    } // end loop on vspaces
1142} // end boot_vobjs_init()
1143
1144////////////////////////////////////////////////////////////////////////////////
1145// This function intializes the periherals and coprocessors, as specified
1146// tsuch as the IOB component
1147// (I/O bridge, containing the IOMMU, the IOC (external disk controller),
1148// the NIC (external network controller), the FBDMA (frame buffer controller),
1149////////////////////////////////////////////////////////////////////////////////
1150void boot_peripherals_init()
1151{
1152    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
1153    mapping_cluster_t*  cluster = boot_get_cluster_base( header );     
1154    mapping_periph_t*   periph  = boot_get_periph_base( header );
1155    mapping_pseg_t*     pseg    = boot_get_pseg_base( header );
1156
1157    unsigned int        cluster_id;
1158    unsigned int        periph_id; 
1159    unsigned int        coproc_id; 
1160    unsigned int        channel_id;
1161
1162    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
1163    {
1164
1165#if BOOT_DEBUG_PERI
1166boot_puts("\n[BOOT DEBUG] ****** peripheral initialisation in cluster "); 
1167boot_putw( cluster_id );
1168boot_puts(" ******\n");
1169#endif
1170
1171        for ( periph_id = cluster[cluster_id].periph_offset ;
1172              periph_id < cluster[cluster_id].periph_offset + cluster[cluster_id].periphs ;
1173              periph_id++ )
1174        {
1175            unsigned int    type      = periph[periph_id].type;
1176            unsigned int    channels  = periph[periph_id].channels;
1177            unsigned int    pseg_id   = periph[periph_id].psegid;
1178
1179            unsigned int*   pseg_base = (unsigned int*)pseg[pseg_id].base;
1180
1181            //////// vci_block_device component
1182            if      ( type == PERIPH_TYPE_IOC )
1183            {
1184
1185                // activate interrupts
1186                pseg_base[BLOCK_DEVICE_IRQ_ENABLE] = 1; 
1187
1188#if BOOT_DEBUG_PERI
1189boot_puts("- IOC initialised : ");
1190boot_putw( channels );
1191boot_puts(" channels\n");
1192#endif
1193            }
1194
1195            //////// vci_multi_dma component
1196            else if ( type == PERIPH_TYPE_DMA )
1197            {
1198                for ( channel_id = 0 ; channel_id < channels ; channel_id++ )
1199                { 
1200                    // activate interrupts
1201                    pseg_base[DMA_IRQ_DISABLE + channel_id*DMA_SPAN] = 0;
1202                }
1203
1204#if BOOT_DEBUG_PERI
1205boot_puts("- DMA initialised : ");
1206boot_putw( channels );
1207boot_puts(" channels\n");
1208#endif
1209            }
1210
1211            //////// vci_multi_nic component
1212            else if ( type == PERIPH_TYPE_NIC  )
1213            {
1214                for ( channel_id = 0 ; channel_id < channels ; channel_id++ )
1215                { 
1216                // TODO
1217                }
1218
1219#if BOOT_DEBUG_PERI
1220boot_puts("- NIC initialised : ");
1221boot_putw( channels );
1222boot_puts(" channels\n");
1223#endif
1224            }
1225
1226            //////// vci_io_bridge component
1227            else if ( (type == PERIPH_TYPE_IOB) && GIET_IOMMU_ACTIVE )
1228            {
1229                // get the iommu page table physical address
1230                // TODO
1231
1232                // define IPI address mapping the IOC interrupt
1233                // TODO
1234
1235                // set IOMMU page table address
1236                // pseg_base[IOB_IOMMU_PTPR] = ptab_pbase;   
1237
1238                // activate IOMMU
1239                // pseg_base[IOB_IOMMU_ACTIVE] = 1;       
1240
1241#if BOOT_DEBUG_PERI
1242boot_puts("- IOB initialised : ");
1243boot_putw( channels );
1244boot_puts(" channels\n");
1245#endif
1246            }
1247
1248        } // end for periphs
1249
1250        for ( coproc_id = cluster[cluster_id].coproc_offset ;
1251              coproc_id < cluster[cluster_id].coproc_offset + cluster[cluster_id].coprocs ;
1252              coproc_id++ )
1253        {
1254            // TODO
1255        } // end for coprocs
1256
1257    } // end for clusters
1258} // end boot_peripherals_init()
1259
1260
1261///////////////////////////////////////////////////////////////////////////////
1262// This function initialises all processors schedulers.
1263// This is done by processor 0, and the MMU must be activated.
1264// It initialises the boot_schedulers_paddr[gpid] pointers array.
1265// Finally, it scan all tasks in all vspaces to initialise the tasks contexts,
1266// as specified in the mapping_info data structure.
1267// For each task, a TTY channel, a TIMER channel, a FBDMA channel, and a NIC
1268// channel can be allocated if required.
1269///////////////////////////////////////////////////////////////////////////////
1270void boot_schedulers_init()
1271{
1272    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
1273    mapping_cluster_t*  cluster = boot_get_cluster_base( header );
1274    mapping_pseg_t*     pseg    = boot_get_pseg_base( header );
1275    mapping_vspace_t*   vspace  = boot_get_vspace_base( header );     
1276    mapping_task_t*     task    = boot_get_task_base( header );
1277    mapping_vobj_t*     vobj    = boot_get_vobj_base( header );
1278    mapping_proc_t*     proc    = boot_get_proc_base( header );
1279    mapping_irq_t*      irq     = boot_get_irq_base( header );
1280
1281    unsigned int        alloc_tty_channel;                 // TTY channel allocator
1282    unsigned int        alloc_nic_channel;                 // NIC channel allocator
1283    unsigned int        alloc_fbdma_channel[NB_CLUSTERS];  // FBDMA channel allocators
1284    unsigned int        alloc_timer_channel[NB_CLUSTERS];  // user TIMER allocators
1285
1286    unsigned int        cluster_id;                        // cluster global index
1287    unsigned int        proc_id;                           // processor global index
1288    unsigned int        irq_id;                            // irq global index
1289    unsigned int        pseg_id;                           // pseg global index
1290    unsigned int        vspace_id;                         // vspace global index
1291    unsigned int        task_id;                           // task global index;
1292
1293    // Step 0 : TTY, NIC, TIMERS and DMA channels allocators initialisation
1294    //          global_id = cluster_id*NB_*_MAX + loc_id
1295    //          - TTY[0] is reserved for the kernel
1296    //          - In all clusters the first NB_PROCS_MAX timers
1297    //            are reserved for the kernel (context switch)
1298
1299    alloc_tty_channel = 1; 
1300    alloc_nic_channel = 0;
1301
1302    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
1303    {
1304        alloc_fbdma_channel[cluster_id] = 0;
1305        alloc_timer_channel[cluster_id] = NB_PROCS_MAX;
1306    }
1307               
1308    // Step 1 : loop on the clusters and on the processors
1309    //          - initialise the boot_schedulers_paddr[] pointers array
1310    //          - initialise the interrupt vectors for each processor.
1311
1312    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
1313    {
1314
1315#if BOOT_DEBUG_SCHED
1316boot_puts("\n[BOOT DEBUG] Initialise schedulers / IT vector in cluster ");
1317boot_putw( cluster_id );
1318boot_puts("\n");
1319#endif
1320        unsigned int found = 0;
1321        unsigned int pseg_pbase;           // pseg base address
1322        unsigned int lpid;                 // processor local index
1323
1324        // get the physical base address of the first PSEG_TYPE_RAM pseg in cluster
1325        for ( pseg_id = cluster[cluster_id].pseg_offset ; 
1326              pseg_id < cluster[cluster_id].pseg_offset + cluster[cluster_id].psegs ; 
1327              pseg_id++ )
1328        {
1329            if ( pseg[pseg_id].type == PSEG_TYPE_RAM ) 
1330            {
1331                pseg_pbase = pseg[pseg_id].base;
1332                found = 1;
1333                break;
1334            }
1335        }
1336
1337        if ( (cluster[cluster_id].procs > 0) && (found == 0) )
1338        {
1339            boot_puts("\n[BOOT ERROR] Missing RAM pseg in cluster ");
1340            boot_putw( cluster_id );
1341            boot_puts("\n");
1342            boot_exit();
1343        }
1344
1345        // 4 Kbytes per scheduler
1346        for ( lpid = 0 ; lpid < cluster[cluster_id].procs ; lpid++ )
1347        {
1348            boot_schedulers_paddr[cluster_id*NB_PROCS_MAX + lpid] =
1349                (static_scheduler_t*)( pseg_pbase + (lpid<<12) );
1350        }
1351
1352        for ( proc_id = cluster[cluster_id].proc_offset ;
1353              proc_id < cluster[cluster_id].proc_offset + cluster[cluster_id].procs ;
1354              proc_id++ )
1355        {
1356
1357#if BOOT_DEBUG_SCHED
1358boot_puts("\nProc ");
1359boot_putw( proc_id );
1360boot_puts(" : scheduler pbase = ");
1361boot_putw( pseg_pbase + (lpid<<12) );
1362boot_puts("\n");
1363#endif
1364            // initialise the "tasks" variable in scheduler
1365            boot_scheduler_set_tasks( proc_id , 0 );
1366           
1367            // initialise the interrupt_vector with ISR_DEFAULT
1368            unsigned int slot;
1369            for ( slot = 0 ; slot < 32 ; slot++) 
1370            {
1371                boot_scheduler_set_itvector( proc_id, slot, 0);
1372            }
1373
1374            // scan the IRQs actually allocated to current processor
1375            for ( irq_id = proc[proc_id].irq_offset ;
1376                  irq_id < proc[proc_id].irq_offset + proc[proc_id].irqs ;
1377                  irq_id++ )
1378            {
1379                unsigned int type    = irq[irq_id].type;
1380                unsigned int icu_id  = irq[irq_id].icuid;
1381                unsigned int isr_id  = irq[irq_id].isr;
1382                unsigned int channel = irq[irq_id].channel;
1383                unsigned int value   = isr_id | (type<<8) | (channel<<16); 
1384                boot_scheduler_set_itvector( proc_id, icu_id, value );
1385
1386#if BOOT_DEBUG_SCHED
1387boot_puts("- IRQ : icu = ");
1388boot_putw( icu_id );
1389boot_puts(" / type = ");
1390boot_putw( type );
1391boot_puts(" / isr = ");
1392boot_putw( isr_id );
1393boot_puts(" / channel = ");
1394boot_putw( channel );
1395boot_puts("\n");
1396#endif
1397            }
1398        } // end for procs
1399    } // end for clusters
1400
1401    // Step 2 : loop on the vspaces and the tasks
1402    //          to initialise the schedulers and the task contexts.
1403
1404    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1405    {
1406
1407#if BOOT_DEBUG_SCHED
1408boot_puts("\n[BOOT DEBUG] Initialise schedulers / task contexts for vspace ");
1409boot_puts(vspace[vspace_id].name);
1410boot_puts("\n");
1411#endif
1412        // We must set the PTPR depending on the vspace, because the start_vector
1413        // and the stack address are defined in virtual space.
1414        boot_set_mmu_ptpr( (unsigned int)boot_ptabs_paddr[vspace_id] >> 13 );
1415
1416        // loop on the tasks in vspace (task_id is the global index)
1417        for ( task_id = vspace[vspace_id].task_offset ; 
1418              task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks) ; 
1419              task_id++ )
1420        {
1421            // ra :  the return address is &boot_eret()
1422            unsigned int ra = (unsigned int)&boot_eret;
1423
1424            // sr : value required before an eret instruction
1425            unsigned int sr = 0x0000FF13; 
1426
1427            // ptpr : page table physical base address (shifted by 13 bit)
1428            unsigned int ptpr = (unsigned int)boot_ptabs_paddr[vspace_id] >> 13;
1429
1430            // ptab : page_table virtual base address (not a register)
1431            unsigned int ptab = (unsigned int)boot_ptabs_vaddr[vspace_id];
1432
1433            // tty : terminal global index provided by a global allocator
1434            unsigned int tty = 0xFFFFFFFF;
1435            if ( task[task_id].use_tty ) 
1436            {
1437                if ( alloc_tty_channel >= NB_TTYS )
1438                {
1439                    boot_puts("\n[BOOT ERROR] TTY index too large for task ");
1440                    boot_puts( task[task_id].name );
1441                    boot_puts(" in vspace ");
1442                    boot_puts( vspace[vspace_id].name );
1443                    boot_puts("\n");
1444                    boot_exit();
1445                }
1446                tty = alloc_tty_channel;
1447                alloc_tty_channel++;
1448            }
1449
1450            // nic : NIC channel global index provided by a global allocator
1451            unsigned int nic = 0xFFFFFFFF;
1452            if ( task[task_id].use_nic ) 
1453            {
1454                if ( alloc_nic_channel >= NB_NICS )
1455                {
1456                    boot_puts("\n[BOOT ERROR] NIC channel index too large for task ");
1457                    boot_puts( task[task_id].name );
1458                    boot_puts(" in vspace ");
1459                    boot_puts( vspace[vspace_id].name );
1460                    boot_puts("\n");
1461                    boot_exit();
1462                }
1463                nic = alloc_nic_channel;
1464                alloc_nic_channel++;
1465            }
1466
1467            // timer : user TIMER global index provided by a cluster allocator
1468            unsigned int timer = 0xFFFFFFFF;
1469            if ( task[task_id].use_timer ) 
1470            {
1471                unsigned int cluster_id = task[task_id].clusterid;
1472                if ( alloc_timer_channel[cluster_id] >= NB_TIMERS_MAX )
1473                {
1474                    boot_puts("\n[BOOT ERROR] local TIMER index too large for task ");
1475                    boot_puts( task[task_id].name );
1476                    boot_puts(" in vspace ");
1477                    boot_puts( vspace[vspace_id].name );
1478                    boot_puts("\n");
1479                    boot_exit();
1480                }
1481                timer = cluster_id*NB_TIMERS_MAX + alloc_timer_channel[cluster_id];
1482                alloc_timer_channel[cluster_id]++;
1483            }
1484
1485            // fbdma : DMA global index provided by a cluster allocator 
1486            unsigned int fbdma = 0xFFFFFFFF;
1487            if ( task[task_id].use_fbdma ) 
1488            {
1489                unsigned int cluster_id = task[task_id].clusterid;
1490                if ( alloc_fbdma_channel[cluster_id] >= NB_DMAS_MAX )
1491                {
1492                    boot_puts("\n[BOOT ERROR] local FBDMA index too large for task ");
1493                    boot_puts( task[task_id].name );
1494                    boot_puts(" in vspace ");
1495                    boot_puts( vspace[vspace_id].name );
1496                    boot_puts("\n");
1497                    boot_exit();
1498                }
1499                fbdma = cluster_id*NB_DMAS_MAX + alloc_fbdma_channel[cluster_id];
1500                alloc_fbdma_channel[cluster_id]++;
1501            }
1502
1503            // epc : Get the (virtual) base address of the start_vector containing
1504            // the start addresses for all tasks defined in the vspace.
1505            mapping_vobj_t* pvobj = &vobj[vspace[vspace_id].vobj_offset + 
1506                                          vspace[vspace_id].start_offset]; 
1507            unsigned int* start_vector_vbase = (unsigned int*)pvobj->vaddr;
1508            unsigned int epc = start_vector_vbase[task[task_id].startid];
1509
1510            // sp :  Get the vobj containing the stack
1511            unsigned int vobj_id = task[task_id].vobjlocid + vspace[vspace_id].vobj_offset;
1512            unsigned int sp = vobj[vobj_id].vaddr + vobj[vobj_id].length;
1513
1514            // compute gpid = global processor index
1515            unsigned int gpid = task[task_id].clusterid*NB_PROCS_MAX + 
1516                                task[task_id].proclocid;
1517
1518            // sched : scheduler physical address
1519            unsigned int sched = (unsigned int)boot_schedulers_paddr[gpid];
1520
1521            // In the code below, we access the scheduler with specific access
1522            // functions, because we only have the physical address of the scheduler,
1523            // and these functions must temporary desactivate the DTLB...
1524
1525            // get local task index in scheduler[gpid]
1526            unsigned int ltid = boot_scheduler_get_tasks( gpid );
1527
1528            if ( ltid >= 15 )
1529            {
1530                boot_puts("\n[BOOT ERROR] : ");
1531                boot_putw( ltid );
1532                boot_puts(" tasks allocated to processor ");
1533                boot_putw( gpid );
1534                boot_puts(" / max is 15\n");
1535                boot_exit();
1536            }
1537
1538            // update the "tasks" field in scheduler[gpid]
1539            boot_scheduler_set_tasks( gpid, ltid + 1);
1540
1541            // update the "current" field in scheduler[gpid]
1542            boot_scheduler_set_current( gpid, 0 );
1543
1544            // initializes the task context in scheduler[gpid]
1545            boot_scheduler_set_context( gpid, ltid, CTX_SR_ID    , sr    );
1546            boot_scheduler_set_context( gpid, ltid, CTX_SP_ID    , sp    );
1547            boot_scheduler_set_context( gpid, ltid, CTX_RA_ID    , ra    );
1548            boot_scheduler_set_context( gpid, ltid, CTX_EPC_ID   , epc   );
1549            boot_scheduler_set_context( gpid, ltid, CTX_PTPR_ID  , ptpr  );
1550            boot_scheduler_set_context( gpid, ltid, CTX_TTY_ID   , tty   );
1551            boot_scheduler_set_context( gpid, ltid, CTX_TIMER_ID , timer );
1552            boot_scheduler_set_context( gpid, ltid, CTX_FBDMA_ID , fbdma );
1553            boot_scheduler_set_context( gpid, ltid, CTX_PTAB_ID  , ptab  );
1554            boot_scheduler_set_context( gpid, ltid, CTX_SCHED_ID , sched );
1555                                       
1556#if BOOT_DEBUG_SCHED
1557boot_puts("\nTask ");
1558boot_puts( task[task_id].name );
1559boot_puts(" allocated to processor ");
1560boot_putw( gpid );
1561boot_puts(" / ltid = ");
1562boot_putw( ltid );
1563boot_puts("\n");
1564
1565boot_puts("  - SR          = ");
1566boot_putw( sr );
1567boot_puts("\n");
1568
1569boot_puts("  - SP          = ");
1570boot_putw( sp );
1571boot_puts("\n");
1572
1573boot_puts("  - RA          = ");
1574boot_putw( ra );
1575boot_puts("\n");
1576
1577boot_puts("  - EPC         = ");
1578boot_putw( epc );
1579boot_puts("\n");
1580
1581boot_puts("  - PTPR        = ");
1582boot_putw( ptpr<<13 );
1583boot_puts("\n");
1584
1585boot_puts("  - TTY         = ");
1586boot_putw( tty );
1587boot_puts("\n");
1588
1589boot_puts("  - TIMER       = ");
1590boot_putw( timer );
1591boot_puts("\n");
1592
1593boot_puts("  - FBDMA       = ");
1594boot_putw( fbdma );
1595boot_puts("\n");
1596
1597boot_puts("  - PTAB        = ");
1598boot_putw( ptab );
1599boot_puts("\n");
1600
1601boot_puts("  - SCHED       = ");
1602boot_putw( sched );
1603boot_puts("\n");
1604#endif
1605
1606        } // end loop on tasks
1607    } // end loop on vspaces
1608} // end boot_schedulers_init()
1609
1610//////////////////////////////////////////////////////////////////////////////////
1611// This function is executed by P[0] to wakeup all processors.
1612//////////////////////////////////////////////////////////////////////////////////
1613void boot_start_all_procs()
1614{
1615    mapping_header_t*   header = (mapping_header_t*)&seg_mapping_base; 
1616    header->signature = OUT_MAPPING_SIGNATURE;
1617}
1618
1619/////////////////////////////////////////////////////////////////////
1620// This function is the entry point of the initialisation procedure
1621/////////////////////////////////////////////////////////////////////
1622void boot_init()
1623{
1624    // mapping_info checking
1625    boot_check_mapping();
1626
1627    boot_puts("\n[BOOT] Mapping check completed at cycle ");
1628    boot_putw( boot_proctime() );
1629    boot_puts("\n");
1630
1631    // pseg allocators initialisation
1632    boot_psegs_init();
1633
1634    boot_puts("\n[BOOT] Pseg allocators initialisation completed at cycle ");
1635    boot_putw( boot_proctime() );
1636    boot_puts("\n");
1637
1638    // peripherals initialisation
1639    boot_peripherals_init();
1640
1641    boot_puts("\n[BOOT] Peripherals initialisation completed at cycle ");
1642    boot_putw( boot_proctime() );
1643    boot_puts("\n");
1644
1645    // page table building
1646    boot_pt_init();
1647
1648    boot_puts("\n[BOOT] Page Tables initialisation completed at cycle ");
1649    boot_putw( boot_proctime() );
1650    boot_puts("\n");
1651
1652    // mmu activation
1653    boot_set_mmu_ptpr( (unsigned int)boot_ptabs_paddr[0] >> 13 );
1654    boot_set_mmu_mode( 0xF );
1655
1656    boot_puts("\n[BOOT] MMU activation completed at cycle ");
1657    boot_putw( boot_proctime() );
1658    boot_puts("\n");
1659
1660    // vobjs initialisation
1661    boot_vobjs_init();
1662
1663    boot_puts("\n[BOOT] Vobjs initialisation completed at cycle : ");
1664    boot_putw( boot_proctime() );
1665    boot_puts("\n");
1666
1667    // schedulers initialisation
1668    boot_schedulers_init();
1669
1670    boot_puts("\n[BOOT] Schedulers initialisation completed at cycle ");
1671    boot_putw( boot_proctime() );
1672    boot_puts("\n");
1673
1674    // start all processors
1675    boot_start_all_procs();
1676
1677} // end boot_init()
1678
1679// Local Variables:
1680// tab-width: 4
1681// c-basic-offset: 4
1682// c-file-offsets:((innamespace . 0)(inline-open . 0))
1683// indent-tabs-mode: nil
1684// End:
1685// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1686
Note: See TracBrowser for help on using the repository browser.