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

Last change on this file since 293 was 293, checked in by cfuguet, 11 years ago

Initializing the CP0 CAUSE value on the task contexts to
zero during creation of tasks (boot_scheduler_init). This
is to avoid writing non initialized data on the CAUSE
register when swithing tasks for the first time.

File size: 76.7 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// for vobjs initialisation
71#include <giet_config.h>
72#include <mwmr_channel.h>
73#include <barrier.h>
74#include <memspace.h>
75#include <tty_driver.h>
76#include <xcu_driver.h>
77#include <ioc_driver.h>
78#include <dma_driver.h>
79#include <cma_driver.h>
80#include <nic_driver.h>
81#include <ioc_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        _putl( 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_proc_t*    proc    = _get_proc_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 proc_id;       // processor 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 = 0;            // 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;            // IOC channel allocator
1169    unsigned int alloc_tim_channel[X_SIZE*Y_SIZE]; // user TIMER allocators
1170
1171    if (NB_TTY_CHANNELS > 1) alloc_tty_channel++;
1172
1173    /////////////////////////////////////////////////////////////////////////
1174    // Step 1 : loop on the clusters and on the processors
1175    //          to initialize the schedulers[] array of pointers,
1176    //          and the interrupt vectors.
1177    // Implementation note:
1178    // We need to use both proc_id to scan the mapping info structure,
1179    // and lpid to access the schedulers array.
1180    // - the _schedulers[] array of pointers can contain "holes", because
1181    //   it is indexed by the global pid = cluster_xy*NB_PROCS_MAX + lpid
1182    // - the mapping info array of processors is contiguous, it is indexed
1183    //   by proc_id, and use an offset specific in each cluster.
1184
1185    for (cluster_id = 0 ; cluster_id < X_SIZE*Y_SIZE ; cluster_id++) 
1186    {
1187        unsigned int x          = cluster[cluster_id].x;
1188        unsigned int y          = cluster[cluster_id].y;
1189        unsigned int cluster_xy = (x<<Y_WIDTH) + y;
1190
1191#if BOOT_DEBUG_SCHED
1192_puts("\n[BOOT DEBUG] Initialise schedulers in cluster[");
1193_putd( x );
1194_puts(",");
1195_putd( y );
1196_puts("]\n");
1197#endif
1198        alloc_tim_channel[cluster_id] = NB_PROCS_MAX;
1199
1200        unsigned int  lpid;          // processor local index in cluster
1201        unsigned int  sched_vbase;   // schedulers segment virtual base address
1202        unsigned int  sched_length;  // schedulers segment length
1203        unsigned int  nprocs;        // number of processors in cluster
1204
1205        nprocs = cluster[cluster_id].procs;
1206
1207        // checking processors number
1208        if ( nprocs > NB_PROCS_MAX )
1209        {
1210            _puts("\n[BOOT ERROR] Too much processors in cluster[");
1211            _putd( x );
1212            _puts(",");
1213            _putd( y );
1214            _puts("]\n");
1215            _exit();
1216        }
1217 
1218        // get scheduler array virtual base address and length
1219        boot_get_sched_vaddr( cluster_id, &sched_vbase, &sched_length );
1220
1221        // each processor scheduler requires 4 Kbytes
1222        if ( sched_length < (nprocs<<12) ) 
1223        {
1224            _puts("\n[BOOT ERROR] Schedulers segment too small in cluster[");
1225            _putd( x );
1226            _puts(",");
1227            _putd( y );
1228            _puts("]\n");
1229            _exit();
1230        }
1231
1232        // loop on processors
1233        for ( proc_id = cluster[cluster_id].proc_offset, lpid = 0 ;
1234              proc_id < cluster[cluster_id].proc_offset + cluster[cluster_id].procs;
1235              proc_id++, lpid++ ) 
1236        {
1237            // current processor scheduler pointer : psched
1238            static_scheduler_t* psched = (static_scheduler_t*)(sched_vbase+(lpid<<12));
1239
1240            // set the schedulers pointers array
1241            _schedulers[cluster_xy * NB_PROCS_MAX + lpid] = psched;
1242
1243#if BOOT_DEBUG_SCHED
1244_puts("\nProc_");
1245_putd( x );
1246_puts("_");
1247_putd( y );
1248_puts("_");
1249_putd( lpid );
1250_puts(" : scheduler virtual base address = ");
1251_putx( sched_vbase + (lpid<<12) );
1252_puts("\n");
1253#endif
1254
1255            // initialise the "tasks" variable : default value is 0
1256            psched->tasks = 0;
1257
1258            // initialise the "current" variable : default value is idle_task
1259            psched->current = IDLE_TASK_INDEX;
1260
1261            // initialise interrupt_vector with default value (valid bit = 0)
1262            unsigned int slot;
1263            for (slot = 0; slot < 32; slot++) psched->interrupt_vector[slot] = 0;
1264
1265            // initialise interrupt vector with the IRQs actually allocated
1266            for (irq_id = proc[proc_id].irq_offset;
1267                 irq_id < proc[proc_id].irq_offset + proc[proc_id].irqs;
1268                 irq_id++) 
1269            {
1270                unsigned int type    = irq[irq_id].type;
1271                unsigned int icu_id  = irq[irq_id].icuid;
1272                unsigned int isr_id  = irq[irq_id].isr;
1273                unsigned int channel = irq[irq_id].channel;
1274
1275                unsigned int value = ((isr_id  & 0xFF)        ) | 
1276                                     ((type    & 0xFF)   <<  8) | 
1277                                     ((channel & 0x7FFF) << 16) | 
1278                                     0x80000000;                    // Valid entry
1279
1280                psched->interrupt_vector[icu_id] = value;
1281
1282#if BOOT_DEBUG_SCHED
1283_puts("- IRQ : icu = ");
1284_putd(icu_id);
1285_puts(" / type = ");
1286_putd(type);
1287_puts(" / isr = ");
1288_putd(isr_id);
1289_puts(" / channel = ");
1290_putd(channel);
1291_puts(" => vector_entry = ");
1292_putx( value );
1293_puts("\n");
1294#endif
1295            }
1296
1297            // initializes the idle_task context in scheduler:
1298            // - the SR slot is 0xFF03 because this task run in kernel mode.
1299            // - it uses the page table of vspace[0]
1300            // - it uses the kernel TTY terminal
1301            // - slots containing addresses (SP, RA, EPC, PTAB, PTPR)
1302            //   must be re-initialised by kernel_parallel_init()
1303
1304            psched->context[IDLE_TASK_INDEX][CTX_CR_ID]    = 0;
1305            psched->context[IDLE_TASK_INDEX][CTX_SR_ID]    = 0xFF03;
1306            psched->context[IDLE_TASK_INDEX][CTX_PTPR_ID]  = _ptabs_paddr[0]>>13;
1307            psched->context[IDLE_TASK_INDEX][CTX_PTAB_ID]  = _ptabs_vaddr[0];
1308            psched->context[IDLE_TASK_INDEX][CTX_TTY_ID]   = 0;
1309            psched->context[IDLE_TASK_INDEX][CTX_LTID_ID]  = IDLE_TASK_INDEX;
1310            psched->context[IDLE_TASK_INDEX][CTX_VSID_ID]  = 0;
1311            psched->context[IDLE_TASK_INDEX][CTX_RUN_ID]   = 1;
1312
1313        } // end for procs
1314    } // end for clusters
1315
1316    ///////////////////////////////////////////////////////////////////
1317    // Step 2 : loop on the vspaces and the tasks
1318    //          to initialise the schedulers and the task contexts.
1319
1320    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
1321    {
1322        // We must set the PTPR depending on the vspace, because the start_vector
1323        // and the stack address are defined in virtual space.
1324        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id] >> 13) );
1325
1326        // loop on the tasks in vspace (task_id is the global index)
1327        for (task_id = vspace[vspace_id].task_offset;
1328             task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks);
1329             task_id++) 
1330        {
1331
1332            // compute the cluster coordinates
1333            unsigned int x          = cluster[task[task_id].clusterid].x;
1334            unsigned int y          = cluster[task[task_id].clusterid].y;
1335            unsigned int cluster_xy = (x<<Y_WIDTH) + y;
1336
1337#if BOOT_DEBUG_SCHED
1338_puts("\n[BOOT DEBUG] Initialise context for task ");
1339_puts( task[task_id].name );
1340_puts(" in vspace ");
1341_puts( vspace[vspace_id].name );
1342_puts(" running on cluster[");
1343_putd( x );
1344_puts(",");
1345_putd( y );
1346_puts("]\n");
1347#endif
1348            // compute gpid (global processor index) and scheduler base address
1349            unsigned int gpid = cluster_xy * NB_PROCS_MAX + task[task_id].proclocid;
1350            static_scheduler_t* psched = _schedulers[gpid];
1351
1352            // ctx_sr : value required before an eret instruction
1353            unsigned int ctx_sr = 0x0000FF13;
1354
1355            // ctx_ptpr : page table physical base address (shifted by 13 bit)
1356            unsigned int ctx_ptpr = (unsigned int)(_ptabs_paddr[vspace_id] >> 13);
1357
1358            // ctx_ptab : page_table virtual base address
1359            unsigned int ctx_ptab = _ptabs_vaddr[vspace_id];
1360
1361            // ctx_tty : TTY terminal global index provided by the global allocator
1362            unsigned int ctx_tty = 0xFFFFFFFF;
1363            if (task[task_id].use_tty) 
1364            {
1365                if (alloc_tty_channel >= NB_TTY_CHANNELS) 
1366                {
1367                    _puts("\n[BOOT ERROR] TTY index too large for task ");
1368                    _puts(task[task_id].name);
1369                    _puts(" in vspace ");
1370                    _puts(vspace[vspace_id].name);
1371                    _puts("\n");
1372                    _exit();
1373                }
1374                ctx_tty = alloc_tty_channel;
1375                if (NB_TTY_CHANNELS > 1) alloc_tty_channel++;
1376            }
1377            // ctx_nic : NIC channel global index provided by the global allocator
1378            unsigned int ctx_nic = 0xFFFFFFFF;
1379            if (task[task_id].use_nic) 
1380            {
1381                if (alloc_nic_channel >= NB_NIC_CHANNELS) 
1382                {
1383                    _puts("\n[BOOT ERROR] NIC channel index too large for task ");
1384                    _puts(task[task_id].name);
1385                    _puts(" in vspace ");
1386                    _puts(vspace[vspace_id].name);
1387                    _puts("\n");
1388                    _exit();
1389                }
1390                ctx_nic = alloc_nic_channel;
1391                alloc_nic_channel++;
1392            }
1393            // ctx_cma : CMA channel global index provided by the global allocator
1394            unsigned int ctx_cma = 0xFFFFFFFF;
1395            if (task[task_id].use_cma) 
1396            {
1397                if (alloc_cma_channel >= NB_CMA_CHANNELS) 
1398                {
1399                    _puts("\n[BOOT ERROR] CMA channel index too large for task ");
1400                    _puts(task[task_id].name);
1401                    _puts(" in vspace ");
1402                    _puts(vspace[vspace_id].name);
1403                    _puts("\n");
1404                    _exit();
1405                }
1406                ctx_cma = alloc_cma_channel;
1407                alloc_cma_channel++;
1408            }
1409            // ctx_hba : HBA channel global index provided by the global allocator
1410            unsigned int ctx_hba = 0xFFFFFFFF;
1411            if (task[task_id].use_hba) 
1412            {
1413                if (alloc_hba_channel >= NB_HBA_CHANNELS) 
1414                {
1415                    _puts("\n[BOOT ERROR] IOC channel index too large for task ");
1416                    _puts(task[task_id].name);
1417                    _puts(" in vspace ");
1418                    _puts(vspace[vspace_id].name);
1419                    _puts("\n");
1420                    _exit();
1421                }
1422                ctx_hba = alloc_hba_channel;
1423                alloc_hba_channel++;
1424            }
1425            // ctx_tim : TIM local channel index provided by the cluster allocator
1426            unsigned int ctx_tim = 0xFFFFFFFF;
1427            if (task[task_id].use_tim) 
1428            {
1429                unsigned int cluster_id = task[task_id].clusterid;
1430
1431                if ( alloc_tim_channel[cluster_id] >= NB_TIM_CHANNELS ) 
1432                {
1433                    _puts("\n[BOOT ERROR] local TIMER index too large for task ");
1434                    _puts(task[task_id].name);
1435                    _puts(" in vspace ");
1436                    _puts(vspace[vspace_id].name);
1437                    _puts("\n");
1438                    _exit();
1439                }
1440
1441                // checking that there is an ISR_TIMER installed
1442                unsigned int found = 0;
1443                for ( irq_id = 0 ; irq_id < 32 ; irq_id++ ) 
1444                {
1445                    unsigned int entry   = psched->interrupt_vector[irq_id];
1446                    unsigned int isr     = entry & 0x000000FF;
1447                    unsigned int channel = entry>>16;
1448                    if ( (isr == ISR_TIMER) && (channel == alloc_tim_channel[cluster_id]) ) 
1449                    {
1450                        found     = 1;
1451                        ctx_tim =  alloc_tim_channel[cluster_id];
1452                        alloc_tim_channel[cluster_id]++;
1453                        break;
1454                    }
1455                }
1456                if (!found) 
1457                {
1458                    _puts("\n[BOOT ERROR] No ISR_TIMER installed 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            }
1466            // ctx_epc : Get the virtual address of the memory location containing
1467            // the task entry point : the start_vector is stored by GCC in the seg_data
1468            // segment and we must wait the .elf loading to get the entry point value...
1469            mapping_vobj_t* pvobj = &vobj[vspace[vspace_id].vobj_offset + 
1470                                     vspace[vspace_id].start_offset];
1471            unsigned int ctx_epc = pvobj->vaddr + (task[task_id].startid)*4;
1472
1473            // ctx_sp :  Get the vobj containing the stack
1474            unsigned int vobj_id = task[task_id].stack_vobjid + vspace[vspace_id].vobj_offset;
1475            unsigned int ctx_sp = vobj[vobj_id].vaddr + vobj[vobj_id].length;
1476
1477            // get local task index in scheduler
1478            unsigned int ltid = psched->tasks;
1479
1480            // get vspace thread index
1481            unsigned int thread_id = task[task_id].trdid;
1482
1483            if (ltid >= IDLE_TASK_INDEX) 
1484            {
1485                _puts("\n[BOOT ERROR] in boot_schedulers_init() : ");
1486                _putd( ltid );
1487                _puts(" tasks allocated to processor ");
1488                _putd( gpid );
1489                _puts(" / max is ");
1490                _putd( IDLE_TASK_INDEX );
1491                _puts("\n");
1492                _exit();
1493            }
1494
1495            // update the "tasks" and "current" fields in scheduler:
1496            // the first task to execute is task 0 as soon as there is at least
1497            // one task allocated to processor.
1498            psched->tasks   = ltid + 1;
1499            psched->current = 0;
1500
1501            // initializes the task context in scheduler
1502            psched->context[ltid][CTX_CR_ID]    = 0;
1503            psched->context[ltid][CTX_SR_ID]    = ctx_sr;
1504            psched->context[ltid][CTX_SP_ID]    = ctx_sp;
1505            psched->context[ltid][CTX_EPC_ID]   = ctx_epc;
1506            psched->context[ltid][CTX_PTPR_ID]  = ctx_ptpr;
1507            psched->context[ltid][CTX_TTY_ID]   = ctx_tty;
1508            psched->context[ltid][CTX_CMA_ID]   = ctx_cma;
1509            psched->context[ltid][CTX_HBA_ID]   = ctx_hba;
1510            psched->context[ltid][CTX_NIC_ID]   = ctx_nic;
1511            psched->context[ltid][CTX_TIM_ID]   = ctx_tim;
1512            psched->context[ltid][CTX_PTAB_ID]  = ctx_ptab;
1513            psched->context[ltid][CTX_LTID_ID]  = ltid;
1514            psched->context[ltid][CTX_GTID_ID]  = task_id;
1515            psched->context[ltid][CTX_TRDID_ID] = thread_id;
1516            psched->context[ltid][CTX_VSID_ID]  = vspace_id;
1517            psched->context[ltid][CTX_RUN_ID]   = 1;
1518
1519#if BOOT_DEBUG_SCHED
1520_puts("\nTask ");
1521_putd( task_id );
1522_puts(" allocated to processor ");
1523_putd( gpid );
1524_puts("\n  - ctx[LTID]   = ");
1525_putd( psched->context[ltid][CTX_LTID_ID] );
1526_puts("\n  - ctx[SR]     = ");
1527_putx( psched->context[ltid][CTX_SR_ID] );
1528_puts("\n  - ctx[SP]     = ");
1529_putx( psched->context[ltid][CTX_SP_ID] );
1530_puts("\n  - ctx[EPC]    = ");
1531_putx( psched->context[ltid][CTX_EPC_ID] );
1532_puts("\n  - ctx[PTPR]   = ");
1533_putx( psched->context[ltid][CTX_PTPR_ID] );
1534_puts("\n  - ctx[TTY]    = ");
1535_putd( psched->context[ltid][CTX_TTY_ID] );
1536_puts("\n  - ctx[NIC]    = ");
1537_putd( psched->context[ltid][CTX_NIC_ID] );
1538_puts("\n  - ctx[CMA]    = ");
1539_putd( psched->context[ltid][CTX_CMA_ID] );
1540_puts("\n  - ctx[IOC]    = ");
1541_putd( psched->context[ltid][CTX_HBA_ID] );
1542_puts("\n  - ctx[TIM]    = ");
1543_putd( psched->context[ltid][CTX_TIM_ID] );
1544_puts("\n  - ctx[PTAB]   = ");
1545_putx( psched->context[ltid][CTX_PTAB_ID] );
1546_puts("\n  - ctx[GTID]   = ");
1547_putd( psched->context[ltid][CTX_GTID_ID] );
1548_puts("\n  - ctx[VSID]   = ");
1549_putd( psched->context[ltid][CTX_VSID_ID] );
1550_puts("\n  - ctx[TRDID]  = ");
1551_putd( psched->context[ltid][CTX_TRDID_ID] );
1552_puts("\n");
1553#endif
1554
1555        } // end loop on tasks
1556    } // end loop on vspaces
1557} // end _schedulers_init()
1558
1559//////////////////////////////////////////////////////////////////////////////////
1560// This function loads the map.bin file from block device.
1561// The fat global varible is defined in fat32.c file.
1562//////////////////////////////////////////////////////////////////////////////////
1563void boot_mapping_init()
1564{
1565    _ioc_init( 0 );
1566
1567    int fd_id = _fat_open( IOC_BOOT_PA_MODE,
1568                           "map.bin",
1569                           0 );         // no creation
1570
1571    if ( fd_id == -1 )
1572    {
1573        _puts("\n[BOOT ERROR] : map.bin file not found \n");
1574        _exit();
1575    }
1576
1577#if BOOT_DEBUG_MAPPING
1578_puts("\n[BOOT] map.bin file successfully open at cycle ");
1579_putd(_get_proctime());
1580_puts("\n");
1581#endif
1582
1583    unsigned int size    = fat.fd[fd_id].file_size;
1584    unsigned int nblocks = size >> 9;
1585    unsigned int offset  = size & 0x1FF;
1586    if ( offset ) nblocks++;
1587
1588    unsigned int ok = _fat_read( IOC_BOOT_PA_MODE,
1589                                 fd_id, 
1590                                 (unsigned int*)( &seg_boot_mapping_base), 
1591                                 nblocks,       
1592                                 0 );      // offset
1593    if ( ok == -1 )
1594    {
1595        _puts("\n[BOOT ERROR] : unable to load map.bin file \n");
1596        _exit();
1597    }
1598    _fat_close( fd_id );
1599   
1600    boot_mapping_check();
1601} // end boot_mapping_init()
1602
1603
1604//////////////////////////////////////////////////////////////////////////////////
1605// This function open the .elf file identified by the "pathname" argument.
1606// It loads the complete file in a dedicated buffer, it copies all loadable
1607// segments  at the memory virtual address defined in the .elf file,
1608// and close the file.
1609// Notes:
1610// - The processor PTPR should contain the value corresponding to the
1611//   vspace containing the .elf file.
1612// - As this function requires a temporary memory buffer
1613//   to load the complete .elf file before to copy the various segments
1614//   to te proper location, it uses the seg_boot_buffer defined in map.xml.
1615//////////////////////////////////////////////////////////////////////////////////
1616void load_one_elf_file( unsigned int mode,
1617                        char*        pathname,
1618                        unsigned int vspace_id )    // to use the proper page_table
1619{
1620    unsigned int seg_id;
1621
1622    // get boot buffer address and size
1623    char*             boot_buffer      = (char*)(&seg_boot_buffer_base);
1624    unsigned int      boot_buffer_size = (unsigned int)(&seg_boot_buffer_size);
1625
1626#if BOOT_DEBUG_ELF
1627_puts("\n[BOOT DEBUG] Start searching file ");
1628_puts( pathname );
1629_puts(" at cycle ");
1630_putd( _get_proctime() );
1631_puts("\n");
1632#endif
1633
1634    // open .elf file
1635    int fd_id = _fat_open( mode,
1636                           pathname,
1637                           0 );      // no creation
1638    if ( fd_id < 0 )
1639    {
1640        _puts("\n[BOOT ERROR] load_one_elf_file() : ");
1641        _puts( pathname );
1642        _puts(" not found\n");
1643        _exit();
1644    }
1645
1646    // check boot_buffer size versus file size
1647    if ( fat.fd[fd_id].file_size > boot_buffer_size )
1648    {
1649        _puts("\n[BOOT ERROR] load_one_elf_file() : ");
1650        _puts( pathname );
1651        _puts(" exceeds the seg_boot_buffer size\n");
1652        _exit();
1653    }
1654
1655    // compute number of sectors
1656    unsigned int nbytes   = fat.fd[fd_id].file_size;
1657    unsigned int nsectors = nbytes>>9;
1658    if( nbytes & 0x1FF) nsectors++;
1659
1660    // load file in boot_buffer
1661    if( _fat_read( mode, 
1662                   fd_id, 
1663                   boot_buffer,
1664                   nsectors,
1665                   0 ) != nsectors )
1666    {
1667        _puts("\n[BOOT ERROR] load_one_elf_file() : unexpected EOF for file ");
1668        _puts( pathname );
1669        _puts("\n");   
1670        _exit();
1671    }
1672
1673    // Check ELF Magic Number in ELF header
1674    Elf32_Ehdr* elf_header_ptr = (Elf32_Ehdr*)boot_buffer;
1675
1676    if ( (elf_header_ptr->e_ident[EI_MAG0] != ELFMAG0) ||
1677         (elf_header_ptr->e_ident[EI_MAG1] != ELFMAG1) ||
1678         (elf_header_ptr->e_ident[EI_MAG2] != ELFMAG2) ||
1679         (elf_header_ptr->e_ident[EI_MAG3] != ELFMAG3) )
1680    {
1681        _puts("\n[BOOT ERROR] load_elf() : file ");
1682        _puts( pathname );
1683        _puts(" does not use ELF format\n");   
1684        _exit();
1685    }
1686
1687    // get program header table pointer
1688    unsigned int pht_index = elf_header_ptr->e_phoff;
1689    if( pht_index == 0 )
1690    {
1691        _puts("\n[BOOT ERROR] load_one_elf_file() : file ");
1692        _puts( pathname );
1693        _puts(" does not contain loadable segment\n");   
1694        _exit();
1695    }
1696    Elf32_Phdr* elf_pht_ptr = (Elf32_Phdr*)(boot_buffer + pht_index);
1697
1698    // get number of segments
1699    unsigned int nsegments   = elf_header_ptr->e_phnum;
1700
1701#if BOOT_DEBUG_ELF
1702_puts("\n[BOOT DEBUG] File ");
1703_puts( pathname );
1704_puts(" loaded at cycle ");
1705_putd( _get_proctime() );
1706_puts(" / bytes = ");
1707_putd( nbytes );
1708_puts(" / sectors = ");
1709_putd( nsectors );
1710_puts("\n");
1711#endif
1712
1713    // Loop on loadable segments in the ELF file
1714    for (seg_id = 0 ; seg_id < nsegments ; seg_id++)
1715    {
1716        if(elf_pht_ptr[seg_id].p_type == PT_LOAD)
1717        {
1718            // Get segment attributes
1719            unsigned int seg_vaddr  = elf_pht_ptr[seg_id].p_vaddr;
1720            unsigned int seg_offset = elf_pht_ptr[seg_id].p_offset;
1721            unsigned int seg_filesz = elf_pht_ptr[seg_id].p_filesz;
1722            unsigned int seg_memsz  = elf_pht_ptr[seg_id].p_memsz;
1723
1724            if( seg_memsz < seg_filesz )
1725            {
1726                _puts("\n[BOOT ERROR] load_one_elf_file() : segment at vaddr = ");
1727                _putx( seg_vaddr );
1728                _puts(" in file ");
1729                _puts( pathname );
1730                _puts(" has a wrong size \n");   
1731                _exit();
1732            }
1733
1734            // fill empty space with 0 as required
1735            if( seg_memsz > seg_filesz )
1736            {
1737                unsigned int i; 
1738                for( i = seg_filesz ; i < seg_memsz ; i++ ) boot_buffer[i+seg_offset] = 0;
1739            } 
1740
1741            unsigned int src_vaddr = (unsigned int)boot_buffer + seg_offset;
1742
1743#if BOOT_DEBUG_ELF
1744_puts(" - segment ");
1745_putd( seg_id );
1746_puts(" / dst_vaddr = ");
1747_putx( seg_vaddr );
1748_puts(" / src_vaddr = ");
1749_putx( src_vaddr );
1750_puts(" / size = ");
1751_putx( seg_filesz );
1752_puts("\n");
1753#endif
1754
1755            // copy the segment from boot buffer to destination buffer
1756            if( NB_DMA_CHANNELS > 0 )
1757            {
1758                _dma_copy( vspace_id,           // required for V2P translation
1759                           (char*)seg_vaddr,
1760                           (char*)src_vaddr,
1761                           seg_filesz );
1762            }
1763            else
1764            {
1765                _memcpy( (char*)seg_vaddr,
1766                         (char*)src_vaddr,
1767                         seg_filesz );
1768            }
1769        }
1770    } // end for segments
1771
1772    // close .elf file
1773    _fat_close( fd_id );
1774
1775} // end load_one_elf_file()
1776
1777
1778//////////////////////////////////////////////////////////////////////////////////
1779// This function uses the map.bin data structure to load the "kernel.elf" file
1780// as well as the various "application.elf" files.
1781// The "preloader.elf" file is not loaded, because it has been burned in the ROM.
1782// The "boot.elf" file is not loaded, because it has been loaded by the preloader.
1783// It scans all vobjs defined in the map.bin data structure to collect
1784// all .elf files pathnames, and calls the load_one_elf_file() function to
1785// load all loadable segments at the virtual address found in the .elf file.
1786//////////////////////////////////////////////////////////////////////////////////
1787void boot_elf_load()
1788{
1789    mapping_header_t* header = (mapping_header_t *) & seg_boot_mapping_base;
1790    mapping_vspace_t* vspace = _get_vspace_base( header );
1791    mapping_vobj_t*   vobj   = _get_vobj_base( header );
1792    unsigned int      vspace_id;
1793    unsigned int      vobj_id;
1794    unsigned int      found;
1795
1796    // Scan all vobjs corresponding to global vsegs,
1797    // to find the pathname to the kernel.elf file
1798    found = 0;
1799    for( vobj_id = 0 ; vobj_id < header->globals ; vobj_id++ )
1800    {
1801        if(vobj[vobj_id].type == VOBJ_TYPE_ELF) 
1802        {   
1803            found = 1;
1804            break;
1805        }
1806    }
1807
1808    // We need one kernel.elf file
1809    if (found == 0)
1810    {
1811        _puts("[BOOT ERROR] boot_elf_load() : kernel.elf file not found\n");
1812        _exit();
1813    }
1814
1815    load_one_elf_file( IOC_BOOT_VA_MODE,
1816                       vobj[vobj_id].binpath,
1817                       0 );                         // vspace 0
1818
1819    _puts("\n[BOOT] File ");
1820    _puts( vobj[vobj_id].binpath );
1821    _puts(" loaded at cycle ");
1822    _putd( _get_proctime() );
1823    _puts("\n");
1824
1825    // loop on the vspaces, scanning all vobjs in a vspace,
1826    // to find the pathname of the .elf file associated to the vspace.
1827    for( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1828    {
1829        // Set PTPR depending on the vspace, as seg_data is defined in virtual space.
1830        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id] >> 13) );
1831
1832        // loop on the vobjs in vspace (vobj_id is the global index)
1833        unsigned int found = 0;
1834        for (vobj_id = vspace[vspace_id].vobj_offset;
1835             vobj_id < (vspace[vspace_id].vobj_offset + vspace[vspace_id].vobjs);
1836             vobj_id++) 
1837        {
1838            if(vobj[vobj_id].type == VOBJ_TYPE_ELF) 
1839            {   
1840                found = 1;
1841                break;
1842            }
1843        }
1844
1845        // We want one .elf file per vspace
1846        if (found == 0)
1847        {
1848            _puts("[BOOT ERROR] boot_elf_load() : .elf file not found for vspace ");
1849            _puts( vspace[vspace_id].name );
1850            _puts("\n");
1851            _exit();
1852        }
1853
1854        load_one_elf_file( IOC_BOOT_VA_MODE,
1855                           vobj[vobj_id].binpath,
1856                           vspace_id );
1857
1858        _puts("\n[BOOT] File ");
1859        _puts( vobj[vobj_id].binpath );
1860        _puts(" loaded at cycle ");
1861        _putd( _get_proctime() );
1862        _puts("\n");
1863
1864    }  // end for vspaces
1865
1866    // restaure vspace 0 PTPR
1867    _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0] >> 13) );
1868
1869} // end boot_elf_load()
1870
1871////////////////////////////////////////////////////////////////////////////////
1872// This function intializes the periherals and coprocessors, as specified
1873// in the mapping_info file.
1874////////////////////////////////////////////////////////////////////////////////
1875void boot_peripherals_init() 
1876{
1877    mapping_header_t * header   = (mapping_header_t *) & seg_boot_mapping_base;
1878    mapping_cluster_t * cluster = _get_cluster_base(header);
1879    mapping_periph_t * periph   = _get_periph_base(header);
1880    mapping_vobj_t * vobj       = _get_vobj_base(header);
1881    mapping_vspace_t * vspace   = _get_vspace_base(header);
1882    mapping_coproc_t * coproc   = _get_coproc_base(header);
1883    mapping_cp_port_t * cp_port = _get_cp_port_base(header);
1884
1885    unsigned int cluster_id;
1886    unsigned int periph_id;
1887    unsigned int coproc_id;
1888    unsigned int cp_port_id;
1889    unsigned int channel_id;
1890
1891    // loop on all physical clusters
1892    for (cluster_id = 0; cluster_id < X_SIZE*Y_SIZE; cluster_id++) 
1893    {
1894        // computes cluster coordinates
1895        unsigned int x          = cluster[cluster_id].x;
1896        unsigned int y          = cluster[cluster_id].y;
1897        unsigned int cluster_xy = (x<<Y_WIDTH) + y;
1898
1899#if BOOT_DEBUG_PERI
1900_puts("\n[BOOT DEBUG] ****** peripherals initialisation in cluster[");
1901_putd( x );
1902_puts(",");
1903_putd( y );
1904_puts("] ******\n");
1905#endif
1906
1907        // loop on peripherals
1908        for (periph_id = cluster[cluster_id].periph_offset;
1909             periph_id < cluster[cluster_id].periph_offset +
1910             cluster[cluster_id].periphs; periph_id++) 
1911        {
1912            unsigned int type       = periph[periph_id].type;
1913            unsigned int channels   = periph[periph_id].channels;
1914
1915            switch (type) 
1916            {
1917                case PERIPH_TYPE_IOC:    // vci_block_device component
1918                {
1919                    // initialize all channels except channel 0 because it has been
1920                    // initialize during mapping_info loading
1921                    for (channel_id = 1; channel_id < channels; channel_id++) 
1922                    {
1923                        _ioc_init( channel_id );
1924                    }
1925#if BOOT_DEBUG_PERI
1926_puts("- IOC / channels = ");
1927_putd(channels);
1928_puts("\n");
1929#endif
1930                    break;
1931                }
1932                case PERIPH_TYPE_DMA:    // vci_multi_dma component
1933                {
1934                    for (channel_id = 0; channel_id < channels; channel_id++) 
1935                    {
1936                        _dma_init( cluster_xy, channel_id );
1937                    }
1938#if BOOT_DEBUG_PERI
1939_puts("- DMA / channels = ");
1940_putd(channels);
1941_puts("\n");
1942#endif
1943                    break;
1944                }
1945                case PERIPH_TYPE_FBF:    // vci_block_device component
1946                {
1947                    // nothing to do
1948#if BOOT_DEBUG_PERI
1949_puts("- FBF / channels = ");
1950_putd(channels);
1951_puts("\n");
1952#endif
1953                    break;
1954                }
1955                case PERIPH_TYPE_CMA:    // vci_chbuf_dma component
1956                {
1957                    for (channel_id = 0; channel_id < channels; channel_id++) 
1958                    {
1959                        // TODO
1960                    }
1961#if BOOT_DEBUG_PERI
1962_puts("- CMA / channels = ");
1963_putd(channels);
1964_puts("\n");
1965#endif
1966                    break;
1967                }
1968                case PERIPH_TYPE_NIC:    // vci_multi_nic component
1969                {
1970                    for (channel_id = 0; channel_id < channels; channel_id++) 
1971                    {
1972                        // TODO
1973                    }
1974#if BOOT_DEBUG_PERI
1975_puts("- NIC / channels = ");
1976_putd(channels);
1977_puts("\n");
1978#endif
1979                    break;
1980                }
1981                case PERIPH_TYPE_XCU:    // vci_xicu component
1982                {
1983                    // nothing to do
1984#if BOOT_DEBUG_PERI
1985_puts("- XCU / channels = ");
1986_putd(channels);
1987_puts("\n");
1988#endif
1989                    break;
1990                }
1991                case PERIPH_TYPE_MMC:    // vci_memcache config
1992                {
1993                    // nothing to do
1994#if BOOT_DEBUG_PERI
1995_puts("- MMC / channels = ");
1996_putd(channels);
1997_puts("\n");
1998#endif
1999                    break;
2000                }
2001                case PERIPH_TYPE_TTY:    // vci_multi_tty component
2002                {
2003#if BOOT_DEBUG_PERI
2004_puts("- TTY / channels = ");
2005_putd(channels);
2006_puts("\n");
2007#endif
2008                    break;
2009                }
2010                case PERIPH_TYPE_IOB:    // vci_io_bridge component
2011                {
2012                    if (USE_IOB) 
2013                    {
2014                        // TODO
2015                        // get the iommu page table physical address
2016                        // define IPI address mapping the IOC interrupt
2017                        // set IOMMU page table address
2018                        // pseg_base[IOB_IOMMU_PTPR] = ptab_pbase;   
2019                        // activate IOMMU
2020                        // pseg_base[IOB_IOMMU_ACTIVE] = 1;       
2021                    }
2022#if BOOT_DEBUG_PERI
2023_puts("- IOB / channels = ");
2024_putd(channels);
2025_puts("\n");
2026#endif
2027                    break;
2028                }
2029            }  // end switch periph type
2030        }  // end for periphs
2031
2032#if BOOT_DEBUG_PERI
2033_puts("\n[BOOT DEBUG] ****** coprocessors initialisation in cluster[");
2034_putd( x );
2035_puts(",");
2036_putd( y );
2037_puts("] ******\n");
2038#endif
2039
2040        // loop on coprocessors
2041        for ( coproc_id = cluster[cluster_id].coproc_offset;
2042              coproc_id < cluster[cluster_id].coproc_offset +
2043              cluster[cluster_id].coprocs; coproc_id++ ) 
2044        {
2045
2046#if BOOT_DEBUG_PERI
2047_puts("- coprocessor name : ");
2048_puts(coproc[coproc_id].name);
2049_puts(" / nb ports = ");
2050_putd((unsigned int) coproc[coproc_id].ports);
2051_puts("\n");
2052#endif
2053            // loop on the coprocessor ports
2054            for ( cp_port_id = coproc[coproc_id].port_offset;
2055                  cp_port_id < coproc[coproc_id].port_offset + coproc[coproc_id].ports;
2056                  cp_port_id++ ) 
2057            {
2058                unsigned int vspace_id = cp_port[cp_port_id].vspaceid;
2059                unsigned int vobj_id   = cp_port[cp_port_id].mwmr_vobjid + 
2060                                                vspace[vspace_id].vobj_offset;
2061
2062                // Get MWMR channel base address
2063                paddr_t mwmr_channel_pbase = vobj[vobj_id].paddr;
2064
2065                _mwr_hw_init( cluster_xy,
2066                              cp_port_id, 
2067                              cp_port[cp_port_id].direction, 
2068                              mwmr_channel_pbase );
2069#if BOOT_DEBUG_PERI
2070_puts("     port direction: ");
2071_putd( (unsigned int)cp_port[cp_port_id].direction );
2072_puts(" / mwmr_channel_pbase = ");
2073_putl( mwmr_channel_pbase );
2074_puts(" / name = ");
2075_puts(vobj[vobj_id].name);
2076_puts(" / in vspace ");
2077_puts(vspace[vspace_id].name);
2078_puts("\n"); 
2079#endif
2080            } // end for cp_ports
2081        } // end for coprocs
2082    } // end for clusters
2083} // end boot_peripherals_init()
2084
2085/////////////////////////////////////////////////////////////////////////
2086// This function is the entry point of the boot code for all processors.
2087// Most of this code is executed by Processor 0 only.
2088/////////////////////////////////////////////////////////////////////////
2089void boot_init() 
2090{
2091    mapping_header_t* header     = (mapping_header_t *) & seg_boot_mapping_base;
2092    unsigned int      gpid       = _get_procid();
2093    unsigned int      cluster_xy = gpid / NB_PROCS_MAX;
2094    unsigned int      lpid       = gpid % NB_PROCS_MAX;
2095 
2096    if ( gpid == 0 )    // only Processor 0 does it
2097    {
2098        _puts("\n[BOOT] boot_init start at cycle ");
2099        _putd(_get_proctime());
2100        _puts("\n");
2101
2102        // Loading the map.bin file into memory and checking it
2103        boot_mapping_init();
2104
2105        _puts("\n[BOOT] Mapping ");
2106        _puts( header->name );
2107        _puts(" loaded at cycle ");
2108        _putd(_get_proctime());
2109        _puts("\n");
2110
2111        // Building all page tables
2112        boot_pt_init();
2113
2114        _puts("\n[BOOT] Page Tables initialisation completed at cycle ");
2115        _putd(_get_proctime());
2116        _puts("\n");
2117
2118        // Activating proc 0 MMU
2119        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0]>>13) );
2120        _set_mmu_mode( 0xF );
2121
2122        _puts("\n[BOOT] Processor[0,0,0] : MMU activation at cycle ");
2123        _putd(_get_proctime());
2124        _puts("\n");
2125
2126        // Initialising private vobjs in vspaces
2127        boot_vobjs_init();
2128
2129        _puts("\n[BOOT] Private vobjs initialised at cycle ");
2130        _putd(_get_proctime());
2131        _puts("\n");
2132
2133        // Initializing schedulers
2134        boot_schedulers_init();
2135
2136        _puts("\n[BOOT] All schedulers initialised at cycle ");
2137        _putd(_get_proctime());
2138        _puts("\n");
2139       
2140        // Setting CP0_SCHED register for proc 0
2141        _set_sched( (unsigned int)_schedulers[0] );
2142
2143        // Initializing peripherals
2144        boot_peripherals_init();
2145
2146        _puts("\n[BOOT] All peripherals initialised at cycle ");
2147        _putd(_get_proctime());
2148        _puts("\n");
2149
2150        // Loading all .elf files
2151        boot_elf_load();
2152
2153        _puts("\n[BOOT] All ELF files loaded at cycle ");
2154        _putd(_get_proctime());
2155        _puts("\n");
2156
2157        // P0 starts all other processors
2158        unsigned int x,y,p;
2159        for (x = 0 ; x < X_SIZE ; x++) 
2160        {
2161            for (y = 0 ; y < Y_SIZE ; y++) 
2162            {
2163                for(p = 0; p < NB_PROCS_MAX; p++) 
2164                {
2165                    if ( (x != 0) || (y != 0) || (p != 0) )
2166                    {
2167                        _xcu_send_ipi( (x<<Y_WIDTH) + y, 
2168                                       p,
2169                                       (unsigned int)boot_init );
2170                    }
2171                }
2172            }
2173        }
2174    }  // end monoprocessor boot
2175
2176    // reset BEV bit in the status register to use GIET exception
2177    // handler instead of the PRELOADER exception handler
2178    _set_sr( 0 );
2179
2180    // all processor initialise SCHED register
2181    _set_sched( (unsigned int)_schedulers[gpid] );
2182
2183    // all processors (but Proc 0) activate MMU
2184    if ( gpid != 0 )
2185    {
2186        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0]>>13) );
2187        _set_mmu_mode( 0xF );
2188
2189        _tty_get_lock( 0 );
2190        _puts("\n[BOOT] Processor[");
2191        _putd( cluster_xy >> Y_WIDTH );
2192        _puts(",");
2193        _putd( cluster_xy & ((1<<Y_WIDTH)-1) );
2194        _puts(",");
2195        _putd( lpid );
2196        _puts("] : MMU activation at cycle ");
2197        _putd(_get_proctime());
2198        _puts("\n");
2199        _tty_release_lock( 0 );
2200    }
2201
2202    // all processors jump to kernel_init
2203    unsigned int kernel_entry = (unsigned int)&seg_kernel_init_base;
2204
2205#if GIET_DEBUG_INIT
2206    _tty_get_lock( 0 );
2207    _puts("\n[BOOT DEBUG] Processor[");
2208    _putd( cluster_xy >> Y_WIDTH );
2209    _puts(",");
2210    _putd( cluster_xy & ((1<<Y_WIDTH)-1) );
2211    _puts(",");
2212    _putd( lpid );
2213    _puts("] enters kernel at cycle ");
2214    _putd( _get_proctime() );
2215    _puts(" / kernel entry = ");
2216    _putx( kernel_entry );
2217    _puts("\n");
2218    _tty_release_lock( 0 );
2219#endif
2220
2221    asm volatile( "jr   %0" ::"r"(kernel_entry) );
2222
2223} // end boot_init()
2224
2225
2226// Local Variables:
2227// tab-width: 4
2228// c-basic-offset: 4
2229// c-file-offsets:((innamespace . 0)(inline-open . 0))
2230// indent-tabs-mode: nil
2231// End:
2232// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
2233
Note: See TracBrowser for help on using the repository browser.