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

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

boot.c:

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