source: soft/giet_vm/giet_boot/boot.c @ 259

Last change on this file since 259 was 258, checked in by alain, 11 years ago

This is a major release, including a deep restructuration of code.
The main evolutions are

  • use of the Tsar preloader to load the GIET boot-loader from disk
  • introduction of a FAT32 file system library,
  • use of this fat32 library by the boot-loader to load the map.bin data structure, and the various .elf files
  • reorganisation of drivers (one file per peripheral).
  • introduction of drivers for new peripherals: vci_chbuf_dma and vci_multi_ahci.
  • introduction of a new physical memory allocator in the boot code.

This release has been tested on the tsar_generic_iob architecture,
for the two following mappings: 4c_1p_iob_four.xml and 4c_1p_iob_sort.xml

File size: 74.0 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////////////
2// File     : boot.c
3// Date     : 01/11/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6//////////////////////////////////////////////////////////////////////////////////////////
7// The boot.c file is part of the GIET-VM nano-kernel.
8//
9// This nano-kernel has been written for the MIPS32 processor.
10// The virtual adresses are on 32 bits and use the (unsigned int) type, but the
11// physicals addresses can have up to 40 bits, and use the  (unsigned long long) type.
12// It natively supports clusterised shared mmemory multi-processors architectures,
13// where each processor is identified by a composite index (cluster_id, local_id),
14// and where there is one physical memory bank per cluster.
15//
16// This code is executed in the boot phase by proc[0] and performs the following tasks:
17// - load into memory the giet_vm binary files, contained in a FAT32 file system,
18// - build the various page tables (one page table per vspace)
19// - initialize the shedulers (one scheduler per processor)
20//
21// 1) The binary files to be loaded are:
22//    - the "map.bin" file contains the hardware architecture description and the
23//      mapping directives. It must be stored in the the seg_boot_mapping segment
24//      (at address seg_boot_mapping_base).
25//    - the "sys.elf" file contains the kernel binary code and data.
26//    - the various "application.elf" files.
27//
28// 2) The map.bin file contains the binary representation of the map.xml file defining:
29//    - the hardware architecture: number of clusters, number or processors,
30//      size of the memory segments, and peripherals in each cluster.
31//    - The structure of the various multi-threaded software applications:
32//      number of tasks, communication channels.
33//    - The mapping: placement of virtual objects (vobj) in the virtual segments (vseg),
34//      placement of virtual segments (vseg) in the physical segments (pseg), placement
35//      of software tasks on the processors,
36//
37// 3) The GIET-VM uses the paged virtual memory to provides two services:
38//    - classical memory protection, when several independant applications compiled
39//      in different virtual spaces are executing on the same hardware platform.
40//    - data placement in NUMA architectures, when we want to control the placement
41//      of the software objects (virtual segments) on the physical memory banks.
42//
43//    The page table are statically build in the boot phase, and they do not
44//    change during execution. The GIET uses only 4 Kbytes pages.
45//    As most applications use only a limited number of segments, the number of PT2s
46//    actually used by a given virtual space is generally smaller than 2048, and is
47//    computed during the boot phase.
48//    The max number of virtual spaces (GIET_NB_VSPACE_MAX) is a configuration parameter.
49//
50//    Each page table (one page table per virtual space) is monolithic, and contains
51//    one PT1 and up to (GIET_NB_PT2_MAX) PT2s. The PT1 is addressed using the ix1 field
52//    (11 bits) of the VPN, and the selected PT2 is addressed using the ix2 field (9 bits).
53//    - PT1[2048] : a first 8K aligned array of unsigned int, indexed by (ix1) field of VPN.
54//    Each entry in the PT1 contains a 32 bits PTD. The MSB bit PTD[31] is
55//    the PTD valid bit, and LSB bits PTD[19:0] are the 20 MSB bits of the physical base
56//    address of the selected PT2.
57//    The PT1 contains 2048 PTD of 4 bytes => 8K bytes.
58//    - PT2[1024][GIET_NB_PT2_MAX] : an array of array of unsigned int.
59//    Each PT2[1024] must be 4K aligned, each entry in a PT2 contains two unsigned int:
60//    the first word contains the protection flags, and the second word contains the PPN.
61//    Each PT2 contains 512 PTE2 of 8bytes => 4K bytes.
62//    The total size of a page table is finally = 8K + (GIET_NB_PT2_MAX)*4K bytes.
63////////////////////////////////////////////////////////////////////////////////////
64
65// for vobjs initialisation
66#include <mwmr_channel.h>
67#include <barrier.h>
68#include <memspace.h>
69#include <tty_driver.h>
70#include <xcu_driver.h>
71#include <ioc_driver.h>
72#include <dma_driver.h>
73#include <cma_driver.h>
74#include <nic_driver.h>
75#include <ioc_driver.h>
76#include <mwr_driver.h>
77#include <ctx_handler.h>
78#include <irq_handler.h>
79#include <vmem.h>
80#include <utils.h>
81#include <elf-types.h>
82
83// for boot FAT initialisation
84#include <fat32.h>
85
86#include <mips32_registers.h>
87#include <stdarg.h>
88
89#if !defined(NB_CLUSTERS)
90# error The NB_CLUSTERS value must be defined in the 'giet_config.h' file !
91#endif
92
93#if !defined(NB_PROCS_MAX)
94# error The NB_PROCS_MAX value must be defined in the 'giet_config.h' file !
95#endif
96
97#if !defined(GIET_NB_VSPACE_MAX)
98# error The GIET_NB_VSPACE_MAX value must be defined in the 'giet_config.h' file !
99#endif
100
101////////////////////////////////////////////////////////////////////////////
102//      Global variables for boot code
103// Both the page tables for the various virtual spaces, and the schedulers
104// for the processors are physically distributed on the clusters.
105// These global variables are just arrays of pointers.
106////////////////////////////////////////////////////////////////////////////
107
108// This global variable is allocated in "fat32.c" file
109extern fat32_fs_t fat;
110
111// Page table addresses arrays
112__attribute__((section (".bootdata"))) 
113paddr_t      _ptabs_paddr[GIET_NB_VSPACE_MAX];
114
115__attribute__((section (".bootdata"))) 
116unsigned int _ptabs_vaddr[GIET_NB_VSPACE_MAX];
117
118// Scheduler pointers array (virtual addresses)
119__attribute__((section (".bootdata"))) 
120static_scheduler_t* _schedulers[NB_CLUSTERS * NB_PROCS_MAX];
121
122// Next free PT2 index array
123__attribute__((section (".bootdata"))) 
124unsigned int _next_free_pt2[GIET_NB_VSPACE_MAX] =
125{ [0 ... GIET_NB_VSPACE_MAX - 1] = 0 };
126
127// Max PT2 index
128__attribute__((section (".bootdata"))) 
129unsigned int _max_pt2[GIET_NB_VSPACE_MAX] =
130{ [0 ... GIET_NB_VSPACE_MAX - 1] = 0 };
131
132
133/////////////////////////////////////////////////////////////////////
134// This function checks consistence beween the  mapping_info data
135// structure (soft), and the giet_config file (hard).
136/////////////////////////////////////////////////////////////////////
137void boot_mapping_check() 
138{
139    mapping_header_t * header = (mapping_header_t *) & seg_boot_mapping_base;
140
141    // checking mapping availability
142    if (header->signature != IN_MAPPING_SIGNATURE) 
143    {
144        _puts("\n[BOOT ERROR] Illegal mapping signature: ");
145        _putx(header->signature);
146        _puts("\n");
147        _exit();
148    }
149    // checking number of clusters
150    if (header->clusters != NB_CLUSTERS) 
151    {
152        _puts("\n[BOOT ERROR] Incoherent NB_CLUSTERS");
153        _puts("\n             - In giet_config,  value = ");
154        _putd(NB_CLUSTERS);
155        _puts("\n             - In mapping_info, value = ");
156        _putd(header->clusters);
157        _puts("\n");
158        _exit();
159    }
160    // checking number of virtual spaces
161    if (header->vspaces > GIET_NB_VSPACE_MAX) 
162    {
163        _puts("\n[BOOT ERROR] : number of vspaces > GIET_NB_VSPACE_MAX\n");
164        _puts("\n");
165        _exit();
166    }
167
168#if BOOT_DEBUG_MAPPING
169_puts("\n - clusters  = ");
170_putd( header->clusters );
171_puts("\n - procs     = ");
172_putd( header->procs );
173_puts("\n - periphs   = ");
174_putd( header->periphs );
175_puts("\n - vspaces   = ");
176_putd( header->vspaces );
177_puts("\n - tasks     = ");
178_putd( header->tasks );
179_puts("\n");
180_puts("\n - size of header  = ");
181_putd( MAPPING_HEADER_SIZE );
182_puts("\n - size of cluster = ");
183_putd( MAPPING_CLUSTER_SIZE );
184_puts("\n - size of pseg    = ");
185_putd( MAPPING_PSEG_SIZE );
186_puts("\n - size of proc    = ");
187_putd( MAPPING_PROC_SIZE );
188_puts("\n - size of vspace  = ");
189_putd( MAPPING_VSPACE_SIZE );
190_puts("\n - size of vseg    = ");
191_putd( MAPPING_VSEG_SIZE );
192_puts("\n - size of vobj    = ");
193_putd( MAPPING_VOBJ_SIZE );
194_puts("\n - size of task    = ");
195_putd( MAPPING_TASK_SIZE );
196_puts("\n");
197
198unsigned int        cluster_id;
199mapping_cluster_t * cluster = _get_cluster_base(header);
200for (cluster_id = 0; cluster_id < NB_CLUSTERS; cluster_id++) 
201{
202_puts("\n cluster = ");
203_putd( cluster_id );
204_puts("\n procs   = ");
205_putd( cluster[cluster_id].procs );
206_puts("\n psegs   = ");
207_putd( cluster[cluster_id].psegs );
208_puts("\n periphs = ");
209_putd( cluster[cluster_id].periphs );
210_puts("\n");
211}
212#endif
213
214} // end boot_mapping_check()
215
216
217//////////////////////////////////////////////////////////////////////////////
218//     boot_pseg_get()
219// This function returns the pointer on a physical segment
220// identified  by the pseg index.
221//////////////////////////////////////////////////////////////////////////////
222mapping_pseg_t *boot_pseg_get(unsigned int seg_id) 
223{
224    mapping_header_t* header = (mapping_header_t*)(&seg_boot_mapping_base);
225    mapping_pseg_t * pseg    = _get_pseg_base(header);
226
227    // checking argument
228    if (seg_id >= header->psegs) 
229    {
230        _puts("\n[BOOT ERROR] : seg_id argument too large\n");
231        _puts("               in function boot_pseg_get()\n");
232        _exit();
233    }
234
235    return &pseg[seg_id];
236} 
237
238//////////////////////////////////////////////////////////////////////////////
239// boot_add_pte()
240// This function registers a new PTE in the page table defined
241// by the vspace_id argument, and updates both PT1 and PT2.
242// A new PT2 is used when required.
243// As the set of PT2s is implemented as a fixed size array (no dynamic
244// allocation), this function checks a possible overflow of the PT2 array.
245//////////////////////////////////////////////////////////////////////////////
246void boot_add_pte(unsigned int vspace_id,
247                  unsigned int vpn, 
248                  unsigned int flags, 
249                  unsigned int ppn,
250                  unsigned int verbose) 
251{
252    unsigned int ix1;
253    unsigned int ix2;
254    paddr_t      pt1_pbase;     // PT1 physical base address
255    paddr_t      pt2_pbase;     // PT2 physical base address
256    paddr_t      pte_paddr;     // PTE physucal address
257    unsigned int pt2_id;        // PT2 index
258    unsigned int ptd;           // PTD : entry in PT1
259    unsigned int max_pt2;       // max number of PT2s for a given vspace
260
261    ix1 = vpn >> 9;         // 11 bits
262    ix2 = vpn & 0x1FF;      //  9 bits
263
264    // check that the _max_pt2[vspace_id] has been set
265    max_pt2 = _max_pt2[vspace_id];
266
267    if (max_pt2 == 0) 
268    {
269        _puts("Undefined page table for vspace ");
270        _putd(vspace_id);
271        _puts("\n");
272        _exit();
273    }
274
275
276    // get page table physical base address
277    pt1_pbase = _ptabs_paddr[vspace_id];
278
279    // get ptd in PT1
280    ptd = _physical_read(pt1_pbase + 4 * ix1);
281
282    if ((ptd & PTE_V) == 0)    // invalid PTD: compute PT2 base address,
283                               // and set a new PTD in PT1
284    {
285        pt2_id = _next_free_pt2[vspace_id];
286        if (pt2_id == max_pt2) 
287        {
288            _puts("\n[BOOT ERROR] in boot_add_pte() function\n");
289            _puts("the length of the ptab vobj is too small\n");
290
291            _puts(" max_pt2 = ");
292            _putd( max_pt2 );
293            _puts("\n");
294            _puts(" pt2_id  = ");
295            _putd( pt2_id );
296            _puts("\n");
297           
298            _exit();
299        }
300        else 
301        {
302            pt2_pbase = pt1_pbase + PT1_SIZE + PT2_SIZE * pt2_id;
303            ptd = PTE_V | PTE_T | (unsigned int) (pt2_pbase >> 12);
304            _physical_write( pt1_pbase + 4 * ix1, ptd);
305            _next_free_pt2[vspace_id] = pt2_id + 1;
306        }
307    }
308    else                       // valid PTD: compute PT2 base address
309    {
310        pt2_pbase = ((paddr_t)(ptd & 0x0FFFFFFF)) << 12;
311    }
312
313    // set PTE in PT2 : flags & PPN in two 32 bits words
314    pte_paddr = pt2_pbase + 8 * ix2;
315    _physical_write(pte_paddr    , flags);
316    _physical_write(pte_paddr + 4, ppn);
317
318    if (verbose)
319    {
320        _puts("     / pt1_pbase = ");
321        _putl( pt1_pbase );
322        _puts(" / ptd = ");
323        _putl( ptd );
324        _puts(" / pt2_pbase = ");
325        _putl( pt2_pbase );
326        _puts(" / pte_paddr = ");
327        _putl( pte_paddr );
328        _puts(" / ppn = ");
329        _putx( ppn );
330        _puts("/\n");
331    }
332
333}   // end boot_add_pte()
334
335
336/////////////////////////////////////////////////////////////////////
337// This function build the page table for a given vspace.
338// The physical base addresses for all vsegs (global and private)
339// must have been previously computed and stored in the mapping.
340// It initializes the MWMR channels.
341/////////////////////////////////////////////////////////////////////
342void boot_vspace_pt_build(unsigned int vspace_id) 
343{
344    unsigned int vseg_id;
345    unsigned int npages;
346    unsigned int ppn;
347    unsigned int vpn;
348    unsigned int flags;
349    unsigned int page_id;
350    unsigned int verbose = 0;   // can be used to activate trace in add_pte()
351
352    mapping_header_t * header = (mapping_header_t *) & seg_boot_mapping_base;
353    mapping_vspace_t * vspace = _get_vspace_base(header);
354    mapping_vseg_t   * vseg   = _get_vseg_base(header);
355
356    // private segments
357    for (vseg_id = vspace[vspace_id].vseg_offset;
358         vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs);
359         vseg_id++) 
360    {
361        vpn = vseg[vseg_id].vbase >> 12;
362        ppn = (unsigned int) (vseg[vseg_id].pbase >> 12);
363
364        npages = vseg[vseg_id].length >> 12;
365        if ((vseg[vseg_id].length & 0xFFF) != 0) npages++; 
366
367        flags = PTE_V;
368        if (vseg[vseg_id].mode & C_MODE_MASK) flags = flags | PTE_C;
369        if (vseg[vseg_id].mode & X_MODE_MASK) flags = flags | PTE_X;
370        if (vseg[vseg_id].mode & W_MODE_MASK) flags = flags | PTE_W;
371        if (vseg[vseg_id].mode & U_MODE_MASK) flags = flags | PTE_U;
372
373#if BOOT_DEBUG_PT
374        _puts(vseg[vseg_id].name);
375        _puts(" : flags = ");
376        _putx(flags);
377        _puts(" / npages = ");
378        _putd(npages);
379        _puts(" / pbase = ");
380        _putl(vseg[vseg_id].pbase);
381        _puts("\n");
382#endif
383        // loop on 4K pages
384        for (page_id = 0; page_id < npages; page_id++) 
385        {
386            boot_add_pte(vspace_id, vpn, flags, ppn, verbose);
387            vpn++;
388            ppn++;
389        }
390    }
391
392    // global segments
393    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
394    {
395        vpn = vseg[vseg_id].vbase >> 12;
396        ppn = (unsigned int)(vseg[vseg_id].pbase >> 12);
397        npages = vseg[vseg_id].length >> 12;
398        if ((vseg[vseg_id].length & 0xFFF) != 0) npages++;
399
400        flags = PTE_V;
401        if (vseg[vseg_id].mode & C_MODE_MASK)  flags = flags | PTE_C;
402        if (vseg[vseg_id].mode & X_MODE_MASK)  flags = flags | PTE_X;
403        if (vseg[vseg_id].mode & W_MODE_MASK)  flags = flags | PTE_W;
404        if (vseg[vseg_id].mode & U_MODE_MASK)  flags = flags | PTE_U;
405
406#if BOOT_DEBUG_PT
407        _puts(vseg[vseg_id].name);
408        _puts(" : flags = ");
409        _putx(flags);
410        _puts(" / npages = ");
411        _putd(npages);
412        _puts(" / pbase = ");
413        _putl(vseg[vseg_id].pbase);
414        _puts("\n");
415#endif
416        // loop on 4K pages
417        for (page_id = 0; page_id < npages; page_id++) 
418        {
419            boot_add_pte(vspace_id, vpn, flags, ppn, verbose);
420            vpn++;
421            ppn++;
422        }
423    }
424}   // end boot_vspace_pt_build()
425
426
427///////////////////////////////////////////////////////////////////////////
428// Align the value of paddr or vaddr to the required alignement,
429// defined by alignPow2 == L2(alignement).
430///////////////////////////////////////////////////////////////////////////
431paddr_t paddr_align_to(paddr_t paddr, unsigned int alignPow2) 
432{
433    paddr_t mask = (1 << alignPow2) - 1;
434    return ((paddr + mask) & ~mask);
435}
436
437unsigned int vaddr_align_to(unsigned int vaddr, unsigned int alignPow2) 
438{
439    unsigned int mask = (1 << alignPow2) - 1;
440    return ((vaddr + mask) & ~mask);
441}
442
443///////////////////////////////////////////////////////////////////////////
444// Set pbase for a vseg when identity mapping is required.
445// The length of the vseg must be known.
446// The ordered linked list of vsegs mapped on pseg must be updated,
447// and overlap with previously mapped vsegs must be checked.
448///////////////////////////////////////////////////////////////////////////
449void boot_vseg_set_paddr_ident(mapping_vseg_t * vseg) 
450{
451    // checking vseg not already mapped
452    if (vseg->mapped != 0) 
453    {
454        _puts("\n[BOOT ERROR] in boot_vseg_set_paddr_ident() : vseg ");
455        _puts( vseg->name );
456        _puts(" already mapped\n");
457        _exit();
458    }
459
460    // computes selected pseg pointer
461    mapping_pseg_t* pseg = boot_pseg_get( vseg->psegid );
462
463    // computes vseg alignment constraint
464    mapping_header_t* header    = (mapping_header_t*)&seg_boot_mapping_base;
465    mapping_vobj_t*   vobj_base = _get_vobj_base( header );
466    unsigned int      align     = vobj_base[vseg->vobj_offset].align;
467    if ( vobj_base[vseg->vobj_offset].align < 12 ) align = 12;
468
469    // computes required_pbase for identity mapping,
470    paddr_t required_pbase = (paddr_t)vseg->vbase;
471
472    // checks identity constraint against alignment constraint
473    if ( paddr_align_to( required_pbase, align) != required_pbase )
474    {
475        _puts("\n[BOOT ERROR] in boot_vseg_set_paddr_ident() : vseg ");
476        _puts( vseg->name );
477        _puts(" has uncompatible identity and alignment constraints\n");
478        _exit();
479    }
480
481    // We are looking for a contiguous space in target pseg.
482    // If there is vsegs already mapped, we scan the vsegs list to:
483    // - check overlap with already mapped vsegs,
484    // - try mapping in holes between already mapped vsegs,
485    // - update the ordered linked list if success
486    // We don't enter the loop if no vsegs is already mapped.
487    // implementation note: The next_vseg field is unsigned int,
488    // but we use it to store a MIP32 pointer on a vseg...
489
490    mapping_vseg_t*   curr      = 0;
491    mapping_vseg_t*   prev      = 0;
492    unsigned int      min_pbase = pseg->base;
493
494    for ( curr = (mapping_vseg_t*)pseg->next_vseg ; 
495          (curr != 0) && (vseg->mapped == 0) ; 
496          curr = (mapping_vseg_t*)curr->next_vseg )
497    {
498        // looking before current vseg
499        if( (required_pbase >= min_pbase) && 
500            (curr->pbase >= (required_pbase + vseg->length)) ) // space found
501        {
502            vseg->pbase  = required_pbase;
503            vseg->mapped = 1;
504
505            // update linked list
506            vseg->next_vseg = (unsigned int)curr;
507            if( curr == (mapping_vseg_t*)pseg->next_vseg ) 
508                pseg->next_vseg = (unsigned int)vseg;
509            else
510                prev->next_vseg = (unsigned int)vseg;
511        }
512        else                                         // looking in space after curr
513        {
514            prev = curr;
515            min_pbase = curr->pbase + curr->length;
516        }
517    }
518
519    // no success in the loop
520    if( (vseg->mapped == 0) &&
521        (required_pbase >= min_pbase) && 
522        ((required_pbase + vseg->length) <= (pseg->base + pseg->length)) )
523    {
524        vseg->pbase  = required_pbase;
525        vseg->mapped = 1;
526
527        // update linked list
528        vseg->next_vseg = 0;
529        if ((curr == 0) && (prev == 0)) pseg->next_vseg = (unsigned int)vseg;
530        else                            prev->next_vseg = (unsigned int)vseg;
531    }
532
533    if( vseg->mapped == 0 )
534    {
535        _puts("\n[BOOT ERROR] in boot_vseg_set_paddr_ident() : vseg ");
536        _puts( vseg->name );
537        _puts(" cannot be mapped on pseg ");
538        _puts( pseg->name );
539        _puts("\n");
540        _exit();
541    }
542}  // end boot_vseg_set_paddr_ident()
543
544               
545////////////////////////////////////////////////////////////////////////////
546// Set pbase for a vseg when there is no identity mapping constraint.
547// This is the physical memory allocator (written by Q.Meunier).
548// The length of the vseg must be known.
549// All identity mapping vsegs must be already mapped.
550// We use a linked list of already mapped vsegs, ordered by incresing pbase.
551// We try to place the vseg in the "first fit" hole in this list.
552////////////////////////////////////////////////////////////////////////////
553void boot_vseg_set_paddr(mapping_vseg_t * vseg) 
554{
555    // checking vseg not already mapped
556    if ( vseg->mapped != 0 ) 
557    {
558        _puts("\n[BOOT ERROR] in boot_vseg_set_paddr() : vseg ");
559        _puts( vseg->name );
560        _puts(" already mapped\n");
561        _exit();
562    }
563
564    // computes selected pseg pointer
565    mapping_pseg_t*   pseg      = boot_pseg_get( vseg->psegid );
566
567    // computes vseg alignment constraint
568    mapping_header_t* header    = (mapping_header_t*)&seg_boot_mapping_base;
569    mapping_vobj_t*   vobj_base = _get_vobj_base( header );
570    unsigned int      align     = vobj_base[vseg->vobj_offset].align;
571    if ( vobj_base[vseg->vobj_offset].align < 12 ) align = 12;
572
573    // initialise physical base address, with alignment constraint
574    paddr_t possible_pbase = paddr_align_to( pseg->base, align );
575
576    // We are looking for a contiguous space in target pseg
577    // If there is vsegs already mapped, we scan the vsegs list to:
578    // - try mapping in holes between already mapped vsegs,
579    // - update the ordered linked list if success
580    // We don't enter the loop if no vsegs is already mapped.
581    // implementation note: The next_vseg field is unsigned int,
582    // but we use it to store a MIP32 pointer on a vseg...
583
584    mapping_vseg_t*   curr = 0;
585    mapping_vseg_t*   prev = 0;
586
587    for( curr = (mapping_vseg_t*)pseg->next_vseg ; 
588         (curr != 0) && (vseg->mapped == 0) ; 
589         curr = (mapping_vseg_t*)curr->next_vseg )
590    {
591        // looking for space before current vseg
592        if ( (curr->pbase >= possible_pbase + vseg->length) ) // space before curr
593        {
594            vseg->pbase  = possible_pbase;
595            vseg->mapped = 1;
596
597            // update linked list
598            vseg->next_vseg = (unsigned int)curr;
599            if( curr == (mapping_vseg_t*)pseg->next_vseg ) 
600                pseg->next_vseg = (unsigned int)vseg;
601            else
602                prev->next_vseg = (unsigned int)vseg;
603        }
604        else                                            // looking for space after curr
605        {
606            possible_pbase = paddr_align_to( curr->pbase + curr->length, align );
607            prev           = curr;
608        }
609    }
610       
611    // when no space found, try to allocate space after already mapped vsegs
612    if( (vseg->mapped == 0) &&
613        ((possible_pbase + vseg->length) <= (pseg->base + pseg->length)) )
614    {
615        vseg->pbase  = possible_pbase;
616        vseg->mapped = 1;
617
618        // update linked list
619        vseg->next_vseg = 0;
620        if ((curr == 0 ) && (prev == 0)) pseg->next_vseg = (unsigned int)vseg;
621        else                             prev->next_vseg = (unsigned int)vseg;
622    }
623
624    if( vseg->mapped == 0 )
625    {
626        _puts("\n[BOOT ERROR] in boot_vseg_set_paddr() : vseg ");
627        _puts( vseg->name );
628        _puts(" cannot be mapped on pseg ");
629        _puts( pseg->name );
630        _puts("\n");
631        _exit();
632    }
633}  // end boot_vseg_set_paddr()
634
635///////////////////////////////////////////////////////////////////////////
636// This function computes the physical base address for a vseg
637// as specified in the mapping info data structure.
638// It updates the pbase and the length fields of the vseg.
639// It updates the pbase and vbase fields of all vobjs in the vseg.
640// It updates the _ptabs_paddr[] and _ptabs_vaddr[] arrays.
641// It is a global vseg if vspace_id = (-1).
642///////////////////////////////////////////////////////////////////////////
643void boot_vseg_map(mapping_vseg_t * vseg, unsigned int vspace_id) 
644{
645    unsigned int vobj_id;
646    unsigned int cur_vaddr;
647    paddr_t      cur_paddr;
648    paddr_t      cur_length;
649    unsigned int offset;
650
651    mapping_header_t * header = (mapping_header_t *) & seg_boot_mapping_base;
652    mapping_vobj_t   * vobj   = _get_vobj_base(header);
653
654    // loop on the vobjs contained in vseg to compute
655    // the vseg length, required for mapping.
656    cur_length = 0;
657    for ( vobj_id = vseg->vobj_offset; 
658          vobj_id < (vseg->vobj_offset + vseg->vobjs); 
659          vobj_id++ ) 
660    {
661        if (vobj[vobj_id].align)
662        {
663            cur_length = vaddr_align_to(cur_length, vobj[vobj_id].align);
664        }
665        cur_length += vobj[vobj_id].length;
666    }
667    vseg->length = paddr_align_to(cur_length, 12);
668
669    // mapping: computes vseg pbase address
670    if (vseg->ident != 0)                         // identity mapping
671    {
672        boot_vseg_set_paddr_ident( vseg );
673    }
674    else                                          // unconstrained mapping
675    {
676        boot_vseg_set_paddr( vseg );
677    }
678
679    // second loop on vobjs contained in vseg to :
680    // initialize the vaddr and paddr fields of all vobjs,
681    // and initialize the page table pointers arrays
682
683    cur_vaddr = vseg->vbase;
684    cur_paddr = vseg->pbase;
685
686    for (vobj_id = vseg->vobj_offset; 
687         vobj_id < (vseg->vobj_offset + vseg->vobjs); vobj_id++) 
688    {
689        if (vobj[vobj_id].align) 
690        {
691            cur_paddr = paddr_align_to(cur_paddr, vobj[vobj_id].align);
692            cur_vaddr = vaddr_align_to(cur_vaddr, vobj[vobj_id].align);
693        }
694        // set vaddr/paddr for current vobj
695        vobj[vobj_id].vaddr = cur_vaddr;
696        vobj[vobj_id].paddr = cur_paddr;
697       
698        // initialize _ptabs_vaddr[] & boot_ptabs-paddr[] if PTAB
699        if (vobj[vobj_id].type == VOBJ_TYPE_PTAB) 
700        {
701            if (vspace_id == ((unsigned int) -1))    // global vseg
702            {
703                _puts("\n[BOOT ERROR] in boot_vseg_map() function: ");
704                _puts("a PTAB vobj cannot be global");
705                _exit();
706            }
707            // we need at least one PT2
708            if (vobj[vobj_id].length < (PT1_SIZE + PT2_SIZE)) 
709            {
710                _puts("\n[BOOT ERROR] in boot_vseg_map() function, ");
711                _puts("PTAB too small, minumum size is: ");
712                _putx(PT1_SIZE + PT2_SIZE);
713                _exit();
714            }
715            // register both physical and virtual page table address
716            _ptabs_vaddr[vspace_id] = vobj[vobj_id].vaddr;
717            _ptabs_paddr[vspace_id] = vobj[vobj_id].paddr;
718           
719            // reset all valid bits in PT1
720            for ( offset = 0 ; offset < 8192 ; offset = offset + 4)
721            {
722                _physical_write(cur_paddr + offset, 0);
723            }
724
725            // computing the number of second level pages
726            _max_pt2[vspace_id] = (vobj[vobj_id].length - PT1_SIZE) / PT2_SIZE;
727        }
728
729        // set next vaddr/paddr
730        cur_vaddr = cur_vaddr + vobj[vobj_id].length;
731        cur_paddr = cur_paddr + vobj[vobj_id].length;
732    } // end for vobjs
733
734}    // end boot_vseg_map()
735
736/////////////////////////////////////////////////////////////////////
737// This function builds the page tables for all virtual spaces
738// defined in the mapping_info data structure, in three steps:
739// - step 1 : It computes the physical base address for global vsegs
740//            and for all associated vobjs.
741// - step 2 : It computes the physical base address for all private
742//            vsegs and all vobjs in each virtual space.
743// - step 3 : It actually fill the page table for each vspace.
744//
745// Note: It must exist at least one vspace in the mapping_info...
746/////////////////////////////////////////////////////////////////////
747void boot_pt_init() 
748{
749    mapping_header_t * header = (mapping_header_t *) &seg_boot_mapping_base;
750    mapping_vspace_t * vspace = _get_vspace_base(header);
751    mapping_vseg_t   * vseg   = _get_vseg_base(header);
752
753    unsigned int vspace_id;
754    unsigned int vseg_id;
755
756    if (header->vspaces == 0 )
757    {
758        _puts("\n[BOOT ERROR] in boot_pt_init() : mapping ");
759        _puts( header->name );
760        _puts(" contains no vspace\n");
761        _exit();
762    }
763
764#if BOOT_DEBUG_PT
765_puts("\n[BOOT DEBUG] ****** mapping global vsegs ******\n");
766#endif
767
768    // step 1 : loop on global vsegs
769
770    // vsegs with identity mapping constraint first
771    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
772    {
773        if (vseg[vseg_id].ident == 1) 
774            boot_vseg_map(&vseg[vseg_id], ((unsigned int) (-1)));
775    }
776
777    // unconstrained vsegs second
778    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
779    {
780        if (vseg[vseg_id].ident == 0) 
781            boot_vseg_map(&vseg[vseg_id], ((unsigned int) (-1)));
782    }
783
784    // step 2 : loop on virtual vspaces to map private vsegs
785    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
786    {
787
788#if BOOT_DEBUG_PT
789_puts("\n[BOOT DEBUG] ****** mapping private vsegs in vspace ");
790_puts(vspace[vspace_id].name);
791_puts(" ******\n");
792#endif
793
794        // vsegs with identity mapping constraint first
795        for (vseg_id = vspace[vspace_id].vseg_offset;
796             vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs);
797             vseg_id++) 
798        {
799            if (vseg[vseg_id].ident == 1) 
800                boot_vseg_map(&vseg[vseg_id], vspace_id);
801        }
802        // unconstrained vsegs second
803        for (vseg_id = vspace[vspace_id].vseg_offset;
804             vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs);
805             vseg_id++) 
806        {
807            if (vseg[vseg_id].ident == 0)
808                boot_vseg_map(&vseg[vseg_id], vspace_id);
809        }
810    }
811
812#if BOOT_DEBUG_PT
813mapping_vseg_t* curr;
814mapping_pseg_t* pseg = _get_pseg_base(header);
815unsigned int    pseg_id;
816for( pseg_id = 0 ; pseg_id < header->psegs ; pseg_id++ )
817{
818    _puts("\n[BOOT DEBUG] ****** vsegs mapped on pseg ");
819    _puts( pseg[pseg_id].name );
820    _putd( pseg[pseg_id].cluster);
821    _puts(" ******\n");
822    for( curr = (mapping_vseg_t*)pseg[pseg_id].next_vseg ;
823         curr != 0 ;
824         curr = (mapping_vseg_t*)curr->next_vseg )
825    {
826        _puts(" - vseg ");
827        _puts( curr->name );
828        _puts(" : len = ");
829        _putx( curr->length );
830        _puts(" / vbase ");
831        _putl( curr->vbase );
832        _puts(" / pbase ");
833        _putl( curr->pbase );
834        _puts("\n");
835    } 
836}
837#endif
838
839    // step 3 : loop on the vspaces to build the page tables
840    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
841    {
842
843#if BOOT_DEBUG_PT
844_puts("\n[BOOT DEBUG] ****** building page table for vspace ");
845_puts(vspace[vspace_id].name);
846_puts(" ******\n");
847#endif
848
849        boot_vspace_pt_build(vspace_id);
850
851        _puts("\n[BOOT] Page Table for vspace ");
852        _puts( vspace[vspace_id].name );
853        _puts(" completed at cycle ");
854        _putd( _get_proctime() );
855        _puts("\n");
856
857#if BOOT_DEBUG_PT
858_puts("  vaddr = ");
859_putx( _ptabs_vaddr[vspace_id] );
860_puts(" / paddr = ");
861_putl( _ptabs_paddr[vspace_id] );
862_puts(" / PT2 number = ");
863_putd( _max_pt2[vspace_id] );
864_puts("\n");
865#endif
866    }
867} // end boot_pt_init()
868
869///////////////////////////////////////////////////////////////////////////////
870// This function initializes all private vobjs defined in the vspaces,
871// such as mwmr channels, barriers and locks, because these vobjs
872// are not known, and not initialized by the compiler.
873// The MMU is supposed to be activated...
874///////////////////////////////////////////////////////////////////////////////
875void boot_vobjs_init() 
876{
877    mapping_header_t* header = (mapping_header_t *) & seg_boot_mapping_base;
878    mapping_vspace_t* vspace = _get_vspace_base(header);
879    mapping_vobj_t* vobj     = _get_vobj_base(header);
880
881    unsigned int vspace_id;
882    unsigned int vobj_id;
883
884    // loop on the vspaces
885    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
886    {
887
888#if BOOT_DEBUG_VOBJS
889_puts("\n[BOOT DEBUG] ****** vobjs initialisation in vspace ");
890_puts(vspace[vspace_id].name);
891_puts(" ******\n");
892#endif
893
894        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id] >> 13) );
895
896        unsigned int ptab_found = 0;
897
898        // loop on the vobjs
899        for (vobj_id = vspace[vspace_id].vobj_offset;
900             vobj_id < (vspace[vspace_id].vobj_offset + vspace[vspace_id].vobjs);
901             vobj_id++) 
902        {
903            switch (vobj[vobj_id].type) 
904            {
905                case VOBJ_TYPE_MWMR:    // storage capacity is (vobj.length/4 - 5) words
906                {
907                    mwmr_channel_t* mwmr = (mwmr_channel_t *) (vobj[vobj_id].vaddr);
908                    mwmr->ptw = 0;
909                    mwmr->ptr = 0;
910                    mwmr->sts = 0;
911                    mwmr->width = vobj[vobj_id].init;
912                    mwmr->depth = (vobj[vobj_id].length >> 2) - 6;
913                    mwmr->lock = 0;
914#if BOOT_DEBUG_VOBJS
915_puts("MWMR    : ");
916_puts(vobj[vobj_id].name);
917_puts(" / depth = ");
918_putd(mwmr->depth);
919_puts(" / width = ");
920_putd(mwmr->width);
921_puts("\n");
922#endif
923                    break;
924                }
925                case VOBJ_TYPE_ELF:    // initialisation done by the loader
926                {
927#if BOOT_DEBUG_VOBJS
928_puts("ELF     : ");
929_puts(vobj[vobj_id].name);
930_puts(" / length = ");
931_putx(vobj[vobj_id].length);
932_puts("\n");
933#endif
934                    break;
935                }
936                case VOBJ_TYPE_BLOB:    // initialisation done by the loader
937                {
938#if BOOT_DEBUG_VOBJS
939_puts("BLOB     : ");
940_puts(vobj[vobj_id].name);
941_puts(" / length = ");
942_putx(vobj[vobj_id].length);
943_puts("\n");
944#endif
945                    break;
946                }
947                case VOBJ_TYPE_BARRIER:    // init is the number of participants
948                {
949                    giet_barrier_t* barrier = (giet_barrier_t *) (vobj[vobj_id].vaddr);
950                    barrier->count = vobj[vobj_id].init;
951                    barrier->init = vobj[vobj_id].init;
952#if BOOT_DEBUG_VOBJS
953_puts("BARRIER : ");
954_puts(vobj[vobj_id].name);
955_puts(" / init_value = ");
956_putd(barrier->init);
957_puts("\n");
958#endif
959                    break;
960                }
961                case VOBJ_TYPE_LOCK:    // init value is "not taken"
962                {
963                    unsigned int* lock = (unsigned int *) (vobj[vobj_id].vaddr);
964                    *lock = 0;
965#if BOOT_DEBUG_VOBJS
966_puts("LOCK    : ");
967_puts(vobj[vobj_id].name);
968_puts("\n");
969#endif
970                    break;
971                }
972                case VOBJ_TYPE_BUFFER:    // nothing to initialise
973                {
974#if BOOT_DEBUG_VOBJS
975_puts("BUFFER  : ");
976_puts(vobj[vobj_id].name);
977_puts(" / paddr = ");
978_putl(vobj[vobj_id].paddr);
979_puts(" / length = ");
980_putx(vobj[vobj_id].length);
981_puts("\n");
982#endif
983                    break;
984                }
985                case VOBJ_TYPE_MEMSPACE:
986                {
987                    giet_memspace_t* memspace = (giet_memspace_t *) vobj[vobj_id].vaddr;
988                    memspace->buffer = (void *) vobj[vobj_id].vaddr + 8;
989                    memspace->size = vobj[vobj_id].length - 8;
990#if BOOT_DEBUG_VOBJS
991_puts("MEMSPACE  : ");
992_puts(vobj[vobj_id].name);
993_puts(" / vaddr = ");
994_putx(vobj[vobj_id].vaddr);
995_puts(" / length = ");
996_putx(vobj[vobj_id].length);
997_puts(" / buffer = ");
998_putx((unsigned int)memspace->buffer);
999_puts(" / size = ");
1000_putx(memspace->size);
1001_puts("\n");
1002#endif
1003                    break;
1004                }
1005                case VOBJ_TYPE_PTAB:    // nothing to initialize
1006                {
1007                    ptab_found = 1;
1008#if BOOT_DEBUG_VOBJS
1009_puts("PTAB    : ");
1010_puts(vobj[vobj_id].name);
1011_puts(" / length = ");
1012_putx(vobj[vobj_id].length);
1013_puts("\n");
1014#endif
1015                    break;
1016                }
1017                case VOBJ_TYPE_CONST:
1018                {
1019                    unsigned int* addr = (unsigned int *) vobj[vobj_id].vaddr;
1020                    *addr = vobj[vobj_id].init;
1021#if BOOT_DEBUG_VOBJS
1022_puts("CONST   : ");
1023_puts(vobj[vobj_id].name);
1024_puts(" / Paddr :");
1025_putl(vobj[vobj_id].paddr);
1026_puts(" / init = ");
1027_putx(*addr);
1028_puts("\n");
1029#endif
1030                    break;
1031                }
1032                default:
1033                {
1034                    _puts("\n[BOOT ERROR] illegal vobj type: ");
1035                    _putd(vobj[vobj_id].type);
1036                    _puts("\n");
1037                    _exit();
1038                }
1039            }            // end switch type
1040        }            // end loop on vobjs
1041        if (ptab_found == 0) 
1042        {
1043            _puts("\n[BOOT ERROR] Missing PTAB for vspace ");
1044            _putd(vspace_id);
1045            _exit();
1046        }
1047    } // end loop on vspaces
1048
1049} // end boot_vobjs_init()
1050
1051///////////////////////////////////////////////////////////////////////////////
1052// This function returns in the vbase and length buffers the virtual base
1053// address and the length of the  segment allocated to the schedulers array
1054// in the cluster defined by the clusterid argument.
1055///////////////////////////////////////////////////////////////////////////////
1056void boot_get_sched_vaddr( unsigned int  cluster_id,
1057                           unsigned int* vbase, 
1058                           unsigned int* length )
1059{
1060    mapping_header_t* header = (mapping_header_t *) & seg_boot_mapping_base;
1061    mapping_vobj_t*   vobj   = _get_vobj_base(header);
1062    mapping_vseg_t*   vseg   = _get_vseg_base(header);
1063    mapping_pseg_t*   pseg   = _get_pseg_base(header);
1064
1065    unsigned int vseg_id;
1066    unsigned int found = 0;
1067
1068    for ( vseg_id = 0 ; (vseg_id < header->vsegs) && (found == 0) ; vseg_id++ )
1069    {
1070        if ( (vobj[vseg[vseg_id].vobj_offset].type == VOBJ_TYPE_SCHED) && 
1071             (pseg[vseg[vseg_id].psegid].cluster == cluster_id ) )
1072        {
1073            *vbase  = vseg[vseg_id].vbase;
1074            *length = vobj[vseg[vseg_id].vobj_offset].length;
1075            found = 1;
1076        }
1077    }
1078    if ( found == 0 )
1079    {
1080        _puts("\n[BOOT ERROR] No vobj of type SCHED in cluster ");
1081        _putd(cluster_id);
1082        _puts("\n");
1083        _exit();
1084    }
1085} // end boot_get_sched_vaddr()
1086
1087////////////////////////////////////////////////////////////////////////////////////
1088// This function initialises all processors schedulers.
1089// This is done by processor 0, and the MMU must be activated.
1090// - In Step 1, it initialises the _schedulers[gpid] pointers array, and scan
1091//              the processors to initialise the schedulers, including the
1092//              idle_task context (ltid == 14).
1093// - In Step 2, it scan all tasks in all vspaces to initialise the tasks contexts,
1094//              as specified in the mapping_info data structure.
1095////////////////////////////////////////////////////////////////////////////////////
1096void boot_schedulers_init() 
1097{
1098    mapping_header_t*  header  = (mapping_header_t *) & seg_boot_mapping_base;
1099    mapping_cluster_t* cluster = _get_cluster_base(header);
1100    mapping_vspace_t*  vspace  = _get_vspace_base(header);
1101    mapping_task_t*    task    = _get_task_base(header);
1102    mapping_vobj_t*    vobj    = _get_vobj_base(header);
1103    mapping_proc_t*    proc    = _get_proc_base(header);
1104    mapping_irq_t*     irq     = _get_irq_base(header);
1105
1106    unsigned int cluster_id;    // cluster index in mapping_info
1107    unsigned int proc_id;       // processor index in mapping_info
1108    unsigned int irq_id;        // irq index in mapping_info
1109    unsigned int vspace_id;     // vspace index in mapping_info
1110    unsigned int task_id;       // task index in mapping_info
1111
1112    // TTY, NIC, CMA, HBA, TIM and DMA channels allocators
1113    // - TTY[0] is reserved for the kernel
1114    // - In all clusters the first NB_PROCS_MAX timers
1115    //   are reserved for the kernel (context switch)
1116
1117    unsigned int alloc_tty_channel = 1;            // TTY channel allocator
1118    unsigned int alloc_nic_channel = 0;            // NIC channel allocator
1119    unsigned int alloc_cma_channel = 0;            // CMA channel allocator
1120    unsigned int alloc_hba_channel = 0;            // IOC channel allocator
1121    unsigned int alloc_tim_channel[NB_CLUSTERS];   // user TIMER allocators
1122
1123    /////////////////////////////////////////////////////////////////////////
1124    // Step 1 : loop on the clusters and on the processors
1125    //          to initialize the schedulers[] array of pointers,
1126    //          and the interrupt vectors.
1127    // Implementation note:
1128    // We need to use both proc_id to scan the mapping info structure,
1129    // and lpid to access the schedulers array.
1130    // - the _schedulers[] array of pointers can contain "holes", because
1131    //   it is indexed by the global pid = cluster_id*NB_PROCS_MAX + lpid
1132    // - the mapping info array of processors is contiguous, it is indexed
1133    //   by proc_id, and use an offset specific in each cluster.
1134
1135    for (cluster_id = 0; cluster_id < header->clusters; cluster_id++) 
1136    {
1137
1138#if BOOT_DEBUG_SCHED
1139_puts("\n[BOOT DEBUG] Initialise schedulers in cluster ");
1140_putd(cluster_id);
1141_puts("\n");
1142#endif
1143
1144        alloc_tim_channel[cluster_id] = NB_PROCS_MAX;
1145
1146        unsigned int  lpid;          // processor local index in cluster
1147        unsigned int  sched_vbase;   // schedulers segment virtual base address
1148        unsigned int  sched_length;  // schedulers segment length
1149        unsigned int  nprocs;        // number of processors in cluster
1150
1151        nprocs = cluster[cluster_id].procs;
1152
1153        // checking processors number
1154        if ( nprocs > NB_PROCS_MAX )
1155        {
1156            _puts("\n[BOOT ERROR] Too much processors in cluster ");
1157            _putd(cluster_id);
1158            _puts("\n");
1159            _exit();
1160        }
1161 
1162        // get scheduler array virtual base address and length
1163        boot_get_sched_vaddr( cluster_id, &sched_vbase, &sched_length );
1164
1165        // each processor scheduler requires 4 Kbytes
1166        if ( sched_length < (nprocs<<12) ) 
1167        {
1168            _puts("\n[BOOT ERROR] Schedulers segment too small in cluster ");
1169            _putd(cluster_id);
1170            _puts("\n");
1171            _exit();
1172        }
1173
1174        // loop on processors
1175        for ( proc_id = cluster[cluster_id].proc_offset, lpid = 0 ;
1176              proc_id < cluster[cluster_id].proc_offset + cluster[cluster_id].procs;
1177              proc_id++, lpid++ ) 
1178        {
1179            // set the schedulers pointers array
1180            _schedulers[cluster_id * NB_PROCS_MAX + lpid] =
1181               (static_scheduler_t*)( sched_vbase + (lpid<<12) );
1182
1183#if BOOT_DEBUG_SCHED
1184_puts("\nProc_");
1185_putd(lpid);
1186_puts("_");
1187_putd(cluster_id);
1188_puts(" : scheduler virtual base address = ");
1189_putx( sched_vbase + (lpid<<12) );
1190_puts("\n");
1191#endif
1192            // current processor scheduler pointer : psched
1193            static_scheduler_t* psched = (static_scheduler_t*)(sched_vbase+(lpid<<12));
1194
1195            // initialise the "tasks" variable : default value is 0
1196            psched->tasks = 0;
1197
1198            // initialise the "current" variable : default value is idle_task
1199            psched->current = IDLE_TASK_INDEX;
1200
1201            // initialise interrupt_vector with default value (valid bit = 0)
1202            unsigned int slot;
1203            for (slot = 0; slot < 32; slot++) psched->interrupt_vector[slot] = 0;
1204
1205            // initialise interrupt vector with the IRQs actually allocated
1206            for (irq_id = proc[proc_id].irq_offset;
1207                 irq_id < proc[proc_id].irq_offset + proc[proc_id].irqs;
1208                 irq_id++) 
1209            {
1210                unsigned int type    = irq[irq_id].type;
1211                unsigned int icu_id  = irq[irq_id].icuid;
1212                unsigned int isr_id  = irq[irq_id].isr;
1213                unsigned int channel = irq[irq_id].channel;
1214
1215                unsigned int value = ((isr_id  & 0xFF)        ) | 
1216                                     ((type    & 0xFF)   <<  8) | 
1217                                     ((channel & 0x7FFF) << 16) | 
1218                                     0x80000000;                    // Valid entry
1219
1220                psched->interrupt_vector[icu_id] = value;
1221
1222#if BOOT_DEBUG_SCHED
1223_puts("- IRQ : icu = ");
1224_putd(icu_id);
1225_puts(" / type = ");
1226_putd(type);
1227_puts(" / isr = ");
1228_putd(isr_id);
1229_puts(" / channel = ");
1230_putd(channel);
1231_puts(" => vector_entry = ");
1232_putx( value );
1233_puts("\n");
1234#endif
1235            }
1236
1237            // initializes the idle_task context in scheduler:
1238            // - the SR slot is 0xFF03 because this task run in kernel mode.
1239            // - it uses the page table of vspace[0]
1240            // - it uses the kernel TTY terminal
1241            // - slots containing addresses (SP, RA, EPC, PTAB, PTPR)
1242            //   must be re-initialised by kernel_parallel_init()
1243
1244            psched->context[IDLE_TASK_INDEX][CTX_SR_ID]    = 0xFF03;
1245            psched->context[IDLE_TASK_INDEX][CTX_PTPR_ID]  = _ptabs_paddr[0]>>13;
1246            psched->context[IDLE_TASK_INDEX][CTX_PTAB_ID]  = _ptabs_vaddr[0];
1247            psched->context[IDLE_TASK_INDEX][CTX_TTY_ID]   = 0;
1248            psched->context[IDLE_TASK_INDEX][CTX_LTID_ID]  = IDLE_TASK_INDEX;
1249            psched->context[IDLE_TASK_INDEX][CTX_VSID_ID]  = 0;
1250            psched->context[IDLE_TASK_INDEX][CTX_RUN_ID]   = 1;
1251
1252        } // end for procs
1253    } // end for clusters
1254
1255    ///////////////////////////////////////////////////////////////////
1256    // Step 2 : loop on the vspaces and the tasks
1257    //          to initialise the schedulers and the task contexts.
1258
1259    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
1260    {
1261        // We must set the PTPR depending on the vspace, because the start_vector
1262        // and the stack address are defined in virtual space.
1263        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id] >> 13) );
1264
1265        // loop on the tasks in vspace (task_id is the global index)
1266        for (task_id = vspace[vspace_id].task_offset;
1267             task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks);
1268             task_id++) 
1269        {
1270
1271#if BOOT_DEBUG_SCHED
1272_puts("\n[BOOT DEBUG] Initialise context for task ");
1273_puts( task[task_id].name );
1274_puts(" in vspace ");
1275_puts( vspace[vspace_id].name );
1276_puts("\n");
1277#endif
1278            // compute gpid (global processor index) and scheduler base address
1279            unsigned int gpid = task[task_id].clusterid * NB_PROCS_MAX + 
1280                                task[task_id].proclocid;
1281            static_scheduler_t* psched = _schedulers[gpid];
1282
1283            // ctx_sr : value required before an eret instruction
1284            unsigned int ctx_sr = 0x0000FF13;
1285
1286            // ctx_ptpr : page table physical base address (shifted by 13 bit)
1287            unsigned int ctx_ptpr = (unsigned int)(_ptabs_paddr[vspace_id] >> 13);
1288
1289            // ctx_ptab : page_table virtual base address
1290            unsigned int ctx_ptab = _ptabs_vaddr[vspace_id];
1291
1292            // ctx_tty : TTY terminal global index provided by the global allocator
1293            unsigned int ctx_tty = 0xFFFFFFFF;
1294            if (task[task_id].use_tty) 
1295            {
1296                if (alloc_tty_channel >= NB_TTY_CHANNELS) 
1297                {
1298                    _puts("\n[BOOT ERROR] TTY index too large for task ");
1299                    _puts(task[task_id].name);
1300                    _puts(" in vspace ");
1301                    _puts(vspace[vspace_id].name);
1302                    _puts("\n");
1303                    _exit();
1304                }
1305                ctx_tty = alloc_tty_channel;
1306                alloc_tty_channel++;
1307            }
1308            // ctx_nic : NIC channel global index provided by the global allocator
1309            unsigned int ctx_nic = 0xFFFFFFFF;
1310            if (task[task_id].use_nic) 
1311            {
1312                if (alloc_nic_channel >= NB_NIC_CHANNELS) 
1313                {
1314                    _puts("\n[BOOT ERROR] NIC channel index too large for task ");
1315                    _puts(task[task_id].name);
1316                    _puts(" in vspace ");
1317                    _puts(vspace[vspace_id].name);
1318                    _puts("\n");
1319                    _exit();
1320                }
1321                ctx_nic = alloc_nic_channel;
1322                alloc_nic_channel++;
1323            }
1324            // ctx_cma : CMA channel global index provided by the global allocator
1325            unsigned int ctx_cma = 0xFFFFFFFF;
1326            if (task[task_id].use_cma) 
1327            {
1328                if (alloc_cma_channel >= NB_CMA_CHANNELS) 
1329                {
1330                    _puts("\n[BOOT ERROR] CMA channel index too large for task ");
1331                    _puts(task[task_id].name);
1332                    _puts(" in vspace ");
1333                    _puts(vspace[vspace_id].name);
1334                    _puts("\n");
1335                    _exit();
1336                }
1337                ctx_cma = alloc_cma_channel;
1338                alloc_cma_channel++;
1339            }
1340            // ctx_hba : HBA channel global index provided by the global allocator
1341            unsigned int ctx_hba = 0xFFFFFFFF;
1342            if (task[task_id].use_hba) 
1343            {
1344                if (alloc_hba_channel >= NB_HBA_CHANNELS) 
1345                {
1346                    _puts("\n[BOOT ERROR] IOC channel index too large for task ");
1347                    _puts(task[task_id].name);
1348                    _puts(" in vspace ");
1349                    _puts(vspace[vspace_id].name);
1350                    _puts("\n");
1351                    _exit();
1352                }
1353                ctx_hba = alloc_hba_channel;
1354                alloc_hba_channel++;
1355            }
1356            // ctx_tim : TIM local channel index provided by the cluster allocator
1357            unsigned int ctx_tim = 0xFFFFFFFF;
1358            if (task[task_id].use_tim) 
1359            {
1360                unsigned int cluster_id = task[task_id].clusterid;
1361
1362                if ( alloc_tim_channel[cluster_id] >= NB_TIM_CHANNELS ) 
1363                {
1364                    _puts("\n[BOOT ERROR] local TIMER index too large for task ");
1365                    _puts(task[task_id].name);
1366                    _puts(" in vspace ");
1367                    _puts(vspace[vspace_id].name);
1368                    _puts("\n");
1369                    _exit();
1370                }
1371
1372                // checking that there is an ISR_TIMER installed
1373                unsigned int found = 0;
1374                for ( irq_id = 0 ; irq_id < 32 ; irq_id++ ) 
1375                {
1376                    unsigned int entry   = psched->interrupt_vector[irq_id];
1377                    unsigned int isr     = entry & 0x000000FF;
1378                    unsigned int channel = entry>>16;
1379                    if ( (isr == ISR_TIMER) && (channel == alloc_tim_channel[cluster_id]) ) 
1380                    {
1381                        found     = 1;
1382                        ctx_tim =  alloc_tim_channel[cluster_id];
1383                        alloc_tim_channel[cluster_id]++;
1384                        break;
1385                    }
1386                }
1387                if (!found) 
1388                {
1389                    _puts("\n[BOOT ERROR] No ISR_TIMER installed for task ");
1390                    _puts(task[task_id].name);
1391                    _puts(" in vspace ");
1392                    _puts(vspace[vspace_id].name);
1393                    _puts("\n");
1394                    _exit();
1395                }
1396            }
1397            // ctx_epc : Get the virtual address of the memory location containing
1398            // the task entry point : the start_vector is stored by GCC in the seg_data
1399            // segment and we must wait the .elf loading to get the entry point value...
1400            mapping_vobj_t* pvobj = &vobj[vspace[vspace_id].vobj_offset + 
1401                                     vspace[vspace_id].start_offset];
1402            unsigned int ctx_epc = pvobj->vaddr + (task[task_id].startid)*4;
1403
1404            // ctx_sp :  Get the vobj containing the stack
1405            unsigned int vobj_id = task[task_id].stack_vobjid + vspace[vspace_id].vobj_offset;
1406            unsigned int ctx_sp = vobj[vobj_id].vaddr + vobj[vobj_id].length;
1407
1408            // get local task index in scheduler
1409            unsigned int ltid = psched->tasks;
1410
1411            if (ltid >= IDLE_TASK_INDEX) 
1412            {
1413                _puts("\n[BOOT ERROR] in boot_schedulers_init() : ");
1414                _putd( ltid );
1415                _puts(" tasks allocated to processor ");
1416                _putd( gpid );
1417                _puts(" / max is ");
1418                _putd( IDLE_TASK_INDEX );
1419                _puts("\n");
1420                _exit();
1421            }
1422
1423            // update the "tasks" and "current" fields in scheduler:
1424            // the first task to execute is task 0 as soon as there is at least
1425            // one task allocated to processor.
1426            psched->tasks   = ltid + 1;
1427            psched->current = 0;
1428
1429            // initializes the task context in scheduler
1430            psched->context[ltid][CTX_SR_ID]    = ctx_sr;
1431            psched->context[ltid][CTX_SP_ID]    = ctx_sp;
1432            psched->context[ltid][CTX_EPC_ID]   = ctx_epc;
1433            psched->context[ltid][CTX_PTPR_ID]  = ctx_ptpr;
1434            psched->context[ltid][CTX_TTY_ID]   = ctx_tty;
1435            psched->context[ltid][CTX_CMA_ID]   = ctx_cma;
1436            psched->context[ltid][CTX_HBA_ID]   = ctx_hba;
1437            psched->context[ltid][CTX_NIC_ID]   = ctx_nic;
1438            psched->context[ltid][CTX_TIM_ID]   = ctx_tim;
1439            psched->context[ltid][CTX_PTAB_ID]  = ctx_ptab;
1440            psched->context[ltid][CTX_LTID_ID]  = ltid;
1441            psched->context[ltid][CTX_GTID_ID]  = task_id;
1442            psched->context[ltid][CTX_VSID_ID]  = vspace_id;
1443            psched->context[ltid][CTX_RUN_ID]   = 1;
1444
1445#if BOOT_DEBUG_SCHED
1446_puts("\nTask ");
1447_puts( task[task_id].name );
1448_puts(" (");
1449_putd( task_id );
1450_puts(") allocated to processor ");
1451_putd( gpid );
1452_puts("\n  - ctx[LTID]   = ");
1453_putd( psched->context[ltid][CTX_LTID_ID] );
1454_puts("\n  - ctx[SR]     = ");
1455_putx( psched->context[ltid][CTX_SR_ID] );
1456_puts("\n  - ctx[SP]     = ");
1457_putx( psched->context[ltid][CTX_SP_ID] );
1458_puts("\n  - ctx[EPC]    = ");
1459_putx( psched->context[ltid][CTX_EPC_ID] );
1460_puts("\n  - ctx[PTPR]   = ");
1461_putx( psched->context[ltid][CTX_PTPR_ID] );
1462_puts("\n  - ctx[TTY]    = ");
1463_putd( psched->context[ltid][CTX_TTY_ID] );
1464_puts("\n  - ctx[NIC]    = ");
1465_putd( psched->context[ltid][CTX_NIC_ID] );
1466_puts("\n  - ctx[CMA]    = ");
1467_putd( psched->context[ltid][CTX_CMA_ID] );
1468_puts("\n  - ctx[IOC]    = ");
1469_putd( psched->context[ltid][CTX_HBA_ID] );
1470_puts("\n  - ctx[TIM]    = ");
1471_putd( psched->context[ltid][CTX_TIM_ID] );
1472_puts("\n  - ctx[PTAB]   = ");
1473_putx( psched->context[ltid][CTX_PTAB_ID] );
1474_puts("\n  - ctx[GTID]   = ");
1475_putd( psched->context[ltid][CTX_GTID_ID] );
1476_puts("\n  - ctx[VSID]   = ");
1477_putd( psched->context[ltid][CTX_VSID_ID] );
1478_puts("\n");
1479#endif
1480
1481        } // end loop on tasks
1482    } // end loop on vspaces
1483} // end _schedulers_init()
1484
1485//////////////////////////////////////////////////////////////////////////////////
1486// This function loads the map.bin file from block device.
1487// The fat global varible is defined in fat32.c file.
1488//////////////////////////////////////////////////////////////////////////////////
1489void boot_mapping_init()
1490{
1491    // Initializing the FAT descriptor and files descriptor array
1492    if ( _fat_init( IOC_BOOT_PA_MODE ) )   
1493    {
1494        _puts("[BOOT ERROR] Cannot initialize FAT descriptor fom Boot Sector\n");
1495        _exit();
1496    }
1497
1498#if BOOT_DEBUG_MAPPING
1499_puts("\n[BOOT] FAT initialisation completed at cycle ");
1500_putd(_get_proctime());
1501_puts("\n");
1502_fat_print();
1503#endif
1504
1505    int fd_id = _fat_open( IOC_BOOT_PA_MODE,
1506                           "map.bin",
1507                           0 );         // no creation
1508
1509    if ( fd_id == -1 )
1510    {
1511        _puts("\n[BOOT ERROR] : map.bin file not found \n");
1512        _exit();
1513    }
1514
1515#if BOOT_DEBUG_MAPPING
1516_puts("\n[BOOT] map.bin file successfully open at cycle ");
1517_putd(_get_proctime());
1518_puts("\n");
1519#endif
1520
1521    unsigned int size    = fat.fd[fd_id].file_size;
1522    unsigned int nblocks = size >> 9;
1523    unsigned int offset  = size & 0x1FF;
1524    if ( offset ) nblocks++;
1525
1526    unsigned int ok = _fat_read( IOC_BOOT_PA_MODE,
1527                                 fd_id, 
1528                                 (unsigned int*)( &seg_boot_mapping_base), 
1529                                 nblocks,       
1530                                 0 );      // offset
1531    if ( ok == -1 )
1532    {
1533        _puts("\n[BOOT ERROR] : unable to load map.bin file \n");
1534        _exit();
1535    }
1536    _fat_close( fd_id );
1537   
1538    boot_mapping_check();
1539} // end boot_mapping_init()
1540
1541
1542//////////////////////////////////////////////////////////////////////////////////
1543// This function open the .elf file identified by the "pathname" argument.
1544// It loads the complete file in a dedicated buffer, it copies all loadable
1545// segments  at the memory virtual address defined in the .elf file,
1546// and close the file.
1547// Notes:
1548// - The processor PTPR should contain the value corresponding to the
1549//   vspace containing the .elf file.
1550// - As this function requires a temporary memory buffer
1551//   to load the complete .elf file before to copy the various segments
1552//   to te proper location, it uses the seg_boot_buffer defined in map.xml.
1553//////////////////////////////////////////////////////////////////////////////////
1554void load_one_elf_file( unsigned int mode,
1555                        char*        pathname,
1556                        unsigned int vspace_id )    // to use the proper page_table
1557{
1558    unsigned int seg_id;
1559
1560    // get boot buffer address and size
1561    char*             boot_buffer      = (char*)(&seg_boot_buffer_base);
1562    unsigned int      boot_buffer_size = (unsigned int)(&seg_boot_buffer_size);
1563
1564#if BOOT_DEBUG_ELF
1565_puts("\n[BOOT DEBUG] Start searching file ");
1566_puts( pathname );
1567_puts(" at cycle ");
1568_putd( _get_proctime() );
1569_puts("\n");
1570#endif
1571
1572    // open .elf file
1573    int fd_id = _fat_open( mode,
1574                           pathname,
1575                           0 );      // no creation
1576    if ( fd_id < 0 )
1577    {
1578        _puts("\n[BOOT ERROR] load_one_elf_file() : ");
1579        _puts( pathname );
1580        _puts(" not found\n");
1581        _exit();
1582    }
1583
1584    // check boot_buffer size versus file size
1585    if ( fat.fd[fd_id].file_size > boot_buffer_size )
1586    {
1587        _puts("\n[BOOT ERROR] load_one_elf_file() : ");
1588        _puts( pathname );
1589        _puts(" exceeds the seg_boot_buffer size\n");
1590        _exit();
1591    }
1592
1593    // compute number of sectors
1594    unsigned int nbytes   = fat.fd[fd_id].file_size;
1595    unsigned int nsectors = nbytes>>9;
1596    if( nbytes & 0x1FF) nsectors++;
1597
1598    // load file in boot_buffer
1599    if( _fat_read( mode, 
1600                   fd_id, 
1601                   boot_buffer,
1602                   nsectors,
1603                   0 ) != nsectors )
1604    {
1605        _puts("\n[BOOT ERROR] load_one_elf_file() : unexpected EOF for file ");
1606        _puts( pathname );
1607        _puts("\n");   
1608        _exit();
1609    }
1610
1611    // Check ELF Magic Number in ELF header
1612    Elf32_Ehdr* elf_header_ptr = (Elf32_Ehdr*)boot_buffer;
1613
1614    if ( (elf_header_ptr->e_ident[EI_MAG0] != ELFMAG0) ||
1615         (elf_header_ptr->e_ident[EI_MAG1] != ELFMAG1) ||
1616         (elf_header_ptr->e_ident[EI_MAG2] != ELFMAG2) ||
1617         (elf_header_ptr->e_ident[EI_MAG3] != ELFMAG3) )
1618    {
1619        _puts("\n[BOOT ERROR] load_elf() : file ");
1620        _puts( pathname );
1621        _puts(" does not use ELF format\n");   
1622        _exit();
1623    }
1624
1625    // get program header table pointer
1626    unsigned int pht_index = elf_header_ptr->e_phoff;
1627    if( pht_index == 0 )
1628    {
1629        _puts("\n[BOOT ERROR] load_one_elf_file() : file ");
1630        _puts( pathname );
1631        _puts(" does not contain loadable segment\n");   
1632        _exit();
1633    }
1634    Elf32_Phdr* elf_pht_ptr = (Elf32_Phdr*)(boot_buffer + pht_index);
1635
1636    // get number of segments
1637    unsigned int nsegments   = elf_header_ptr->e_phnum;
1638
1639#if BOOT_DEBUG_ELF
1640_puts("\n[BOOT DEBUG] File ");
1641_puts( pathname );
1642_puts(" loaded at cycle ");
1643_putd( _get_proctime() );
1644_puts(" / bytes = ");
1645_putd( nbytes );
1646_puts(" / sectors = ");
1647_putd( nsectors );
1648_puts("\n");
1649#endif
1650
1651    // Loop on loadable segments in the ELF file
1652    for (seg_id = 0 ; seg_id < nsegments ; seg_id++)
1653    {
1654        if(elf_pht_ptr[seg_id].p_type == PT_LOAD)
1655        {
1656            // Get segment attributes
1657            unsigned int seg_vaddr  = elf_pht_ptr[seg_id].p_vaddr;
1658            unsigned int seg_offset = elf_pht_ptr[seg_id].p_offset;
1659            unsigned int seg_filesz = elf_pht_ptr[seg_id].p_filesz;
1660            unsigned int seg_memsz  = elf_pht_ptr[seg_id].p_memsz;
1661
1662            if( seg_memsz < seg_filesz )
1663            {
1664                _puts("\n[BOOT ERROR] load_one_elf_file() : segment at vaddr = ");
1665                _putx( seg_vaddr );
1666                _puts(" in file ");
1667                _puts( pathname );
1668                _puts(" has a wrong size \n");   
1669                _exit();
1670            }
1671
1672            // fill empty space with 0 as required
1673            if( seg_memsz > seg_filesz )
1674            {
1675                unsigned int i; 
1676                for( i = seg_filesz ; i < seg_memsz; i++ ) boot_buffer[i] = 0;
1677            } 
1678
1679            unsigned int src_vaddr = (unsigned int)boot_buffer + seg_offset;
1680
1681#if BOOT_DEBUG_ELF
1682_puts(" - segment ");
1683_putd( seg_id );
1684_puts(" / dst_vaddr = ");
1685_putx( seg_vaddr );
1686_puts(" / src_vaddr = ");
1687_putx( src_vaddr );
1688_puts(" / size = ");
1689_putx( seg_filesz );
1690_puts("\n");
1691#endif
1692
1693            // copy the segment from boot buffer to destination buffer
1694            if( NB_DMA_CHANNELS > 0 )
1695            {
1696                _dma_copy( vspace_id,           // required for V2P translation
1697                           (char*)seg_vaddr,
1698                           (char*)src_vaddr,
1699                           seg_filesz );
1700            }
1701            else
1702            {
1703                _memcpy( (char*)seg_vaddr,
1704                         (char*)src_vaddr,
1705                         seg_filesz );
1706            }
1707        }
1708    } // end for segments
1709
1710    // close .elf file
1711    _fat_close( fd_id );
1712
1713} // end load_one_elf_file()
1714
1715
1716//////////////////////////////////////////////////////////////////////////////////
1717// This function uses the map.bin data structure to load the "kernel.elf" file
1718// as well as the various "application.elf" files.
1719// The "preloader.elf" file is not loaded, because it has been burned in the ROM.
1720// The "boot.elf" file is not loaded, because it has been loaded by the preloader.
1721// It scans all vobjs defined in the map.bin data structure to collect
1722// all .elf files pathnames, and calls the load_one_elf_file() function to
1723// load all loadable segments at the virtual address found in the .elf file.
1724//////////////////////////////////////////////////////////////////////////////////
1725void boot_elf_load()
1726{
1727    mapping_header_t* header = (mapping_header_t *) & seg_boot_mapping_base;
1728    mapping_vspace_t* vspace = _get_vspace_base( header );
1729    mapping_vobj_t*   vobj   = _get_vobj_base( header );
1730    unsigned int      vspace_id;
1731    unsigned int      vobj_id;
1732    unsigned int      found;
1733
1734    // Scan all vobjs corresponding to global vsegs,
1735    // to find the pathname to the kernel.elf file
1736    found = 0;
1737    for( vobj_id = 0 ; vobj_id < header->globals ; vobj_id++ )
1738    {
1739        if(vobj[vobj_id].type == VOBJ_TYPE_ELF) 
1740        {   
1741            found = 1;
1742            break;
1743        }
1744    }
1745
1746    // We need one kernel.elf file
1747    if (found == 0)
1748    {
1749        _puts("[BOOT ERROR] boot_elf_load() : kernel.elf file not found\n");
1750        _exit();
1751    }
1752
1753    load_one_elf_file( IOC_BOOT_VA_MODE,
1754                       vobj[vobj_id].binpath,
1755                       0 );                         // vspace 0
1756
1757    _puts("\n[BOOT] File ");
1758    _puts( vobj[vobj_id].binpath );
1759    _puts(" loaded at cycle ");
1760    _putd( _get_proctime() );
1761    _puts("\n");
1762
1763    // loop on the vspaces, scanning all vobjs in a vspace,
1764    // to find the pathname of the .elf file associated to the vspace.
1765    for( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1766    {
1767        // Set PTPR depending on the vspace, as seg_data is defined in virtual space.
1768        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id] >> 13) );
1769
1770        // loop on the vobjs in vspace (vobj_id is the global index)
1771        unsigned int found = 0;
1772        for (vobj_id = vspace[vspace_id].vobj_offset;
1773             vobj_id < (vspace[vspace_id].vobj_offset + vspace[vspace_id].vobjs);
1774             vobj_id++) 
1775        {
1776            if(vobj[vobj_id].type == VOBJ_TYPE_ELF) 
1777            {   
1778                found = 1;
1779                break;
1780            }
1781        }
1782
1783        // We want one .elf file per vspace
1784        if (found == 0)
1785        {
1786            _puts("[BOOT ERROR] boot_elf_load() : .elf file not found for vspace ");
1787            _puts( vspace[vspace_id].name );
1788            _puts("\n");
1789            _exit();
1790        }
1791
1792        load_one_elf_file( IOC_BOOT_VA_MODE,
1793                           vobj[vobj_id].binpath,
1794                           vspace_id );
1795
1796        _puts("\n[BOOT] File ");
1797        _puts( vobj[vobj_id].binpath );
1798        _puts(" loaded at cycle ");
1799        _putd( _get_proctime() );
1800        _puts("\n");
1801
1802    }  // end for vspaces
1803
1804    // restaure vspace 0 PTPR
1805    _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0] >> 13) );
1806
1807} // end boot_elf_load()
1808
1809////////////////////////////////////////////////////////////////////////////////
1810// This function intializes the periherals and coprocessors, as specified
1811// in the mapping_info file.
1812////////////////////////////////////////////////////////////////////////////////
1813void boot_peripherals_init() 
1814{
1815    mapping_header_t * header   = (mapping_header_t *) & seg_boot_mapping_base;
1816    mapping_cluster_t * cluster = _get_cluster_base(header);
1817    mapping_periph_t * periph   = _get_periph_base(header);
1818    mapping_vobj_t * vobj       = _get_vobj_base(header);
1819    mapping_vspace_t * vspace   = _get_vspace_base(header);
1820    mapping_coproc_t * coproc   = _get_coproc_base(header);
1821    mapping_cp_port_t * cp_port = _get_cp_port_base(header);
1822
1823    unsigned int cluster_id;
1824    unsigned int periph_id;
1825    unsigned int coproc_id;
1826    unsigned int cp_port_id;
1827    unsigned int channel_id;
1828
1829    for (cluster_id = 0; cluster_id < header->clusters; cluster_id++) 
1830    {
1831
1832#if BOOT_DEBUG_PERI
1833_puts("\n[BOOT DEBUG] ****** peripherals initialisation in cluster ");
1834_putd(cluster_id);
1835_puts(" ******\n");
1836#endif
1837
1838        for (periph_id = cluster[cluster_id].periph_offset;
1839             periph_id < cluster[cluster_id].periph_offset +
1840             cluster[cluster_id].periphs; periph_id++) 
1841        {
1842            unsigned int type       = periph[periph_id].type;
1843            unsigned int channels   = periph[periph_id].channels;
1844
1845#if BOOT_DEBUG_PERI
1846_puts("- peripheral type : ");
1847_putd(type);
1848_puts(" / channels = ");
1849_putd(channels);
1850_puts("\n");
1851#endif
1852            switch (type) 
1853            {
1854                case PERIPH_TYPE_IOC:    // vci_block_device component
1855                {
1856                    _ioc_init();
1857#if BOOT_DEBUG_PERI
1858_puts("- IOC initialised\n");
1859#endif
1860                    break;
1861                }
1862                case PERIPH_TYPE_DMA:    // vci_multi_dma component
1863                {
1864                    for (channel_id = 0; channel_id < channels; channel_id++) 
1865                    {
1866                        _dma_init( cluster_id, channel_id );
1867                    }
1868#if BOOT_DEBUG_PERI
1869_puts("- DMA initialised\n");
1870#endif
1871                    break;
1872                }
1873                case PERIPH_TYPE_NIC:    // vci_multi_nic component
1874                {
1875                    for (channel_id = 0; channel_id < channels; channel_id++) 
1876                    {
1877                        // TODO
1878                    }
1879#if BOOT_DEBUG_PERI
1880_puts("- NIC initialised\n");
1881#endif
1882                    break;
1883                }
1884                case PERIPH_TYPE_TTY:    // vci_multi_tty component
1885                {
1886#if BOOT_DEBUG_PERI
1887_puts("- TTY initialised\n");
1888#endif
1889                    break;
1890                }
1891                case PERIPH_TYPE_IOB:    // vci_io_bridge component
1892                {
1893                    if (USE_IOB) 
1894                    {
1895                        // TODO
1896                        // get the iommu page table physical address
1897                        // define IPI address mapping the IOC interrupt
1898                        // set IOMMU page table address
1899                        // pseg_base[IOB_IOMMU_PTPR] = ptab_pbase;   
1900                        // activate IOMMU
1901                        // pseg_base[IOB_IOMMU_ACTIVE] = 1;       
1902                    }
1903#if BOOT_DEBUG_PERI
1904_puts("- IOB initialised\n");
1905#endif
1906                    break;
1907                }
1908            }  // end switch periph type
1909        }  // end for periphs
1910
1911#if BOOT_DEBUG_PERI
1912_puts("\n[BOOT DEBUG] ****** coprocessors initialisation in cluster ");
1913_putd(cluster_id);
1914_puts(" ******\n");
1915#endif
1916
1917        for ( coproc_id = cluster[cluster_id].coproc_offset;
1918              coproc_id < cluster[cluster_id].coproc_offset +
1919              cluster[cluster_id].coprocs; coproc_id++ ) 
1920        {
1921
1922#if BOOT_DEBUG_PERI
1923_puts("- coprocessor name : ");
1924_puts(coproc[coproc_id].name);
1925_puts(" / nb ports = ");
1926_putd((unsigned int) coproc[coproc_id].ports);
1927_puts("\n");
1928#endif
1929            // loop on the coprocessor ports
1930            for ( cp_port_id = coproc[coproc_id].port_offset;
1931                  cp_port_id < coproc[coproc_id].port_offset + coproc[coproc_id].ports;
1932                  cp_port_id++ ) 
1933            {
1934                unsigned int vspace_id = cp_port[cp_port_id].vspaceid;
1935                unsigned int vobj_id   = cp_port[cp_port_id].mwmr_vobjid + 
1936                                                vspace[vspace_id].vobj_offset;
1937
1938                // Get MWMR channel base address
1939                paddr_t mwmr_channel_pbase = vobj[vobj_id].paddr;
1940
1941                _mwmr_hw_init( cluster_id,
1942                               cp_port_id, 
1943                               cp_port[cp_port_id].direction, 
1944                               mwmr_channel_pbase );
1945#if BOOT_DEBUG_PERI
1946_puts("     port direction: ");
1947_putd( (unsigned int)cp_port[cp_port_id].direction );
1948_puts(" / mwmr_channel_pbase = ");
1949_putl( mwmr_channel_pbase );
1950_puts(" / name = ");
1951_puts(vobj[vobj_id].name);
1952_puts(" / in vspace ");
1953_puts(vspace[vspace_id].name);
1954_puts("\n"); 
1955#endif
1956            } // end for cp_ports
1957        } // end for coprocs
1958    } // end for clusters
1959} // end boot_peripherals_init()
1960
1961
1962//////////////////////////////////////////////////////////////////////////////
1963// This function is executed by all processors to jump into kernel:
1964// - Each processor initialises its CP0_SCHED register from the value
1965//   contained in the _schedulers[] array (previously initialised
1966//   by proc0 in the _schedulers_init() function).
1967// - Each processor (but proc 0) initialise the CP2_PTPR register with
1968//   the default value (i.e. PTPR corresponding to vspace_0 page table),
1969//   and write into CP2 MODE register to activate their MMU.
1970// - All processors jump to the kernel entry point (seg_kernel_init_base).
1971//////////////////////////////////////////////////////////////////////////////
1972void boot_to_kernel()
1973{
1974    // CP0 SCHED register initialisation
1975    unsigned int procid = _get_procid();
1976    _set_sched( (unsigned int)_schedulers[procid] );
1977
1978    // MMU Activation
1979    if ( procid != 0 )
1980    {
1981        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0]>>13) );
1982        _set_mmu_mode( 0xF );
1983
1984        _tty_get_lock( 0 );
1985        _puts("\n[BOOT] Proc ");
1986        _putd( procid );
1987        _puts(" MMU activation at cycle ");
1988        _putd(_get_proctime());
1989        _puts("\n");
1990        _tty_release_lock( 0 );
1991
1992    }
1993
1994    // jump to kernel_init
1995    unsigned int kernel_entry = (unsigned int)&seg_kernel_init_base;
1996
1997    _tty_get_lock( 0 );
1998    _puts("\n[BOOT] Processor ");
1999    _putd( procid );
2000    _puts(" jumps to kernel (");
2001    _putx( kernel_entry );
2002    _puts(") at cycle ");
2003    _putd( _get_proctime() );
2004    _puts("\n");
2005    _tty_release_lock( 0 );
2006
2007    asm volatile( "jr   %0" ::"r"(kernel_entry) );
2008}
2009
2010/////////////////////////////////////////////////////////////////////////
2011// This function is the entry point of the boot code for all processors.
2012// Most of this code is executed by Processor 0 only.
2013/////////////////////////////////////////////////////////////////////////
2014void boot_init() 
2015{
2016    mapping_header_t* header = (mapping_header_t *) & seg_boot_mapping_base;
2017    unsigned int      procid = _get_procid();
2018 
2019    if ( procid == 0 )    // only Processor 0 does it
2020    {
2021        _puts("\n[BOOT] boot_init start at cycle ");
2022        _putd(_get_proctime());
2023        _puts("\n");
2024
2025        // Loading the map.bin file into memory and checking it
2026        boot_mapping_init();
2027
2028        _puts("\n[BOOT] Mapping ");
2029        _puts( header->name );
2030        _puts(" loaded at cycle ");
2031        _putd(_get_proctime());
2032        _puts("\n");
2033
2034        // Building all page tables
2035        boot_pt_init();
2036
2037        _puts("\n[BOOT] Page Tables initialisation completed at cycle ");
2038        _putd(_get_proctime());
2039        _puts("\n");
2040
2041        // Activating proc 0 MMU
2042        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0]>>13) );
2043        _set_mmu_mode( 0xF );
2044
2045        _puts("\n[BOOT] Processor 0 MMU activation at cycle ");
2046        _putd(_get_proctime());
2047        _puts("\n");
2048
2049        // Initialising private vobjs in vspaces
2050        boot_vobjs_init();
2051
2052        _puts("\n[BOOT] Private vobjs initialised at cycle ");
2053        _putd(_get_proctime());
2054        _puts("\n");
2055
2056        // Initializing schedulers
2057        boot_schedulers_init();
2058
2059        _puts("\n[BOOT] All schedulers initialised at cycle ");
2060        _putd(_get_proctime());
2061        _puts("\n");
2062       
2063        // Setting CP0_SCHED register for proc 0
2064        _set_sched( (unsigned int)_schedulers[0] );
2065
2066        _puts("\n[BOOT] Proc 0 CPO_SCHED register initialised at cycle ");
2067        _putd(_get_proctime());
2068        _puts("\n");
2069
2070        // Initializing external peripherals
2071        boot_peripherals_init();
2072
2073        _puts("\n[BOOT] External peripherals initialised at cycle ");
2074        _putd(_get_proctime());
2075        _puts("\n");
2076
2077        // Loading all .elf files
2078        boot_elf_load();
2079
2080        _puts("\n[BOOT] All ELF files loaded at cycle ");
2081        _putd(_get_proctime());
2082        _puts("\n");
2083
2084        // P0 starts all other processors
2085        unsigned int cluster_id;
2086        unsigned int local_id;
2087        for (cluster_id = 0; cluster_id < NB_CLUSTERS; cluster_id++) 
2088        {
2089            for(local_id = 0; local_id < NB_PROCS_MAX; local_id++) 
2090            {
2091                if ((cluster_id != 0) || (local_id != 0))
2092                {
2093                    _xcu_send_ipi( cluster_id,
2094                                   local_id,
2095                                   (unsigned int)boot_init );
2096                }
2097            }
2098        }
2099    }  // end monoprocessor boot
2100
2101    // all processor initialise SCHED register
2102    _set_sched( (unsigned int)_schedulers[procid] );
2103
2104    // all processors (but Proc 0) activate MMU
2105    if ( procid != 0 )
2106    {
2107        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0]>>13) );
2108        _set_mmu_mode( 0xF );
2109
2110        _tty_get_lock( 0 );
2111        _puts("\n[BOOT] Processor ");
2112        _putd( procid );
2113        _puts(" MMU activation at cycle ");
2114        _putd(_get_proctime());
2115        _puts("\n");
2116        _tty_release_lock( 0 );
2117
2118    }
2119
2120    // all processors jump to kernel_init
2121    unsigned int kernel_entry = (unsigned int)&seg_kernel_init_base;
2122
2123    _tty_get_lock( 0 );
2124    _puts("\n[BOOT] Processor ");
2125    _putd( procid );
2126    _puts(" enters kernel at cycle ");
2127    _putd( _get_proctime() );
2128    _puts(" / kernel entry = ");
2129    _putx( kernel_entry );
2130    _puts("\n");
2131    _tty_release_lock( 0 );
2132
2133    asm volatile( "jr   %0" ::"r"(kernel_entry) );
2134
2135} // end boot_init()
2136
2137
2138// Local Variables:
2139// tab-width: 4
2140// c-basic-offset: 4
2141// c-file-offsets:((innamespace . 0)(inline-open . 0))
2142// indent-tabs-mode: nil
2143// End:
2144// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
2145
Note: See TracBrowser for help on using the repository browser.