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

Last change on this file since 298 was 295, checked in by alain, 10 years ago

Introducing a major release, to suppoort the tsar_generic_leti platform
and the various (external or internal) peripherals configurations.
The map.xml format has been modified, in order to support the new
vci_iopic componentand a new policy for peripherals initialisation.
The IRQs are nom described in the XICU and IOPIC components
(and not anymore in the processors).
To enforce this major change, the map.xml file signature changed:
The signature value must be: 0xDACE2014

This new release has been tested on the tsar_generic_leti platform
for the following mappings:

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