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

Last change on this file since 267 was 267, checked in by cfuguet, 10 years ago
  • Adding new task context information: THREAD INDEX.

This value can be accessed by USER applications to get the
thread index of the current task. This thread index
corresponds to the index in a vspace.

The value of this index can be forced in the vspace part
of the XML description file using the trdid field in the
task description. When this value is missing, for each
task, a value from 0 to N-1 will be assigned, where N is
the number of task in the vspace.

The user application access this value through the
giet_thread_id() function defined in the stdio library
which uses the SYSCALL_THREAD_ID to access the task
context information.

  • Supporting mono TTY platforms

When the GIET_MONO_TTY constant defined in the giet_config
file, contains a value different than 0, all tasks will
share the TTY[0]. If this is the case, in the stdio
library, the giet_tty_printf() function will take the TTY
hardware lock before writing

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