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

Last change on this file since 305 was 299, checked in by alain, 11 years ago

ntroducing the TOTAL_PROCS variable in the hard_config.h file
(used by the synchronisation barrier in kernel_init.c)

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