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

Last change on this file since 351 was 347, checked in by alain, 10 years ago

Introducing support for distributed page tables, kernel code and user code,
(if it is requested in the mapping).

File size: 91.1 KB
RevLine 
[258]1//////////////////////////////////////////////////////////////////////////////////////////
2// File     : boot.c
3// Date     : 01/11/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6//////////////////////////////////////////////////////////////////////////////////////////
7// The boot.c file is part of the GIET-VM nano-kernel.
8//
9// This nano-kernel has been written for the MIPS32 processor.
10// The virtual adresses are on 32 bits and use the (unsigned int) type, but the
11// physicals addresses can have up to 40 bits, and use the  (unsigned long long) type.
12// It natively supports clusterised shared mmemory multi-processors architectures,
[263]13// where each processor is identified by a composite index (cluster_xy, local_id),
[258]14// and where there is one physical memory bank per cluster.
15//
[347]16// This code, executed in the boot phase by proc[0,0,0] performs the following tasks:
17// - load into memory the 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)
97# error The X_SIZE value must be defined in the 'hard_config.h' file !
[258]98#endif
99
[263]100#if !defined(Y_SIZE)
101# error The Y_SIZE value must be defined in the 'hard_config.h' file !
102#endif
103
104#if !defined(X_WIDTH)
105# error The X_WIDTH value must be defined in the 'hard_config.h' file !
106#endif
107
108#if !defined(Y_WIDTH)
109# error The Y_WIDTH value must be defined in the 'hard_config.h' file !
110#endif
111
[321]112#if !defined(SEG_BOOT_MAPPING_BASE)
113# error: You must define SEG_BOOT_MAPPING_BASE in the hard_config.h file
114#endif
115
116#if !defined(SEG_BOOT_BUFFER_BASE)
117# error: You must define SEG_BOOT_BUFFER_BASE in the hard_config.h file
118#endif
119
120#if !defined(SEG_BOOT_BUFFER_SIZE)
121# error: You must define SEG_BOOT_BUFFER_SIZE in the hard_config.h file
122#endif
123
[258]124#if !defined(NB_PROCS_MAX)
[263]125# error The NB_PROCS_MAX value must be defined in the 'hard_config.h' file !
[258]126#endif
127
128#if !defined(GIET_NB_VSPACE_MAX)
129# error The GIET_NB_VSPACE_MAX value must be defined in the 'giet_config.h' file !
130#endif
131
132////////////////////////////////////////////////////////////////////////////
133//      Global variables for boot code
134// Both the page tables for the various virtual spaces, and the schedulers
135// for the processors are physically distributed on the clusters.
136// These global variables are just arrays of pointers.
137////////////////////////////////////////////////////////////////////////////
138
139// This global variable is allocated in "fat32.c" file
140extern fat32_fs_t fat;
141
[347]142// Page tables base addresses, sizes, and PT2 allocators:
143// For each vspace, it can exist one page table per cluster,
144// but only one virtual base address per vspace
145
[258]146__attribute__((section (".bootdata"))) 
[347]147unsigned int _ptabs_vaddr[GIET_NB_VSPACE_MAX];
[258]148
149__attribute__((section (".bootdata"))) 
[347]150paddr_t _ptabs_paddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
[258]151
152__attribute__((section (".bootdata"))) 
[347]153unsigned int _ptabs_max_pt2[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
[258]154
155__attribute__((section (".bootdata"))) 
[347]156unsigned int _ptabs_next_pt2[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
[258]157
[263]158// Scheduler pointers array (virtual addresses)
[347]159// indexed by (x,y,lpid) : (((x << Y_WIDTH) + y) * NB_PROCS_MAX) + lpid
[263]160__attribute__((section (".bootdata"))) 
[347]161static_scheduler_t* _schedulers[1<<X_WIDTH][1<<Y_WIDTH][NB_PROCS_MAX];
[258]162
[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);
1114                    barrier->count = vobj[vobj_id].init;
1115                    barrier->init = vobj[vobj_id].init;
1116#if BOOT_DEBUG_VOBJS
[309]1117_puts("          init_value = ");
[258]1118_putd(barrier->init);
1119_puts("\n");
1120#endif
1121                    break;
1122                }
1123                case VOBJ_TYPE_LOCK:    // init value is "not taken"
1124                {
1125#if BOOT_DEBUG_VOBJS
1126_puts("LOCK    : ");
1127_puts(vobj[vobj_id].name);
[309]1128_puts(" / vaddr = ");
1129_putx(vobj[vobj_id].vaddr);
1130_puts(" / paddr = ");
1131_putl(vobj[vobj_id].paddr);
1132_puts(" / length = ");
1133_putx(vobj[vobj_id].length);
[258]1134_puts("\n");
1135#endif
[309]1136                    unsigned int* lock = (unsigned int *) (vobj[vobj_id].vaddr);
1137                    *lock = 0;
[258]1138                    break;
1139                }
1140                case VOBJ_TYPE_BUFFER:    // nothing to initialise
1141                {
1142#if BOOT_DEBUG_VOBJS
1143_puts("BUFFER  : ");
1144_puts(vobj[vobj_id].name);
[309]1145_puts(" / vaddr = ");
1146_putx(vobj[vobj_id].vaddr);
[258]1147_puts(" / paddr = ");
1148_putl(vobj[vobj_id].paddr);
1149_puts(" / length = ");
1150_putx(vobj[vobj_id].length);
1151_puts("\n");
1152#endif
1153                    break;
1154                }
1155                case VOBJ_TYPE_MEMSPACE:
1156                {
1157#if BOOT_DEBUG_VOBJS
1158_puts("MEMSPACE  : ");
1159_puts(vobj[vobj_id].name);
1160_puts(" / vaddr = ");
1161_putx(vobj[vobj_id].vaddr);
[309]1162_puts(" / paddr = ");
1163_putl(vobj[vobj_id].paddr);
[258]1164_puts(" / length = ");
1165_putx(vobj[vobj_id].length);
[309]1166_puts("\n");
1167#endif
1168                    giet_memspace_t* memspace = (giet_memspace_t *) vobj[vobj_id].vaddr;
1169                    memspace->buffer = (void *) vobj[vobj_id].vaddr + 8;
1170                    memspace->size = vobj[vobj_id].length - 8;
1171#if BOOT_DEBUG_VOBJS
1172_puts("          buffer vbase = ");
[258]1173_putx((unsigned int)memspace->buffer);
1174_puts(" / size = ");
1175_putx(memspace->size);
1176_puts("\n");
1177#endif
1178                    break;
1179                }
1180                case VOBJ_TYPE_PTAB:    // nothing to initialize
1181                {
1182#if BOOT_DEBUG_VOBJS
1183_puts("PTAB    : ");
1184_puts(vobj[vobj_id].name);
[309]1185_puts(" / vaddr = ");
1186_putx(vobj[vobj_id].vaddr);
1187_puts(" / paddr = ");
1188_putl(vobj[vobj_id].paddr);
[258]1189_puts(" / length = ");
1190_putx(vobj[vobj_id].length);
1191_puts("\n");
1192#endif
[309]1193                    ptab_found = 1;
[258]1194                    break;
1195                }
1196                case VOBJ_TYPE_CONST:
1197                {
1198#if BOOT_DEBUG_VOBJS
1199_puts("CONST   : ");
1200_puts(vobj[vobj_id].name);
[309]1201_puts(" / vaddr = ");
1202_putx(vobj[vobj_id].vaddr);
1203_puts(" / paddr = ");
[258]1204_putl(vobj[vobj_id].paddr);
[309]1205_puts(" / length = ");
1206_putx(vobj[vobj_id].length);
[258]1207_puts(" / init = ");
[309]1208_putx(vobj[vobj_id].init);
1209_puts("\n");
1210#endif
1211                    unsigned int* addr = (unsigned int *) vobj[vobj_id].vaddr;
1212                    *addr = vobj[vobj_id].init;
1213
1214#if BOOT_DEBUG_VOBJS
1215_puts("          init = ");
[258]1216_putx(*addr);
1217_puts("\n");
1218#endif
1219                    break;
1220                }
1221                default:
1222                {
1223                    _puts("\n[BOOT ERROR] illegal vobj type: ");
1224                    _putd(vobj[vobj_id].type);
1225                    _puts("\n");
1226                    _exit();
1227                }
1228            }            // end switch type
1229        }            // end loop on vobjs
1230        if (ptab_found == 0) 
1231        {
1232            _puts("\n[BOOT ERROR] Missing PTAB for vspace ");
1233            _putd(vspace_id);
1234            _exit();
1235        }
1236    } // end loop on vspaces
1237
1238} // end boot_vobjs_init()
1239
1240///////////////////////////////////////////////////////////////////////////////
1241// This function returns in the vbase and length buffers the virtual base
1242// address and the length of the  segment allocated to the schedulers array
1243// in the cluster defined by the clusterid argument.
1244///////////////////////////////////////////////////////////////////////////////
1245void boot_get_sched_vaddr( unsigned int  cluster_id,
1246                           unsigned int* vbase, 
1247                           unsigned int* length )
1248{
[321]1249    mapping_header_t* header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[258]1250    mapping_vobj_t*   vobj   = _get_vobj_base(header);
1251    mapping_vseg_t*   vseg   = _get_vseg_base(header);
1252    mapping_pseg_t*   pseg   = _get_pseg_base(header);
1253
1254    unsigned int vseg_id;
1255    unsigned int found = 0;
1256
1257    for ( vseg_id = 0 ; (vseg_id < header->vsegs) && (found == 0) ; vseg_id++ )
1258    {
1259        if ( (vobj[vseg[vseg_id].vobj_offset].type == VOBJ_TYPE_SCHED) && 
[263]1260             (pseg[vseg[vseg_id].psegid].clusterid == cluster_id ) )
[258]1261        {
1262            *vbase  = vseg[vseg_id].vbase;
1263            *length = vobj[vseg[vseg_id].vobj_offset].length;
1264            found = 1;
1265        }
1266    }
1267    if ( found == 0 )
1268    {
[263]1269        mapping_cluster_t* cluster = _get_cluster_base(header);
1270        _puts("\n[BOOT ERROR] No vobj of type SCHED in cluster [");
1271        _putd( cluster[cluster_id].x );
1272        _puts(",");
1273        _putd( cluster[cluster_id].y );
1274        _puts("]\n");
[258]1275        _exit();
1276    }
1277} // end boot_get_sched_vaddr()
1278
1279////////////////////////////////////////////////////////////////////////////////////
1280// This function initialises all processors schedulers.
1281// This is done by processor 0, and the MMU must be activated.
[347]1282// - In Step 1, it initialises the _schedulers[] pointers array, and scan
[258]1283//              the processors to initialise the schedulers, including the
[321]1284//              idle_task context (ltid == 14) and HWI / SWI / PTI vectors.
1285// - In Step 2, it scan all tasks in all vspaces to complete the tasks contexts,
1286//              initialisation as specified in the mapping_info data structure.
[258]1287////////////////////////////////////////////////////////////////////////////////////
1288void boot_schedulers_init() 
1289{
[321]1290    mapping_header_t*  header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[258]1291    mapping_cluster_t* cluster = _get_cluster_base(header);
1292    mapping_vspace_t*  vspace  = _get_vspace_base(header);
1293    mapping_task_t*    task    = _get_task_base(header);
1294    mapping_vobj_t*    vobj    = _get_vobj_base(header);
[295]1295    mapping_periph_t*  periph  = _get_periph_base(header);
[258]1296    mapping_irq_t*     irq     = _get_irq_base(header);
1297
1298    unsigned int cluster_id;    // cluster index in mapping_info
[295]1299    unsigned int periph_id;     // peripheral index in mapping_info
[258]1300    unsigned int irq_id;        // irq index in mapping_info
1301    unsigned int vspace_id;     // vspace index in mapping_info
1302    unsigned int task_id;       // task index in mapping_info
[321]1303    unsigned int vobj_id;       // vobj index in mapping_info
[258]1304
[321]1305    unsigned int lpid;          // local processor index (for several loops)
1306
1307    // TTY, NIC, CMA, HBA, user timer, and WTI channel allocators to user tasks:
[258]1308    // - TTY[0] is reserved for the kernel
1309    // - In all clusters the first NB_PROCS_MAX timers
1310    //   are reserved for the kernel (context switch)
[321]1311    unsigned int alloc_tty_channel = 1;              // global
1312    unsigned int alloc_nic_channel = 0;              // global
1313    unsigned int alloc_cma_channel = 0;              // global
1314    unsigned int alloc_hba_channel = 0;              // global
1315    unsigned int alloc_tim_channel[X_SIZE*Y_SIZE];   // one per cluster
[258]1316
[321]1317    // WTI allocators to processors
1318    // In all clusters, first NB_PROCS_MAX WTIs are for WAKUP
1319    unsigned int alloc_wti_channel[X_SIZE*Y_SIZE];   // one per cluster
[258]1320
[321]1321    // pointers on the XCU and PIC peripherals
1322    mapping_periph_t*  xcu = NULL;
1323    mapping_periph_t*  pic = NULL;
1324
1325    // schedulers array base address in a cluster
1326    unsigned int          sched_vbase; 
1327    unsigned int          sched_length; 
1328    static_scheduler_t*   psched; 
1329
[258]1330    /////////////////////////////////////////////////////////////////////////
1331    // Step 1 : loop on the clusters and on the processors
1332    //          to initialize the schedulers[] array of pointers,
1333    //          and the interrupt vectors.
1334    // Implementation note:
[347]1335    // We need to use both (proc_id) to scan the mapping info structure,
1336    // and (x,y,lpid) to access the schedulers array.
[258]1337
[263]1338    for (cluster_id = 0 ; cluster_id < X_SIZE*Y_SIZE ; cluster_id++) 
[258]1339    {
[263]1340        unsigned int x          = cluster[cluster_id].x;
1341        unsigned int y          = cluster[cluster_id].y;
[258]1342
1343#if BOOT_DEBUG_SCHED
[263]1344_puts("\n[BOOT DEBUG] Initialise schedulers in cluster[");
1345_putd( x );
1346_puts(",");
1347_putd( y );
1348_puts("]\n");
[258]1349#endif
1350        alloc_tim_channel[cluster_id] = NB_PROCS_MAX;
[321]1351        alloc_wti_channel[cluster_id] = NB_PROCS_MAX;
[258]1352
1353        // checking processors number
[295]1354        if ( cluster[cluster_id].procs > NB_PROCS_MAX )
[258]1355        {
[263]1356            _puts("\n[BOOT ERROR] Too much processors in cluster[");
1357            _putd( x );
1358            _puts(",");
1359            _putd( y );
1360            _puts("]\n");
[258]1361            _exit();
1362        }
1363 
[295]1364        // no schedulers initialisation if nprocs == 0
1365        if ( cluster[cluster_id].procs > 0 )
[258]1366        {
[321]1367            // get scheduler array virtual base address from mapping
[295]1368            boot_get_sched_vaddr( cluster_id, &sched_vbase, &sched_length );
[258]1369
[295]1370            if ( sched_length < (cluster[cluster_id].procs<<12) ) // 4 Kbytes per scheduler
1371            {
1372                _puts("\n[BOOT ERROR] Schedulers segment too small in cluster[");
1373                _putd( x );
1374                _puts(",");
1375                _putd( y );
1376                _puts("]\n");
1377                _exit();
1378            }
[263]1379
[295]1380            psched = (static_scheduler_t*)sched_vbase;
[258]1381
[321]1382            // scan peripherals to find the ICU/XCU and the PIC component
1383
1384            xcu = NULL; 
[295]1385            for ( periph_id = cluster[cluster_id].periph_offset ;
1386                  periph_id < cluster[cluster_id].periph_offset + cluster[cluster_id].periphs;
1387                  periph_id++ )
1388            {
1389                if( (periph[periph_id].type == PERIPH_TYPE_XCU) || 
1390                    (periph[periph_id].type == PERIPH_TYPE_ICU) )
1391                {
[321]1392                    xcu = &periph[periph_id];
1393
1394                    if ( xcu->arg < cluster[cluster_id].procs )
1395                    {
1396                        _puts("\n[BOOT ERROR] Not enough inputs for XCU[");
1397                        _putd( x );
1398                        _puts(",");
1399                        _putd( y );
1400                        _puts("]\n");
1401                        _exit();
1402                    }
[295]1403                }
[321]1404                if( periph[periph_id].type == PERIPH_TYPE_PIC )   
1405                {
1406                    pic = &periph[periph_id];
1407                }
[295]1408            } 
[321]1409            if ( xcu == NULL )
[295]1410            {         
1411                _puts("\n[BOOT ERROR] No ICU / XCU component in cluster[");
1412                _putd( x );
1413                _puts(",");
1414                _putd( y );
1415                _puts("]\n");
1416                _exit();
1417            }
1418
[321]1419            // loop on processors for sechedulers default values
1420            // initialisation, including WTI and PTI vectors
[295]1421            for ( lpid = 0 ; lpid < cluster[cluster_id].procs ; lpid++ )
1422            {
1423                // set the schedulers pointers array
[347]1424                _schedulers[x][y][lpid] = (static_scheduler_t*)&psched[lpid];
[295]1425
[258]1426#if BOOT_DEBUG_SCHED
[295]1427_puts("\nProc[");
[263]1428_putd( x );
[295]1429_puts(",");
[263]1430_putd( y );
[295]1431_puts(",");
[263]1432_putd( lpid );
[295]1433_puts("] : scheduler virtual base address = ");
1434_putx( (unsigned int)&psched[lpid] );
[258]1435_puts("\n");
1436#endif
[295]1437                // initialise the "tasks" and "current" variables default values
1438                psched[lpid].tasks   = 0;
1439                psched[lpid].current = IDLE_TASK_INDEX;
[258]1440
[321]1441                // default values for HWI / PTI / SWI vectors (valid bit = 0)
[295]1442                unsigned int slot;
1443                for (slot = 0; slot < 32; slot++)
1444                {
1445                    psched[lpid].hwi_vector[slot] = 0;
1446                    psched[lpid].pti_vector[slot] = 0;
1447                    psched[lpid].wti_vector[slot] = 0;
1448                }
[258]1449
[321]1450                // WTI[lpid] <= ISR_WAKUP / PTI[lpid] <= ISR_TICK
1451                psched[lpid].wti_vector[lpid] = ISR_WAKUP | 0x80000000;
1452                psched[lpid].pti_vector[lpid] = ISR_TICK  | 0x80000000;
1453
[295]1454                // initializes the idle_task context in scheduler:
1455                // - the SR slot is 0xFF03 because this task run in kernel mode.
1456                // - it uses the page table of vspace[0]
1457                // - it uses the kernel TTY terminal
1458                // - slots containing addresses (SP, RA, EPC, PTAB, PTPR)
1459                //   must be re-initialised by kernel_parallel_init()
[258]1460
[295]1461                psched[lpid].context[IDLE_TASK_INDEX][CTX_CR_ID]    = 0;
1462                psched[lpid].context[IDLE_TASK_INDEX][CTX_SR_ID]    = 0xFF03;
[347]1463                psched[lpid].context[IDLE_TASK_INDEX][CTX_PTPR_ID]  = _ptabs_paddr[0][x][y]>>13;
[295]1464                psched[lpid].context[IDLE_TASK_INDEX][CTX_PTAB_ID]  = _ptabs_vaddr[0];
1465                psched[lpid].context[IDLE_TASK_INDEX][CTX_TTY_ID]   = 0;
1466                psched[lpid].context[IDLE_TASK_INDEX][CTX_LTID_ID]  = IDLE_TASK_INDEX;
1467                psched[lpid].context[IDLE_TASK_INDEX][CTX_VSID_ID]  = 0;
1468                psched[lpid].context[IDLE_TASK_INDEX][CTX_RUN_ID]   = 1;
[321]1469            }  // end for processors
[258]1470
[321]1471            // scan HWIs connected to local XCU
1472            // for round-robin allocation to processors
1473            lpid = 0;
1474            for ( irq_id = xcu->irq_offset ;
1475                  irq_id < xcu->irq_offset + xcu->irqs ;
[295]1476                  irq_id++ )
[258]1477            {
[321]1478                unsigned int type    = irq[irq_id].srctype;
1479                unsigned int srcid   = irq[irq_id].srcid;
1480                unsigned int isr     = irq[irq_id].isr & 0xFFFF;
1481                unsigned int channel = irq[irq_id].channel << 16;
1482
1483                if ( (type != IRQ_TYPE_HWI) || (srcid > 31) )
[295]1484                {
[321]1485                    _puts("\n[BOOT ERROR] Bad IRQ in XCU of cluster[");
[295]1486                    _putd( x );
1487                    _puts(",");
1488                    _putd( y );
1489                    _puts("]\n");
1490                    _exit();
1491                }
[258]1492
[321]1493                psched[lpid].hwi_vector[srcid] = isr | channel | 0x80000000;
1494                lpid = (lpid + 1) % cluster[cluster_id].procs; 
[258]1495
[321]1496            } // end for irqs
1497        } // end if nprocs > 0
1498    } // end for clusters
[258]1499
[321]1500    // If there is an external PIC component, we scan HWIs connected to PIC
1501    // for Round Robin allocation (as WTI) to processors.
1502    // We allocate one WTI per processor, starting from proc[0,0,0],
1503    // and we increment (cluster_id, lpid) as required.
1504    if ( pic != NULL )
1505    {   
1506        unsigned int cluster_id = 0;   // index in clusters array
1507        unsigned int lpid       = 0;   // processor local index
1508
1509        // scan IRQS defined in PIC
1510        for ( irq_id = pic->irq_offset ;
1511              irq_id < pic->irq_offset + pic->irqs ;
1512              irq_id++ )
1513        {
1514            // compute next values for (cluster_id,lpid)
1515            // if no more procesor available in current cluster
1516            unsigned int overflow = 0;
1517            while ( (lpid >= cluster[cluster_id].procs) ||
1518                    (alloc_wti_channel[cluster_id] >= xcu->arg) )
1519            {
1520                overflow++;
1521                cluster_id = (cluster_id + 1) % (X_SIZE*Y_SIZE);
1522                lpid       = 0;
1523
1524                // overflow detection
1525                if ( overflow > (X_SIZE*Y_SIZE*NB_PROCS_MAX*32) )
1526                {
1527                    _puts("\n[BOOT ERROR] Not enough processors for external IRQs\n");
1528                    _exit();
1529                }
1530            }
1531
1532            unsigned int type    = irq[irq_id].srctype;
1533            unsigned int srcid   = irq[irq_id].srcid;
1534            unsigned int isr     = irq[irq_id].isr & 0xFFFF;
1535            unsigned int channel = irq[irq_id].channel << 16;
1536
1537            if ( (type != IRQ_TYPE_HWI) || (srcid > 31) )
1538            {
1539                _puts("\n[BOOT ERROR] Bad IRQ in PIC component\n");
1540                _exit();
1541            }
1542
1543            // get scheduler[cluster_id] address
1544            unsigned int x          = cluster[cluster_id].x;
1545            unsigned int y          = cluster[cluster_id].y;
1546            unsigned int cluster_xy = (x<<Y_WIDTH) + y;
[347]1547            psched                  = _schedulers[x][y][0];
[321]1548
1549            // update WTI vector for scheduler[cluster_id][lpid]
1550            unsigned int index = alloc_wti_channel[cluster_id];
1551            psched[lpid].wti_vector[index] = isr | channel | 0x80000000;
1552            alloc_wti_channel[cluster_id] = index + 1;
1553            lpid = lpid + 1;
1554
1555            // update IRQ fields in mapping for PIC initialisation
1556            irq[irq_id].dest_id = index;
1557            irq[irq_id].dest_xy = cluster_xy;
1558
1559        }  // end for IRQs
1560    } // end if PIC
1561               
[258]1562#if BOOT_DEBUG_SCHED
[321]1563for ( cluster_id = 0 ; cluster_id < (X_SIZE*Y_SIZE) ; cluster_id++ )
1564{
1565    unsigned int x          = cluster[cluster_id].x;
1566    unsigned int y          = cluster[cluster_id].y;
[347]1567    psched                  = _schedulers[x][y][0];
[321]1568    unsigned int slot;
1569    unsigned int entry;
1570    for ( lpid = 0 ; lpid < cluster[cluster_id].procs ; lpid++ )
1571    {
1572        _puts("\n*** IRQS for proc[");
1573        _putd( x );
1574        _puts(",");
1575        _putd( y );
[329]1576        _puts(",");
[321]1577        _putd( lpid );
1578        _puts("]\n");
1579        for ( slot = 0 ; slot < 32 ; slot++ )
1580        {
1581            entry = psched[lpid].hwi_vector[slot];
1582            if ( entry & 0x80000000 ) 
1583            {
1584                _puts(" - HWI ");
1585                _putd( slot );
1586                _puts(" / isrtype = ");
1587                _putd( entry & 0xFFFF ); 
1588                _puts(" / channel = ");
1589                _putd( (entry >> 16) & 0x7FFF ); 
1590                _puts("\n");
1591            }
1592        }
1593        for ( slot = 0 ; slot < 32 ; slot++ )
1594        {
1595            entry = psched[lpid].wti_vector[slot];
1596            if ( entry & 0x80000000 ) 
1597            {
1598                _puts(" - WTI ");
1599                _putd( slot );
1600                _puts(" / isrtype = ");
1601                _putd( entry & 0xFFFF ); 
1602                _puts(" / channel = ");
1603                _putd( (entry >> 16) & 0x7FFF ); 
1604                _puts("\n");
1605            }
1606        }
1607        for ( slot = 0 ; slot < 32 ; slot++ )
1608        {
1609            entry = psched[lpid].pti_vector[slot];
1610            if ( entry & 0x80000000 ) 
1611            {
1612                _puts(" - PTI ");
1613                _putd( slot );
1614                _puts(" / isrtype = ");
1615                _putd( entry & 0xFFFF ); 
1616                _puts(" / channel = ");
1617                _putd( (entry >> 16) & 0x7FFF ); 
1618                _puts("\n");
1619            }
1620        }
1621    }
1622}
[258]1623#endif
1624
1625    ///////////////////////////////////////////////////////////////////
[295]1626    // Step 2 : loop on the vspaces and the tasks  to complete
1627    //          the schedulers and task contexts initialisation.
[258]1628
1629    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
1630    {
1631        // We must set the PTPR depending on the vspace, because the start_vector
1632        // and the stack address are defined in virtual space.
[347]1633        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id][0][0] >> 13) );
[258]1634
1635        // loop on the tasks in vspace (task_id is the global index)
1636        for (task_id = vspace[vspace_id].task_offset;
1637             task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks);
1638             task_id++) 
1639        {
[295]1640            // compute the cluster coordinates & local processor index
[263]1641            unsigned int x          = cluster[task[task_id].clusterid].x;
1642            unsigned int y          = cluster[task[task_id].clusterid].y;
1643            unsigned int cluster_xy = (x<<Y_WIDTH) + y;
[295]1644            unsigned int lpid       = task[task_id].proclocid;                 
[263]1645
[258]1646#if BOOT_DEBUG_SCHED
1647_puts("\n[BOOT DEBUG] Initialise context for task ");
1648_puts( task[task_id].name );
1649_puts(" in vspace ");
1650_puts( vspace[vspace_id].name );
[309]1651_puts("\n");
[258]1652#endif
1653            // compute gpid (global processor index) and scheduler base address
[295]1654            unsigned int gpid = cluster_xy * NB_PROCS_MAX + lpid;
[347]1655            psched            = _schedulers[x][y][lpid];
[258]1656
1657            // ctx_sr : value required before an eret instruction
1658            unsigned int ctx_sr = 0x0000FF13;
1659
1660            // ctx_ptpr : page table physical base address (shifted by 13 bit)
[347]1661            unsigned int ctx_ptpr = (unsigned int)(_ptabs_paddr[vspace_id][x][y] >> 13);
[258]1662
1663            // ctx_ptab : page_table virtual base address
1664            unsigned int ctx_ptab = _ptabs_vaddr[vspace_id];
1665
1666            // ctx_tty : TTY terminal global index provided by the global allocator
[295]1667            //           Each user terminal is a private ressource: the number of
1668            //           requested terminal cannot be larger than NB_TTY_CHANNELS.             
[258]1669            unsigned int ctx_tty = 0xFFFFFFFF;
1670            if (task[task_id].use_tty) 
1671            {
1672                if (alloc_tty_channel >= NB_TTY_CHANNELS) 
1673                {
[295]1674                    _puts("\n[BOOT ERROR] TTY channel index too large for task ");
[258]1675                    _puts(task[task_id].name);
1676                    _puts(" in vspace ");
1677                    _puts(vspace[vspace_id].name);
1678                    _puts("\n");
1679                    _exit();
1680                }
1681                ctx_tty = alloc_tty_channel;
[295]1682                alloc_tty_channel++;
1683             }
1684
[258]1685            // ctx_nic : NIC channel global index provided by the global allocator
[295]1686            //           Each channel is a private ressource: the number of
1687            //           requested channels cannot be larger than NB_NIC_CHANNELS.
[258]1688            unsigned int ctx_nic = 0xFFFFFFFF;
1689            if (task[task_id].use_nic) 
1690            {
1691                if (alloc_nic_channel >= NB_NIC_CHANNELS) 
1692                {
1693                    _puts("\n[BOOT ERROR] NIC channel index too large for task ");
1694                    _puts(task[task_id].name);
1695                    _puts(" in vspace ");
1696                    _puts(vspace[vspace_id].name);
1697                    _puts("\n");
1698                    _exit();
1699                }
1700                ctx_nic = alloc_nic_channel;
1701                alloc_nic_channel++;
1702            }
[295]1703
[258]1704            // ctx_cma : CMA channel global index provided by the global allocator
[295]1705            //           Each channel is a private ressource: the number of
1706            //           requested channels cannot be larger than NB_NIC_CHANNELS.
[258]1707            unsigned int ctx_cma = 0xFFFFFFFF;
1708            if (task[task_id].use_cma) 
1709            {
1710                if (alloc_cma_channel >= NB_CMA_CHANNELS) 
1711                {
1712                    _puts("\n[BOOT ERROR] CMA channel index too large for task ");
1713                    _puts(task[task_id].name);
1714                    _puts(" in vspace ");
1715                    _puts(vspace[vspace_id].name);
1716                    _puts("\n");
1717                    _exit();
1718                }
1719                ctx_cma = alloc_cma_channel;
1720                alloc_cma_channel++;
1721            }
[295]1722
[258]1723            // ctx_hba : HBA channel global index provided by the global allocator
[295]1724            //           Each channel is a private ressource: the number of
1725            //           requested channels cannot be larger than NB_NIC_CHANNELS.
[258]1726            unsigned int ctx_hba = 0xFFFFFFFF;
1727            if (task[task_id].use_hba) 
1728            {
[295]1729                if (alloc_hba_channel >= NB_IOC_CHANNELS) 
[258]1730                {
1731                    _puts("\n[BOOT ERROR] IOC channel index too large for task ");
1732                    _puts(task[task_id].name);
1733                    _puts(" in vspace ");
1734                    _puts(vspace[vspace_id].name);
1735                    _puts("\n");
1736                    _exit();
1737                }
1738                ctx_hba = alloc_hba_channel;
1739                alloc_hba_channel++;
1740            }
[295]1741            // ctx_tim : TIMER local channel index provided by the cluster allocator
1742            //           Each timer is a private ressource
[258]1743            unsigned int ctx_tim = 0xFFFFFFFF;
1744            if (task[task_id].use_tim) 
1745            {
1746                unsigned int cluster_id = task[task_id].clusterid;
1747
1748                if ( alloc_tim_channel[cluster_id] >= NB_TIM_CHANNELS ) 
1749                {
1750                    _puts("\n[BOOT ERROR] local TIMER index too large for task ");
1751                    _puts(task[task_id].name);
1752                    _puts(" in vspace ");
1753                    _puts(vspace[vspace_id].name);
1754                    _puts("\n");
1755                    _exit();
1756                }
[295]1757                ctx_tim =  alloc_tim_channel[cluster_id];
1758                alloc_tim_channel[cluster_id]++;
[258]1759            }
1760            // ctx_epc : Get the virtual address of the memory location containing
1761            // the task entry point : the start_vector is stored by GCC in the seg_data
1762            // segment and we must wait the .elf loading to get the entry point value...
[321]1763            vobj_id = vspace[vspace_id].start_vobj_id;     
1764            unsigned int ctx_epc = vobj[vobj_id].vaddr + (task[task_id].startid)*4;
[258]1765
1766            // ctx_sp :  Get the vobj containing the stack
[321]1767            vobj_id = task[task_id].stack_vobj_id;
[258]1768            unsigned int ctx_sp = vobj[vobj_id].vaddr + vobj[vobj_id].length;
1769
1770            // get local task index in scheduler
1771            unsigned int ltid = psched->tasks;
1772
[267]1773            // get vspace thread index
1774            unsigned int thread_id = task[task_id].trdid;
1775
[258]1776            if (ltid >= IDLE_TASK_INDEX) 
1777            {
1778                _puts("\n[BOOT ERROR] in boot_schedulers_init() : ");
1779                _putd( ltid );
1780                _puts(" tasks allocated to processor ");
1781                _putd( gpid );
1782                _puts(" / max is ");
1783                _putd( IDLE_TASK_INDEX );
1784                _puts("\n");
1785                _exit();
1786            }
1787
1788            // update the "tasks" and "current" fields in scheduler:
1789            // the first task to execute is task 0 as soon as there is at least
1790            // one task allocated to processor.
1791            psched->tasks   = ltid + 1;
1792            psched->current = 0;
1793
1794            // initializes the task context in scheduler
[293]1795            psched->context[ltid][CTX_CR_ID]    = 0;
[258]1796            psched->context[ltid][CTX_SR_ID]    = ctx_sr;
1797            psched->context[ltid][CTX_SP_ID]    = ctx_sp;
1798            psched->context[ltid][CTX_EPC_ID]   = ctx_epc;
1799            psched->context[ltid][CTX_PTPR_ID]  = ctx_ptpr;
1800            psched->context[ltid][CTX_TTY_ID]   = ctx_tty;
1801            psched->context[ltid][CTX_CMA_ID]   = ctx_cma;
1802            psched->context[ltid][CTX_HBA_ID]   = ctx_hba;
1803            psched->context[ltid][CTX_NIC_ID]   = ctx_nic;
1804            psched->context[ltid][CTX_TIM_ID]   = ctx_tim;
1805            psched->context[ltid][CTX_PTAB_ID]  = ctx_ptab;
1806            psched->context[ltid][CTX_LTID_ID]  = ltid;
1807            psched->context[ltid][CTX_GTID_ID]  = task_id;
[267]1808            psched->context[ltid][CTX_TRDID_ID] = thread_id;
[258]1809            psched->context[ltid][CTX_VSID_ID]  = vspace_id;
1810            psched->context[ltid][CTX_RUN_ID]   = 1;
1811
1812#if BOOT_DEBUG_SCHED
1813_puts("\nTask ");
1814_putd( task_id );
[295]1815_puts(" allocated to processor[");
[309]1816_putd( x );
[295]1817_puts(",");
[309]1818_putd( y );
[295]1819_puts(",");
[309]1820_putd( lpid );
[295]1821_puts("]\n  - ctx[LTID]   = ");
[258]1822_putd( psched->context[ltid][CTX_LTID_ID] );
1823_puts("\n  - ctx[SR]     = ");
1824_putx( psched->context[ltid][CTX_SR_ID] );
1825_puts("\n  - ctx[SP]     = ");
1826_putx( psched->context[ltid][CTX_SP_ID] );
1827_puts("\n  - ctx[EPC]    = ");
1828_putx( psched->context[ltid][CTX_EPC_ID] );
1829_puts("\n  - ctx[PTPR]   = ");
1830_putx( psched->context[ltid][CTX_PTPR_ID] );
1831_puts("\n  - ctx[TTY]    = ");
[295]1832_putx( psched->context[ltid][CTX_TTY_ID] );
[258]1833_puts("\n  - ctx[NIC]    = ");
[295]1834_putx( psched->context[ltid][CTX_NIC_ID] );
[258]1835_puts("\n  - ctx[CMA]    = ");
[295]1836_putx( psched->context[ltid][CTX_CMA_ID] );
[258]1837_puts("\n  - ctx[IOC]    = ");
[295]1838_putx( psched->context[ltid][CTX_HBA_ID] );
[258]1839_puts("\n  - ctx[TIM]    = ");
[295]1840_putx( psched->context[ltid][CTX_TIM_ID] );
[258]1841_puts("\n  - ctx[PTAB]   = ");
1842_putx( psched->context[ltid][CTX_PTAB_ID] );
1843_puts("\n  - ctx[GTID]   = ");
[295]1844_putx( psched->context[ltid][CTX_GTID_ID] );
[258]1845_puts("\n  - ctx[VSID]   = ");
[295]1846_putx( psched->context[ltid][CTX_VSID_ID] );
[267]1847_puts("\n  - ctx[TRDID]  = ");
[295]1848_putx( psched->context[ltid][CTX_TRDID_ID] );
[258]1849_puts("\n");
1850#endif
1851
1852        } // end loop on tasks
1853    } // end loop on vspaces
1854} // end _schedulers_init()
1855
1856//////////////////////////////////////////////////////////////////////////////////
1857// This function loads the map.bin file from block device.
1858// The fat global varible is defined in fat32.c file.
1859//////////////////////////////////////////////////////////////////////////////////
1860void boot_mapping_init()
1861{
[347]1862    // desactivates IOC interrupt
[289]1863    _ioc_init( 0 );
[258]1864
[347]1865    // open file "map.bin"
[295]1866    int fd_id = _fat_open( IOC_BOOT_MODE,
[258]1867                           "map.bin",
1868                           0 );         // no creation
1869    if ( fd_id == -1 )
1870    {
1871        _puts("\n[BOOT ERROR] : map.bin file not found \n");
1872        _exit();
1873    }
1874
1875#if BOOT_DEBUG_MAPPING
1876_puts("\n[BOOT] map.bin file successfully open at cycle ");
1877_putd(_get_proctime());
1878_puts("\n");
1879#endif
1880
[347]1881    // get "map.bin" file size (from fat32) and check it
[258]1882    unsigned int size    = fat.fd[fd_id].file_size;
[347]1883
1884    if ( size > SEG_BOOT_MAPPING_SIZE )
1885    {
1886        _puts("\n[BOOT ERROR] : allocated segment too small for map.bin file\n");
1887        _exit();
1888    }
1889
1890    // load "map.bin" file into buffer
[258]1891    unsigned int nblocks = size >> 9;
1892    unsigned int offset  = size & 0x1FF;
1893    if ( offset ) nblocks++;
1894
[295]1895    unsigned int ok = _fat_read( IOC_BOOT_MODE,
[258]1896                                 fd_id, 
[321]1897                                 (unsigned int*)SEG_BOOT_MAPPING_BASE, 
[258]1898                                 nblocks,       
1899                                 0 );      // offset
1900    if ( ok == -1 )
1901    {
1902        _puts("\n[BOOT ERROR] : unable to load map.bin file \n");
1903        _exit();
1904    }
1905    _fat_close( fd_id );
1906   
[347]1907    // close file "map.bin"
[258]1908    boot_mapping_check();
[347]1909
[258]1910} // end boot_mapping_init()
1911
1912
[347]1913/////////////////////////////////////////////////////////////////////////////////////
1914// This function load all loadable segments for one .elf file, identified
1915// by the "pathname" argument. Some loadable segments can be copied in several
1916// clusters: same virtual address but different physical addresses. 
1917// - It open the file.
1918// - It loads the complete file in a dedicated buffer (seg_boot_buffer).
1919// - It copies each loadable segments  at the virtual address defined in the .elf
1920//   file, making several copies if the target vseg is not local.
1921// - It closes the file.
1922// Note:
1923// - This function is supposed to be executed by processor[0,0,0].
1924//   We must use physical addresses to reach the destination buffers that
1925//   can be located in remote clusters. We use either a _physical_memcpy(),
1926//   or a _dma_physical_copy() if DMA is available.
1927//   The source seg_boot_buffer must be identity mapping.
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    // get boot buffer address and size
[321]1941    char*             boot_buffer      = (char*)SEG_BOOT_BUFFER_BASE;
1942    unsigned int      boot_buffer_size = SEG_BOOT_BUFFER_SIZE;
[258]1943
1944#if BOOT_DEBUG_ELF
1945_puts("\n[BOOT DEBUG] Start searching file ");
1946_puts( pathname );
1947_puts(" at cycle ");
1948_putd( _get_proctime() );
1949_puts("\n");
1950#endif
1951
1952    // open .elf file
[347]1953    int fd_id = _fat_open( IOC_BOOT_MODE,
[258]1954                           pathname,
1955                           0 );      // no creation
1956    if ( fd_id < 0 )
1957    {
1958        _puts("\n[BOOT ERROR] load_one_elf_file() : ");
1959        _puts( pathname );
1960        _puts(" not found\n");
1961        _exit();
1962    }
1963
1964    // check boot_buffer size versus file size
1965    if ( fat.fd[fd_id].file_size > boot_buffer_size )
1966    {
1967        _puts("\n[BOOT ERROR] load_one_elf_file() : ");
1968        _puts( pathname );
1969        _puts(" exceeds the seg_boot_buffer size\n");
1970        _exit();
1971    }
1972
1973    // compute number of sectors
1974    unsigned int nbytes   = fat.fd[fd_id].file_size;
1975    unsigned int nsectors = nbytes>>9;
1976    if( nbytes & 0x1FF) nsectors++;
1977
1978    // load file in boot_buffer
[347]1979    if( _fat_read( IOC_BOOT_MODE, 
[258]1980                   fd_id, 
1981                   boot_buffer,
1982                   nsectors,
1983                   0 ) != nsectors )
1984    {
1985        _puts("\n[BOOT ERROR] load_one_elf_file() : unexpected EOF for file ");
1986        _puts( pathname );
1987        _puts("\n");   
1988        _exit();
1989    }
1990
1991    // Check ELF Magic Number in ELF header
1992    Elf32_Ehdr* elf_header_ptr = (Elf32_Ehdr*)boot_buffer;
1993
1994    if ( (elf_header_ptr->e_ident[EI_MAG0] != ELFMAG0) ||
1995         (elf_header_ptr->e_ident[EI_MAG1] != ELFMAG1) ||
1996         (elf_header_ptr->e_ident[EI_MAG2] != ELFMAG2) ||
1997         (elf_header_ptr->e_ident[EI_MAG3] != ELFMAG3) )
1998    {
1999        _puts("\n[BOOT ERROR] load_elf() : file ");
2000        _puts( pathname );
2001        _puts(" does not use ELF format\n");   
2002        _exit();
2003    }
2004
2005    // get program header table pointer
2006    unsigned int pht_index = elf_header_ptr->e_phoff;
2007    if( pht_index == 0 )
2008    {
2009        _puts("\n[BOOT ERROR] load_one_elf_file() : file ");
2010        _puts( pathname );
2011        _puts(" does not contain loadable segment\n");   
2012        _exit();
2013    }
2014    Elf32_Phdr* elf_pht_ptr = (Elf32_Phdr*)(boot_buffer + pht_index);
2015
2016    // get number of segments
2017    unsigned int nsegments   = elf_header_ptr->e_phnum;
2018
[347]2019    _puts("\n[BOOT] File ");
2020    _puts( pathname );
2021    _puts(" loaded at cycle ");
2022    _putd( _get_proctime() );
2023    _puts("\n");
[258]2024
[347]2025    // Loop on loadable segments in the .elf file
[258]2026    for (seg_id = 0 ; seg_id < nsegments ; seg_id++)
2027    {
2028        if(elf_pht_ptr[seg_id].p_type == PT_LOAD)
2029        {
2030            // Get segment attributes
2031            unsigned int seg_vaddr  = elf_pht_ptr[seg_id].p_vaddr;
2032            unsigned int seg_offset = elf_pht_ptr[seg_id].p_offset;
2033            unsigned int seg_filesz = elf_pht_ptr[seg_id].p_filesz;
2034            unsigned int seg_memsz  = elf_pht_ptr[seg_id].p_memsz;
2035
[347]2036#if BOOT_DEBUG_ELF
2037_puts(" - segment ");
2038_putd( seg_id );
2039_puts(" / vaddr = ");
2040_putx( seg_vaddr );
2041_puts(" / file_size = ");
2042_putx( seg_filesz );
2043_puts("\n");
2044#endif
2045
[258]2046            if( seg_memsz < seg_filesz )
2047            {
2048                _puts("\n[BOOT ERROR] load_one_elf_file() : segment at vaddr = ");
2049                _putx( seg_vaddr );
2050                _puts(" in file ");
2051                _puts( pathname );
[347]2052                _puts(" has a memsz < filesz \n");   
[258]2053                _exit();
2054            }
2055
2056            // fill empty space with 0 as required
2057            if( seg_memsz > seg_filesz )
2058            {
2059                unsigned int i; 
[289]2060                for( i = seg_filesz ; i < seg_memsz ; i++ ) boot_buffer[i+seg_offset] = 0;
[258]2061            } 
2062
2063            unsigned int src_vaddr = (unsigned int)boot_buffer + seg_offset;
2064
[347]2065            // search all vsegs matching the virtual address
2066            unsigned int vseg_first;
2067            unsigned int vseg_last;
2068            unsigned int vseg_id;
2069            unsigned int found = 0;
2070            if ( is_kernel )
2071            {
2072                vseg_first = 0;
2073                vseg_last  = header->globals;
2074            }
2075            else
2076            {
2077                vseg_first = vspace[vspace_id].vseg_offset;
2078                vseg_last  = vseg_first + vspace[vspace_id].vsegs;
2079            }
2080
2081            for ( vseg_id = vseg_first ; vseg_id < vseg_last ; vseg_id++ )
2082            {
2083                if ( seg_vaddr == vseg[vseg_id].vbase )  // matching
2084                {
2085                    found = 1;
2086
2087                    // get destination buffer physical address and size
2088                    paddr_t      seg_paddr  = vseg[vseg_id].pbase;
2089                    unsigned int vobj_id    = vseg[vseg_id].vobj_offset;
2090                    unsigned int seg_size   = vobj[vobj_id].length;
2091                   
[258]2092#if BOOT_DEBUG_ELF
[347]2093_puts("   loaded into vseg ");
2094_puts( vseg[vseg_id].name );
2095_puts(" at paddr = ");
2096_putl( seg_paddr );
2097_puts(" (buffer size = ");
2098_putx( seg_size );
2099_puts(")\n");
[258]2100#endif
[347]2101                    // check vseg size
2102                    if ( seg_size < seg_filesz )
2103                    {
2104                        _puts("\n[BOOT ERROR] in load_one_elf_file()\n");
2105                        _puts("vseg ");
2106                        _puts( vseg[vseg_id].name );
2107                        _puts(" is to small for loadable segment ");
2108                        _putx( seg_vaddr );
2109                        _puts(" in file ");
2110                        _puts( pathname );
2111                        _puts(" \n");   
2112                        _exit();
2113                    }
[258]2114
[347]2115                    // copy the segment from boot buffer to destination buffer
2116                    // using DMA channel[0,0,0] if it is available.
2117                    if( NB_DMA_CHANNELS > 0 )
2118                    {
2119                        _dma_physical_copy( 0,                  // DMA in cluster[0,0]
2120                                            0,                  // DMA channel 0
2121                                            (paddr_t)seg_paddr, // destination paddr
2122                                            (paddr_t)src_vaddr, // source paddr
2123                                            seg_filesz );       // size
2124                    }
2125                    else
2126                    {
2127                        _physical_memcpy( (paddr_t)seg_paddr,   // destination paddr
2128                                          (paddr_t)src_vaddr,   // source paddr
2129                                          seg_filesz );         // size
2130                    }
2131                }
2132            }  // end for vsegs in vspace
2133
2134            // check at least one matching vseg
2135            if ( found == 0 )
[258]2136            {
[347]2137                _puts("\n[BOOT ERROR] in load_one_elf_file()\n");
2138                _puts("vseg for loadable segment ");
2139                _putx( seg_vaddr );
2140                _puts(" in file ");
2141                _puts( pathname );
2142                _puts(" not found \n");   
2143                _exit();
[258]2144            }
2145        }
[347]2146    }  // end for loadable segments
[258]2147
2148    // close .elf file
2149    _fat_close( fd_id );
2150
2151} // end load_one_elf_file()
2152
2153
[347]2154/////i////////////////////////////////////////////////////////////////////////////////
[258]2155// This function uses the map.bin data structure to load the "kernel.elf" file
[347]2156// as well as the various "application.elf" files into memory.
2157// - The "preloader.elf" file is not loaded, because it has been burned in the ROM.
2158// - The "boot.elf" file is not loaded, because it has been loaded by the preloader.
[295]2159// This function scans all vobjs defined in the map.bin data structure to collect
[347]2160// all .elf files pathnames, and calls the load_one_elf_file() for each .elf file.
2161// As the code can be replicated in several vsegs, the same code can be copied
2162// in one or several clusters by the load_one_elf_file() function.
2163//////////////////////////////////////////////////////////////////////////////////////
[258]2164void boot_elf_load()
2165{
[321]2166    mapping_header_t* header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[258]2167    mapping_vspace_t* vspace = _get_vspace_base( header );
2168    mapping_vobj_t*   vobj   = _get_vobj_base( header );
2169    unsigned int      vspace_id;
2170    unsigned int      vobj_id;
2171    unsigned int      found;
2172
2173    // Scan all vobjs corresponding to global vsegs,
2174    // to find the pathname to the kernel.elf file
2175    found = 0;
2176    for( vobj_id = 0 ; vobj_id < header->globals ; vobj_id++ )
2177    {
2178        if(vobj[vobj_id].type == VOBJ_TYPE_ELF) 
2179        {   
2180            found = 1;
2181            break;
2182        }
2183    }
2184
2185    // We need one kernel.elf file
2186    if (found == 0)
2187    {
2188        _puts("[BOOT ERROR] boot_elf_load() : kernel.elf file not found\n");
2189        _exit();
2190    }
2191
[347]2192    // Load the kernel
2193    load_one_elf_file( 1,                           // kernel file
2194                       vobj[vobj_id].binpath,       // file pathname
[258]2195                       0 );                         // vspace 0
2196
[347]2197    // loop on the vspaces, scanning all vobjs in the vspace,
[258]2198    // to find the pathname of the .elf file associated to the vspace.
2199    for( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
2200    {
2201        // loop on the vobjs in vspace (vobj_id is the global index)
2202        unsigned int found = 0;
2203        for (vobj_id = vspace[vspace_id].vobj_offset;
2204             vobj_id < (vspace[vspace_id].vobj_offset + vspace[vspace_id].vobjs);
2205             vobj_id++) 
2206        {
2207            if(vobj[vobj_id].type == VOBJ_TYPE_ELF) 
2208            {   
2209                found = 1;
2210                break;
2211            }
2212        }
2213
2214        // We want one .elf file per vspace
2215        if (found == 0)
2216        {
2217            _puts("[BOOT ERROR] boot_elf_load() : .elf file not found for vspace ");
2218            _puts( vspace[vspace_id].name );
2219            _puts("\n");
2220            _exit();
2221        }
2222
[347]2223        load_one_elf_file( 0,                          // not a kernel file
2224                           vobj[vobj_id].binpath,      // file pathname
2225                           vspace_id );                // vspace index
[258]2226
2227    }  // end for vspaces
2228
2229} // end boot_elf_load()
2230
2231////////////////////////////////////////////////////////////////////////////////
2232// This function intializes the periherals and coprocessors, as specified
2233// in the mapping_info file.
2234////////////////////////////////////////////////////////////////////////////////
2235void boot_peripherals_init() 
2236{
[321]2237    mapping_header_t * header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[258]2238    mapping_cluster_t * cluster = _get_cluster_base(header);
2239    mapping_periph_t * periph   = _get_periph_base(header);
2240    mapping_vobj_t * vobj       = _get_vobj_base(header);
2241    mapping_coproc_t * coproc   = _get_coproc_base(header);
2242    mapping_cp_port_t * cp_port = _get_cp_port_base(header);
[295]2243    mapping_irq_t * irq         = _get_irq_base(header);
[258]2244
2245    unsigned int cluster_id;
2246    unsigned int periph_id;
2247    unsigned int coproc_id;
2248    unsigned int cp_port_id;
2249    unsigned int channel_id;
2250
[263]2251    // loop on all physical clusters
2252    for (cluster_id = 0; cluster_id < X_SIZE*Y_SIZE; cluster_id++) 
[258]2253    {
[263]2254        // computes cluster coordinates
2255        unsigned int x          = cluster[cluster_id].x;
2256        unsigned int y          = cluster[cluster_id].y;
2257        unsigned int cluster_xy = (x<<Y_WIDTH) + y;
[258]2258
2259#if BOOT_DEBUG_PERI
[329]2260_puts("\n[BOOT DEBUG] Peripherals initialisation in cluster[");
[263]2261_putd( x );
2262_puts(",");
2263_putd( y );
[329]2264_puts("]\n");
[258]2265#endif
2266
[263]2267        // loop on peripherals
[258]2268        for (periph_id = cluster[cluster_id].periph_offset;
2269             periph_id < cluster[cluster_id].periph_offset +
2270             cluster[cluster_id].periphs; periph_id++) 
2271        {
2272            unsigned int type       = periph[periph_id].type;
[347]2273            unsigned int subtype    = periph[periph_id].subtype;
[258]2274            unsigned int channels   = periph[periph_id].channels;
2275
2276            switch (type) 
2277            {
2278                case PERIPH_TYPE_IOC:    // vci_block_device component
2279                {
[347]2280                    if ( subtype == PERIPH_SUBTYPE_BDV )
[289]2281                    {
[347]2282                        _bdv_lock.value = 0;
[258]2283#if BOOT_DEBUG_PERI
[347]2284_puts("- BDV : channels = ");
[263]2285_putd(channels);
2286_puts("\n");
[258]2287#endif
[347]2288                    }
2289                    else if ( subtype == PERIPH_SUBTYPE_HBA )
2290                    {
2291                        // TODO
2292                    }
2293                    else if ( subtype == PERIPH_SUBTYPE_SPI )
2294                    {
2295                        // TODO
2296                    }
[258]2297                    break;
2298                }
[263]2299                case PERIPH_TYPE_CMA:    // vci_chbuf_dma component
2300                {
2301                    for (channel_id = 0; channel_id < channels; channel_id++) 
2302                    {
2303                        // TODO
2304                    }
2305#if BOOT_DEBUG_PERI
[309]2306_puts("- CMA : channels = ");
[263]2307_putd(channels);
2308_puts("\n");
2309#endif
2310                    break;
2311                }
[258]2312                case PERIPH_TYPE_NIC:    // vci_multi_nic component
2313                {
2314                    for (channel_id = 0; channel_id < channels; channel_id++) 
2315                    {
2316                        // TODO
2317                    }
2318#if BOOT_DEBUG_PERI
[309]2319_puts("- NIC : channels = ");
[263]2320_putd(channels);
2321_puts("\n");
[258]2322#endif
2323                    break;
2324                }
[299]2325                case PERIPH_TYPE_TTY:    // vci_multi_tty component
[263]2326                {
[347]2327                    for (channel_id = 0; channel_id < channels; channel_id++) 
2328                    {
2329                        _tty_lock[channel_id].value = 0;
2330                        _tty_rx_full[channel_id]    = 0;
2331                    }
[263]2332#if BOOT_DEBUG_PERI
[309]2333_puts("- TTY : channels = ");
[263]2334_putd(channels);
2335_puts("\n");
2336#endif
2337                    break;
2338                }
[299]2339                case PERIPH_TYPE_IOB:    // vci_io_bridge component
[258]2340                {
[299]2341                    if (GIET_USE_IOMMU) 
[258]2342                    {
2343                        // TODO
2344                        // get the iommu page table physical address
2345                        // set IOMMU page table address
2346                        // pseg_base[IOB_IOMMU_PTPR] = ptab_pbase;   
2347                        // activate IOMMU
2348                        // pseg_base[IOB_IOMMU_ACTIVE] = 1;       
2349                    }
2350                    break;
2351                }
[295]2352                case PERIPH_TYPE_PIC:    // vci_iopic component
2353                {
2354#if BOOT_DEBUG_PERI
[309]2355_puts("- PIC : channels = ");
[295]2356_putd(channels);
2357_puts("\n");
2358#endif
[309]2359                    // scan all IRQs defined in mapping for PIC component,
[295]2360                    // and initialises addresses for WTI IRQs
2361                    for ( channel_id = periph[periph_id].irq_offset ;
2362                          channel_id < periph[periph_id].irq_offset + periph[periph_id].irqs ;
2363                          channel_id++ )
2364                    {
[321]2365                        unsigned int hwi_id     = irq[channel_id].srcid;   // HWI index in PIC
2366                        unsigned int wti_id     = irq[channel_id].dest_id; // WTI index in XCU
2367                        unsigned int cluster_xy = irq[channel_id].dest_xy; // XCU coordinates
[295]2368                        unsigned int vaddr;
2369
2370                        _xcu_get_wti_address( wti_id, &vaddr );
2371
[309]2372                        _pic_init( hwi_id, vaddr, cluster_xy ); 
[295]2373#if BOOT_DEBUG_PERI
2374_puts("    hwi_index = ");
2375_putd( hwi_id );
2376_puts(" / wti_index = ");
2377_putd( wti_id );
2378_puts(" / vaddr = ");
2379_putx( vaddr );
2380_puts(" in cluster[");
[321]2381_putd( cluster_xy >> Y_WIDTH );
[295]2382_puts(",");
[321]2383_putd( cluster_xy & ((1<<Y_WIDTH)-1) );
[295]2384_puts("]\n");
2385#endif
2386                    }
2387                    break;
2388                }
[258]2389            }  // end switch periph type
2390        }  // end for periphs
2391
2392#if BOOT_DEBUG_PERI
[329]2393_puts("\n[BOOT DEBUG] Coprocessors initialisation in cluster[");
[263]2394_putd( x );
2395_puts(",");
2396_putd( y );
[329]2397_puts("]\n");
[258]2398#endif
2399
[263]2400        // loop on coprocessors
[258]2401        for ( coproc_id = cluster[cluster_id].coproc_offset;
2402              coproc_id < cluster[cluster_id].coproc_offset +
2403              cluster[cluster_id].coprocs; coproc_id++ ) 
2404        {
2405
2406#if BOOT_DEBUG_PERI
2407_puts("- coprocessor name : ");
2408_puts(coproc[coproc_id].name);
2409_puts(" / nb ports = ");
2410_putd((unsigned int) coproc[coproc_id].ports);
2411_puts("\n");
2412#endif
2413            // loop on the coprocessor ports
2414            for ( cp_port_id = coproc[coproc_id].port_offset;
2415                  cp_port_id < coproc[coproc_id].port_offset + coproc[coproc_id].ports;
2416                  cp_port_id++ ) 
2417            {
[321]2418                // Get global index of associted vobj
2419                unsigned int vobj_id   = cp_port[cp_port_id].mwmr_vobj_id; 
[258]2420
2421                // Get MWMR channel base address
2422                paddr_t mwmr_channel_pbase = vobj[vobj_id].paddr;
2423
[263]2424                _mwr_hw_init( cluster_xy,
2425                              cp_port_id, 
2426                              cp_port[cp_port_id].direction, 
2427                              mwmr_channel_pbase );
[258]2428#if BOOT_DEBUG_PERI
2429_puts("     port direction: ");
2430_putd( (unsigned int)cp_port[cp_port_id].direction );
2431_puts(" / mwmr_channel_pbase = ");
2432_putl( mwmr_channel_pbase );
2433_puts(" / name = ");
2434_puts(vobj[vobj_id].name);
2435_puts("\n"); 
2436#endif
2437            } // end for cp_ports
2438        } // end for coprocs
2439    } // end for clusters
2440} // end boot_peripherals_init()
2441
2442/////////////////////////////////////////////////////////////////////////
2443// This function is the entry point of the boot code for all processors.
2444// Most of this code is executed by Processor 0 only.
2445/////////////////////////////////////////////////////////////////////////
[347]2446void boot_init() 
[258]2447{
[321]2448    mapping_header_t*  header     = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[295]2449    mapping_cluster_t* cluster    = _get_cluster_base(header);
2450    unsigned int       gpid       = _get_procid();
[258]2451 
[263]2452    if ( gpid == 0 )    // only Processor 0 does it
[258]2453    {
2454        _puts("\n[BOOT] boot_init start at cycle ");
2455        _putd(_get_proctime());
2456        _puts("\n");
2457
[347]2458        // Load the map.bin file into memory and check it
[258]2459        boot_mapping_init();
2460
[295]2461        _puts("\n[BOOT] Mapping \"");
[258]2462        _puts( header->name );
[295]2463        _puts("\" loaded at cycle ");
[258]2464        _putd(_get_proctime());
2465        _puts("\n");
2466
[347]2467        // Build page tables
[258]2468        boot_pt_init();
2469
[347]2470        // Activate MMU for proc [0,0,0]
2471        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0][0][0]>>13) );
[258]2472        _set_mmu_mode( 0xF );
2473
[263]2474        _puts("\n[BOOT] Processor[0,0,0] : MMU activation at cycle ");
[258]2475        _putd(_get_proctime());
2476        _puts("\n");
2477
[347]2478        // Initialise private vobjs in vspaces
[258]2479        boot_vobjs_init();
2480
2481        _puts("\n[BOOT] Private vobjs initialised at cycle ");
2482        _putd(_get_proctime());
2483        _puts("\n");
2484
[347]2485        // Initialise schedulers
[258]2486        boot_schedulers_init();
2487
[295]2488        _puts("\n[BOOT] Schedulers initialised at cycle ");
[258]2489        _putd(_get_proctime());
2490        _puts("\n");
2491       
[347]2492        // Set CP0_SCHED register for proc [0,0,0]
2493        _set_sched( (unsigned int)_schedulers[0][0][0] );
[258]2494
[347]2495        // Initialise non replicated peripherals
[258]2496        boot_peripherals_init();
2497
[295]2498        _puts("\n[BOOT] Non replicated peripherals initialised at cycle ");
[258]2499        _putd(_get_proctime());
2500        _puts("\n");
2501
2502        // Loading all .elf files
2503        boot_elf_load();
2504
[295]2505        // P0 starts all other processors
2506        unsigned int clusterid, p;
[258]2507
[295]2508        for ( clusterid = 0 ; clusterid < X_SIZE*Y_SIZE ; clusterid++ ) 
[258]2509        {
[295]2510            unsigned int nprocs     = cluster[clusterid].procs;
[347]2511            unsigned int x          = cluster[clusterid].x;
2512            unsigned int y          = cluster[clusterid].y;
2513            unsigned int cluster_xy = (x<<Y_WIDTH) + y;
[295]2514
2515            for ( p = 0 ; p < nprocs; p++ ) 
[258]2516            {
[295]2517                if ( (nprocs > 0) && ((clusterid != 0) || (p != 0)) )
[258]2518                {
[295]2519                    _xcu_send_wti( cluster_xy, p, (unsigned int)boot_init );
[258]2520                }
2521            }
2522        }
[295]2523 
[258]2524    }  // end monoprocessor boot
2525
[262]2526    // reset BEV bit in the status register to use GIET exception
2527    // handler instead of the PRELOADER exception handler
2528    _set_sr( 0 );
2529
[258]2530    // all processor initialise SCHED register
[347]2531    unsigned int cluster_xy = gpid / NB_PROCS_MAX;
2532    unsigned int lpid       = gpid % NB_PROCS_MAX;
2533    unsigned int x          = cluster_xy >> Y_WIDTH;
2534    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
2535    _set_sched( (unsigned int)_schedulers[x][y][lpid] );
[258]2536
[347]2537    // all processors (but Proc[0,0,0]) activate MMU
[263]2538    if ( gpid != 0 )
[258]2539    {
[347]2540        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0][x][y]>>13) );
[258]2541        _set_mmu_mode( 0xF );
2542    }
2543
[321]2544    // all processors jump to kernel_init (address defined in giet_vsegs.ld)
2545    unsigned int kernel_entry = (unsigned int)&kernel_init_vbase;
[258]2546    asm volatile( "jr   %0" ::"r"(kernel_entry) );
2547
2548} // end boot_init()
2549
2550
2551// Local Variables:
2552// tab-width: 4
2553// c-basic-offset: 4
2554// c-file-offsets:((innamespace . 0)(inline-open . 0))
2555// indent-tabs-mode: nil
2556// End:
2557// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
2558
Note: See TracBrowser for help on using the repository browser.