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

Last change on this file since 315 was 309, checked in by alain, 11 years ago

Reducing the number of log messages in parallel mode.

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