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

Last change on this file since 408 was 392, checked in by alain, 10 years ago

Cosmetic

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