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

Last change on this file since 289 was 289, checked in by cfuguet, 10 years ago

Modifications on GIET-VM IOC driver:

  • Introducing new layer on the IOC driver. Every call to ioc_read, ioc_write, ioc_get_block_size or ioc_init

functions will call the specific driver of the used IOC
controller. Supported IOC controllers are (for now) :

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