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

Last change on this file since 526 was 524, checked in by alain, 10 years ago

The boot.c file has been modified to comply with the removal
of the coproc and cp_ports objects in the mapping.

File size: 78.8 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////////
2// File     : boot.c
3// Date     : 01/11/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////////
7// The boot.c file contains the bootloader for the GIET-VM static OS. 
8//
9// This code has been written for the MIPS32 processor.
10// The virtual adresses are on 32 bits and use the (unsigned int) type. The
11// physicals addresses can have up to 40 bits, and use the  (unsigned long long) type.
12// It natively supports clusterised shared memory multi-processors architectures,
13// where each processor is identified by a composite index [x,y,p],
14// and where there is one physical memory bank per cluster.
15//
16// The boot.elf file is stored on disk and is loaded into memory by proc[0,0,0],
17// executing the generic preloader (stored in ROM). The boot-loader code itself
18// is executed in parallel by all proc[x,y,0], and performs the following tasks:
19// - load into memory various binary files, from a FAT32 file system.
20// - build the various page tables (one page table per vspace).
21// - initialize the shedulers (one scheduler per processor).
22// - initialize the external peripherals.
23//
24// 1) The binary files to be loaded are:
25//    - the "map.bin" file contains the hardware architecture description and the
26//      mapping directives. It must be stored in the the seg_boot_mapping segment
27//      (at address SEG_BOOT_MAPPING_BASE defined in hard_config.h file).
28//    - the "kernel.elf" file contains the kernel binary code and data.
29//    - the various "application.elf" files.
30//
31// 2) The "map.bin" file contains the C binary structure defining:
32//    - the hardware architecture: number of clusters, number or processors,
33//      size of the memory segments, and peripherals in each cluster.
34//    - The structure of the various multi-threaded software applications:
35//      number of tasks, communication channels.
36//    - The mapping: placement of virtual segments (vseg) in the physical
37//      segments (pseg), placement of software tasks on the processors,
38//
39// 3) The GIET-VM uses the paged virtual memory to provides two services:
40//    - classical memory protection, when several independant applications compiled
41//      in different virtual spaces are executing on the same hardware platform.
42//    - data placement in NUMA architectures, to control the placement
43//      of the software objects (vsegs) on the physical memory banks (psegs).
44//
45//    The max number of vspaces (GIET_NB_VSPACE_MAX) is a configuration parameter,
46//    and - for each application - the tasks are statically allocateded on procesors.
47//    The page table are statically build in the boot phase, and they do not
48//    change during execution.
49//    The GIET_VM uses both small pages (4 Kbytes), and big pages (2 Mbytes).
50//
51//    Each page table (one page table per virtual space) is monolithic, and contains
52//    one PT1 (8 Kbytes) and a variable number of PT2s (4 Kbytes each). For each vspace,
53//    the number of PT2s is defined by the size of the PTAB vseg in the mapping.
54//    The PT1 is indexed by the ix1 field (11 bits) of the VPN. Each entry is 32 bits.
55//    A PT2 is indexed the ix2 field (9 bits) of the VPN. Each entry is a double word.
56//    The first word contains the flags, the second word contains the PPN.
57//    The page tables are distributed/replicated in all clusters.
58///////////////////////////////////////////////////////////////////////////////////////
59// Implementation Notes:
60//
61// 1) The cluster_id variable is a linear index in the mapping_info array of clusters.
62//    The cluster_xy variable is the tological index = x << Y_WIDTH + y
63//
64// 2) We set the _tty0_boot_mode variable to force the _printf() function to use
65//    the tty0_spin_lock for exclusive access to TTY0.
66///////////////////////////////////////////////////////////////////////////////////////
67
68#include <giet_config.h>
69#include <hard_config.h>
70#include <mapping_info.h>
71#include <kernel_malloc.h>
72#include <memspace.h>
73#include <tty_driver.h>
74#include <xcu_driver.h>
75#include <bdv_driver.h>
76#include <hba_driver.h>
77#include <dma_driver.h>
78#include <cma_driver.h>
79#include <nic_driver.h>
80#include <ioc_driver.h>
81#include <iob_driver.h>
82#include <pic_driver.h>
83#include <mwr_driver.h>
84#include <ctx_handler.h>
85#include <irq_handler.h>
86#include <vmem.h>
87#include <pmem.h>
88#include <utils.h>
89#include <tty0.h>
90#include <kernel_locks.h>
91#include <kernel_barriers.h>
92#include <elf-types.h>
93#include <fat32.h>
94#include <mips32_registers.h>
95#include <stdarg.h>
96
97#if !defined(X_SIZE)
98# error: The X_SIZE value must be defined in the 'hard_config.h' file !
99#endif
100
101#if !defined(Y_SIZE)
102# error: The Y_SIZE value must be defined in the 'hard_config.h' file !
103#endif
104
105#if !defined(X_WIDTH)
106# error: The X_WIDTH value must be defined in the 'hard_config.h' file !
107#endif
108
109#if !defined(Y_WIDTH)
110# error: The Y_WIDTH value must be defined in the 'hard_config.h' file !
111#endif
112
113#if !defined(SEG_BOOT_MAPPING_BASE)
114# error: The SEG_BOOT_MAPPING_BASE value must be defined in the hard_config.h file !
115#endif
116
117#if !defined(NB_PROCS_MAX)
118# error: The NB_PROCS_MAX value must be defined in the 'hard_config.h' file !
119#endif
120
121#if !defined(GIET_NB_VSPACE_MAX)
122# error: The GIET_NB_VSPACE_MAX value must be defined in the 'giet_config.h' file !
123#endif
124
125#if !defined(GIET_ELF_BUFFER_SIZE)
126# error: The GIET_ELF_BUFFER_SIZE value must be defined in the giet_config.h file !
127#endif
128
129////////////////////////////////////////////////////////////////////////////
130//      Global variables for boot code
131////////////////////////////////////////////////////////////////////////////
132
133extern void boot_entry();
134
135// FAT internal representation for boot code 
136__attribute__((section(".kdata")))
137fat32_fs_t          fat   __attribute__((aligned(512)));
138
139// Temporaty buffer used to load one complete .elf file 
140__attribute__((section(".kdata")))
141char                boot_elf_buffer[GIET_ELF_BUFFER_SIZE] __attribute__((aligned(512)));
142
143// Physical memory allocators array (one per cluster)
144__attribute__((section(".kdata")))
145pmem_alloc_t        boot_pmem_alloc[X_SIZE][Y_SIZE];
146
147// Distributed kernel heap (one per cluster)
148// __attribute__((section(".kdata")))
149// kernel_heap_t       kernel_heap[X_SIZE][Y_SIZE];
150
151// Schedulers virtual base addresses array (one per processor)
152__attribute__((section(".kdata")))
153static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX];
154
155// Page tables virtual base addresses array (one per vspace)
156__attribute__((section(".kdata")))
157unsigned int        _ptabs_vaddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
158
159// Page tables physical base addresses (one per vspace and per cluster)
160__attribute__((section(".kdata")))
161paddr_t             _ptabs_paddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
162
163// Page tables pt2 allocators (one per vspace and per cluster)
164__attribute__((section(".kdata")))
165unsigned int        _ptabs_next_pt2[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
166
167// Page tables max_pt2  (same value for all page tables)
168__attribute__((section(".kdata")))
169unsigned int        _ptabs_max_pt2;
170
171// WTI channel allocator (one per cluster)
172__attribute__((section(".kdata")))
173unsigned int        _wti_channel_alloc[X_SIZE][Y_SIZE];
174
175// boot code uses a spin lock to protect TTY0
176__attribute__((section(".kdata")))
177unsigned int        _tty0_boot_mode = 1;
178
179__attribute__((section(".kdata")))
180spin_lock_t         _ptabs_spin_lock[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
181
182// barrier used by boot code for parallel execution
183__attribute__((section(".kdata")))
184simple_barrier_t    _barrier_all_clusters;
185
186// this variable is defined in the tty0.c file
187extern spin_lock_t  _tty0_spin_lock;
188
189//////////////////////////////////////////////////////////////////////////////
190// This function registers a new PTE1 in the page table defined
191// by the vspace_id argument, and the (x,y) coordinates.
192// It updates only the first level PT1.
193// As each vseg is mapped by a different processor, the PT1 entry cannot
194// be concurrently accessed, and we don't need to take any lock.
195//////////////////////////////////////////////////////////////////////////////
196void boot_add_pte1( unsigned int vspace_id,
197                    unsigned int x,
198                    unsigned int y,
199                    unsigned int vpn,        // 20 bits right-justified
200                    unsigned int flags,      // 10 bits left-justified
201                    unsigned int ppn )       // 28 bits right-justified
202{
203    // compute index in PT1
204    unsigned int    ix1 = vpn >> 9;         // 11 bits for ix1
205
206    // get page table physical base address
207    paddr_t  pt1_pbase = _ptabs_paddr[vspace_id][x][y];
208
209    if ( pt1_pbase == 0 )
210    {
211        _printf("\n[BOOT ERROR] in boot_add_pte1() : no PTAB in cluster[%d,%d]"
212                    " containing processors\n", x , y );
213        _exit();
214    }
215
216    // compute pte1 : 2 bits V T / 8 bits flags / 3 bits RSVD / 19 bits bppi
217    unsigned int    pte1 = PTE_V |
218                           (flags & 0x3FC00000) |
219                           ((ppn>>9) & 0x0007FFFF);
220
221    // write pte1 in PT1
222    _physical_write( pt1_pbase + 4*ix1, pte1 );
223
224    asm volatile ("sync");
225
226}   // end boot_add_pte1()
227
228//////////////////////////////////////////////////////////////////////////////
229// This function registers a new PTE2 in the page table defined
230// by the vspace_id argument, and the (x,y) coordinates.
231// It updates both the first level PT1 and the second level PT2.
232// As the set of PT2s is implemented as a fixed size array (no dynamic
233// allocation), this function checks a possible overflow of the PT2 array.
234// As a given entry in PT1 can be shared by several vsegs, mapped by
235// different processors, we need to take the lock protecting PTAB[v][x]y].
236//////////////////////////////////////////////////////////////////////////////
237void boot_add_pte2( unsigned int vspace_id,
238                    unsigned int x,
239                    unsigned int y,
240                    unsigned int vpn,        // 20 bits right-justified
241                    unsigned int flags,      // 10 bits left-justified
242                    unsigned int ppn )       // 28 bits right-justified
243{
244    unsigned int ix1;
245    unsigned int ix2;
246    paddr_t      pt2_pbase;     // PT2 physical base address
247    paddr_t      pte2_paddr;    // PTE2 physical address
248    unsigned int pt2_id;        // PT2 index
249    unsigned int ptd;           // PTD : entry in PT1
250
251    ix1 = vpn >> 9;             // 11 bits for ix1
252    ix2 = vpn & 0x1FF;          //  9 bits for ix2
253
254    // get page table physical base address
255    paddr_t      pt1_pbase = _ptabs_paddr[vspace_id][x][y];
256
257    if ( pt1_pbase == 0 )
258    {
259        _printf("\n[BOOT ERROR] in boot_add_pte2() : no PTAB for vspace %d "
260                "in cluster[%d,%d]\n", vspace_id , x , y );
261        _exit();
262    }
263
264    // get lock protecting PTAB[vspace_id][x][y]
265    _spin_lock_acquire( &_ptabs_spin_lock[vspace_id][x][y] );
266
267    // get ptd in PT1
268    ptd = _physical_read( pt1_pbase + 4 * ix1 );
269
270    if ((ptd & PTE_V) == 0)    // undefined PTD: compute PT2 base address,
271                               // and set a new PTD in PT1
272    {
273        // get a new pt2_id
274        pt2_id = _ptabs_next_pt2[vspace_id][x][y];
275        _ptabs_next_pt2[vspace_id][x][y] = pt2_id + 1;
276
277        // check overflow
278        if (pt2_id == _ptabs_max_pt2) 
279        {
280            _printf("\n[BOOT ERROR] in boot_add_pte2() : PTAB[%d,%d,%d]"
281                    " contains not enough PT2s\n", vspace_id, x, y );
282            _exit();
283        }
284
285        pt2_pbase = pt1_pbase + PT1_SIZE + PT2_SIZE * pt2_id;
286        ptd = PTE_V | PTE_T | (unsigned int) (pt2_pbase >> 12);
287
288        // set PTD into PT1
289        _physical_write( pt1_pbase + 4*ix1, ptd);
290    }
291    else                       // valid PTD: compute PT2 base address
292    {
293        pt2_pbase = ((paddr_t)(ptd & 0x0FFFFFFF)) << 12;
294    }
295
296    // set PTE in PT2 : flags & PPN in two 32 bits words
297    pte2_paddr  = pt2_pbase + 8 * ix2;
298    _physical_write(pte2_paddr     , (PTE_V | flags) );
299    _physical_write(pte2_paddr + 4 , ppn );
300
301    // release lock protecting PTAB[vspace_id][x][y]
302    _spin_lock_release( &_ptabs_spin_lock[vspace_id][x][y] );
303
304    asm volatile ("sync");
305
306}   // end boot_add_pte2()
307
308////////////////////////////////////////////////////////////////////////////////////
309// Align the value of paddr or vaddr to the required alignement,
310// defined by alignPow2 == L2(alignement).
311////////////////////////////////////////////////////////////////////////////////////
312paddr_t paddr_align_to( paddr_t paddr, unsigned int alignPow2 ) 
313{
314    paddr_t mask = (1 << alignPow2) - 1;
315    return ((paddr + mask) & ~mask);
316}
317
318unsigned int vaddr_align_to( unsigned int vaddr, unsigned int alignPow2 ) 
319{
320    unsigned int mask = (1 << alignPow2) - 1;
321    return ((vaddr + mask) & ~mask);
322}
323
324/////////////////////////////////////////////////////////////////////////////////////
325// This function map a vseg identified by the vseg pointer.
326//
327// A given vseg can be mapped in a Big Physical Pages (BPP: 2 Mbytes) or in a
328// Small Physical Pages (SPP: 4 Kbytes), depending on the "big" attribute of vseg,
329// with the following rules:
330// - SPP : There is only one vseg in a small physical page, but a single vseg
331//   can cover several contiguous small physical pages.
332// - BPP : It can exist several vsegs in a single big physical page, and a single
333//   vseg can cover several contiguous big physical pages.
334//
335// 1) First step: it computes various vseg attributes and checks
336//    alignment constraints.
337//
338// 2) Second step: it allocates the required number of contiguous physical pages,
339//    computes the physical base address (if the vseg is not identity mapping),
340//    and register it in the vseg pbase field.
341//    Only the vsegs used by the boot code and the peripheral vsegs
342//    can be identity mapping. The first big physical page in cluster[0,0]
343//    is reserved for the boot vsegs.
344//
345// 3) Third step (only for vseg that have the VSEG_TYPE_PTAB): the M page tables
346//    associated to the M vspaces must be packed in the same vseg.
347//    We divide this vseg in M sub-segments, and compute the vbase and pbase
348//    addresses for M page tables, and register these addresses in the _ptabs_paddr
349//    and _ptabs_vaddr arrays.
350// 
351/////////////////////////////////////////////////////////////////////////////////////
352void boot_vseg_map( mapping_vseg_t* vseg,
353                    unsigned int    vspace_id )
354{
355    mapping_header_t*   header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
356    mapping_cluster_t*  cluster = _get_cluster_base(header);
357    mapping_pseg_t*     pseg    = _get_pseg_base(header);
358
359    //////////// First step : compute vseg attributes
360
361    // compute destination cluster pointer & coordinates
362    pseg    = pseg + vseg->psegid;
363    cluster = cluster + pseg->clusterid;
364    unsigned int        x_dest     = cluster->x;
365    unsigned int        y_dest     = cluster->y;
366
367    // compute the "big" vseg attribute
368    unsigned int        big = vseg->big;
369
370    // all vsegs must be aligned on 4Kbytes
371    if ( vseg->vbase & 0x00000FFF ) 
372    {
373        _printf("\n[BOOT ERROR] vseg %s not aligned : vbase = %x\n", 
374                vseg->name, vseg->vbase );
375        _exit();
376    }
377
378    // compute the "is_ram" vseg attribute
379    unsigned int        is_ram;
380    if ( pseg->type == PSEG_TYPE_RAM )  is_ram = 1;
381    else                                is_ram = 0;
382
383    // compute the "is_ptab" attribute
384    unsigned int        is_ptab;
385    if ( vseg->type == VSEG_TYPE_PTAB ) is_ptab = 1;
386    else                                is_ptab = 0;
387
388    // compute actual vspace index
389    unsigned int vsid;
390    if ( vspace_id == 0xFFFFFFFF ) vsid = 0;
391    else                           vsid = vspace_id;
392
393    //////////// Second step : compute ppn and npages 
394    //////////// - if identity mapping :  ppn <= vpn
395    //////////// - if vseg is periph   :  ppn <= pseg.base >> 12
396    //////////// - if vseg is ram      :  ppn <= physical memory allocator
397
398    unsigned int ppn;          // first physical page index (28 bits = |x|y|bppi|sppi|)
399    unsigned int vpn;          // first virtual page index  (20 bits = |ix1|ix2|)
400    unsigned int vpn_max;      // last  virtual page index  (20 bits = |ix1|ix2|)
401
402    vpn     = vseg->vbase >> 12;
403    vpn_max = (vseg->vbase + vseg->length - 1) >> 12;
404
405    // compute npages
406    unsigned int npages;       // number of required (big or small) pages
407    if ( big == 0 ) npages  = vpn_max - vpn + 1;            // number of small pages
408    else            npages  = (vpn_max>>9) - (vpn>>9) + 1;  // number of big pages
409
410    // compute ppn
411    if ( vseg->ident )           // identity mapping
412    {
413        ppn = vpn;
414    }
415    else                         // not identity mapping
416    {
417        if ( is_ram )            // RAM : physical memory allocation required
418        {
419            // compute pointer on physical memory allocator in dest cluster
420            pmem_alloc_t*     palloc = &boot_pmem_alloc[x_dest][y_dest];
421
422            if ( big == 0 )             // SPP : small physical pages
423            {
424                // allocate contiguous small physical pages
425                ppn = _get_small_ppn( palloc, npages );
426            }
427            else                            // BPP : big physical pages
428            {
429 
430                // one big page can be shared by several vsegs
431                // we must chek if BPP already allocated
432                if ( is_ptab )   // It cannot be mapped
433                {
434                    ppn = _get_big_ppn( palloc, npages ); 
435                }
436                else             // It can be mapped
437                {
438                    unsigned int ix1   = vpn >> 9;   // 11 bits
439                    paddr_t      paddr = _ptabs_paddr[vsid][x_dest][y_dest] + (ix1<<2);
440                    unsigned int pte1  = _physical_read( paddr );
441
442                    if ( (pte1 & PTE_V) == 0 )     // BPP not allocated yet
443                    {
444                        // allocate contiguous big physical pages
445                        ppn = _get_big_ppn( palloc, npages );
446                    }
447                    else                           // BPP already allocated
448                    {
449                        // test if new vseg has the same mode bits than
450                        // the other vsegs in the same big page
451                        unsigned int pte1_mode = 0;
452                        if (pte1 & PTE_C) pte1_mode |= C_MODE_MASK;
453                        if (pte1 & PTE_X) pte1_mode |= X_MODE_MASK;
454                        if (pte1 & PTE_W) pte1_mode |= W_MODE_MASK;
455                        if (pte1 & PTE_U) pte1_mode |= U_MODE_MASK;
456                        if (vseg->mode != pte1_mode) 
457                        {
458                            _printf("\n[BOOT ERROR] in boot_vseg_map() : "
459                                    "vseg %s has different flags than another vseg "
460                                    "in the same BPP\n", vseg->name );
461                            _exit();
462                        }
463                        ppn = ((pte1 << 9) & 0x0FFFFE00);
464                    }
465                }
466                ppn = ppn | (vpn & 0x1FF);
467            }
468        }
469        else                    // PERI : no memory allocation required
470        {
471            ppn = pseg->base >> 12;
472        }
473    }
474
475    // update vseg.pbase field and update vsegs chaining
476    vseg->pbase     = ((paddr_t)ppn) << 12;
477    vseg->mapped    = 1;
478
479
480    //////////// Third step : (only if the vseg is a page table)
481    //////////// - compute the physical & virtual base address for each vspace
482    ////////////   by dividing the vseg in several sub-segments.
483    //////////// - register it in _ptabs_vaddr & _ptabs_paddr arrays,
484    ////////////   and initialize next_pt2 allocators.
485    //////////// - reset all entries in first level page tables
486   
487    if ( is_ptab )
488    {
489        unsigned int   vs;        // vspace index
490        unsigned int   nspaces;   // number of vspaces
491        unsigned int   nsp;       // number of small pages for one PTAB
492        unsigned int   offset;    // address offset for current PTAB
493
494        nspaces = header->vspaces;
495        offset  = 0;
496
497        // each PTAB must be aligned on a 8 Kbytes boundary
498        nsp = ( vseg->length >> 12 ) / nspaces;
499        if ( (nsp & 0x1) == 0x1 ) nsp = nsp - 1;
500
501        // compute max_pt2
502        _ptabs_max_pt2 = ((nsp<<12) - PT1_SIZE) / PT2_SIZE;
503
504        for ( vs = 0 ; vs < nspaces ; vs++ )
505        {
506            _ptabs_vaddr   [vs][x_dest][y_dest] = (vpn + offset) << 12;
507            _ptabs_paddr   [vs][x_dest][y_dest] = ((paddr_t)(ppn + offset)) << 12;
508            _ptabs_next_pt2[vs][x_dest][y_dest] = 0;
509            offset += nsp;
510
511            // reset all entries in PT1 (8 Kbytes)
512            _physical_memset( _ptabs_paddr[vs][x_dest][y_dest], PT1_SIZE, 0 );
513        }
514    }
515
516    asm volatile ("sync");
517
518#if BOOT_DEBUG_PT
519if ( big )
520_printf("\n[BOOT] vseg %s : cluster[%d,%d] / "
521       "vbase = %x / length = %x / BIG    / npages = %d / pbase = %l\n",
522       vseg->name, x_dest, y_dest, vseg->vbase, vseg->length, npages, vseg-> pbase );
523else
524_printf("\n[BOOT] vseg %s : cluster[%d,%d] / "
525        "vbase = %x / length = %x / SMALL / npages = %d / pbase = %l\n",
526       vseg->name, x_dest, y_dest, vseg->vbase, vseg->length, npages, vseg-> pbase );
527#endif
528
529} // end boot_vseg_map()
530
531/////////////////////////////////////////////////////////////////////////////////////
532// For the vseg defined by the vseg pointer, this function register PTEs
533// in one or several page tables.
534// It is a global vseg (kernel vseg) if (vspace_id == 0xFFFFFFFF).
535// The number of involved PTABs depends on the "local" and "global" attributes:
536//  - PTEs are replicated in all vspaces for a global vseg.
537//  - PTEs are replicated in all clusters containing procs for a non local vseg.
538/////////////////////////////////////////////////////////////////////////////////////
539void boot_vseg_pte( mapping_vseg_t*  vseg,
540                    unsigned int     vspace_id )
541{
542    // compute the "global" vseg attribute and actual vspace index
543    unsigned int        global;
544    unsigned int        vsid;   
545    if ( vspace_id == 0xFFFFFFFF )
546    {
547        global = 1;
548        vsid   = 0;
549    }
550    else
551    {
552        global = 0;
553        vsid   = vspace_id;
554    }
555
556    // compute the "local" and "big" attributes
557    unsigned int        local  = vseg->local;
558    unsigned int        big    = vseg->big;
559
560    // compute vseg flags
561    // The three flags (Local, Remote and Dirty) are set to 1
562    // to avoid hardware update for these flags, because GIET_VM
563    // does use these flags.
564    unsigned int flags = 0;
565    if (vseg->mode & C_MODE_MASK) flags |= PTE_C;
566    if (vseg->mode & X_MODE_MASK) flags |= PTE_X;
567    if (vseg->mode & W_MODE_MASK) flags |= PTE_W;
568    if (vseg->mode & U_MODE_MASK) flags |= PTE_U;
569    if ( global )                 flags |= PTE_G;
570                                  flags |= PTE_L;
571                                  flags |= PTE_R;
572                                  flags |= PTE_D;
573
574    // compute VPN, PPN and number of pages (big or small)
575    unsigned int vpn     = vseg->vbase >> 12;
576    unsigned int vpn_max = (vseg->vbase + vseg->length - 1) >> 12;
577    unsigned int ppn     = (unsigned int)(vseg->pbase >> 12);
578    unsigned int npages;
579    if ( big == 0 ) npages  = vpn_max - vpn + 1;           
580    else            npages  = (vpn_max>>9) - (vpn>>9) + 1; 
581
582    // compute destination cluster coordinates, for local vsegs
583    mapping_header_t*   header       = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
584    mapping_cluster_t*  cluster      = _get_cluster_base(header);
585    mapping_pseg_t*     pseg         = _get_pseg_base(header);
586    mapping_pseg_t*     pseg_dest    = &pseg[vseg->psegid];
587    mapping_cluster_t*  cluster_dest = &cluster[pseg_dest->clusterid];
588    unsigned int        x_dest       = cluster_dest->x;
589    unsigned int        y_dest       = cluster_dest->y;
590
591    unsigned int p;           // iterator for physical page index
592    unsigned int x;           // iterator for cluster x coordinate 
593    unsigned int y;           // iterator for cluster y coordinate 
594    unsigned int v;           // iterator for vspace index
595
596    // loop on PTEs
597    for ( p = 0 ; p < npages ; p++ )
598    { 
599        if  ( (local != 0) && (global == 0) )         // one cluster  / one vspace
600        {
601            if ( big )   // big pages => PTE1s
602            {
603                boot_add_pte1( vsid,
604                               x_dest,
605                               y_dest,
606                               vpn + (p<<9),
607                               flags, 
608                               ppn + (p<<9) );
609            }
610            else         // small pages => PTE2s
611            {
612                boot_add_pte2( vsid,
613                               x_dest,
614                               y_dest,
615                               vpn + p,     
616                               flags, 
617                               ppn + p );
618            }
619        }
620        else if ( (local == 0) && (global == 0) )     // all clusters / one vspace
621        {
622            for ( x = 0 ; x < X_SIZE ; x++ )
623            {
624                for ( y = 0 ; y < Y_SIZE ; y++ )
625                {
626                    if ( cluster[(x * Y_SIZE) + y].procs )
627                    {
628                        if ( big )   // big pages => PTE1s
629                        {
630                            boot_add_pte1( vsid,
631                                           x,
632                                           y,
633                                           vpn + (p<<9),
634                                           flags, 
635                                           ppn + (p<<9) );
636                        }
637                        else         // small pages => PTE2s
638                        {
639                            boot_add_pte2( vsid,
640                                           x,
641                                           y,
642                                           vpn + p,
643                                           flags, 
644                                           ppn + p );
645                        }
646                    }
647                }
648            }
649        }
650        else if ( (local != 0) && (global != 0) )     // one cluster  / all vspaces
651        {
652            for ( v = 0 ; v < header->vspaces ; v++ )
653            {
654                if ( big )   // big pages => PTE1s
655                {
656                    boot_add_pte1( v,
657                                   x_dest,
658                                   y_dest,
659                                   vpn + (p<<9),
660                                   flags, 
661                                   ppn + (p<<9) );
662                }
663                else         // small pages = PTE2s
664                { 
665                    boot_add_pte2( v,
666                                   x_dest,
667                                   y_dest,
668                                   vpn + p,
669                                   flags, 
670                                   ppn + p );
671                }
672            }
673        }
674        else if ( (local == 0) && (global != 0) )     // all clusters / all vspaces
675        {
676            for ( x = 0 ; x < X_SIZE ; x++ )
677            {
678                for ( y = 0 ; y < Y_SIZE ; y++ )
679                {
680                    if ( cluster[(x * Y_SIZE) + y].procs )
681                    {
682                        for ( v = 0 ; v < header->vspaces ; v++ )
683                        {
684                            if ( big )  // big pages => PTE1s
685                            {
686                                boot_add_pte1( v,
687                                               x,
688                                               y,
689                                               vpn + (p<<9),
690                                               flags, 
691                                               ppn + (p<<9) );
692                            }
693                            else        // small pages -> PTE2s
694                            {
695                                boot_add_pte2( v,
696                                               x,
697                                               y,
698                                               vpn + p,
699                                               flags, 
700                                               ppn + p );
701                            }
702                        }
703                    }
704                }
705            }
706        }
707    }  // end for pages
708
709    asm volatile ("sync");
710
711}  // end boot_vseg_pte()
712
713
714///////////////////////////////////////////////////////////////////////////////
715// Processor P[x][y][0] computes physical base address for all globals vsegs,
716// using the local Page Table, to check page tables initialisation.
717///////////////////////////////////////////////////////////////////////////////
718void boot_ptab_check( unsigned int x,
719                      unsigned int y )
720{
721    mapping_header_t*   header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
722    mapping_vseg_t*     vseg   = _get_vseg_base(header);
723    page_table_t*       ptab   = (page_table_t*)_ptabs_vaddr[0][x][y];
724
725    unsigned int vseg_id;
726    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
727    {
728        unsigned int  vpn   = vseg[vseg_id].vbase >> 12;
729        unsigned int  ppn   = 0; 
730        unsigned int  flags = 0;
731        _v2p_translate( ptab , vpn , &ppn , &flags );
732        _printf("@@@ P[%d,%d,0] access vseg %s : vpn = %x / ppn = %x\n",
733                x , y , vseg[vseg_id].name , vpn , ppn ); 
734    }
735} 
736
737///////////////////////////////////////////////////////////////////////////////
738// This function is executed by  processor[x][y][0] in each cluster
739// containing at least one processor.
740// It initialises all page table for all global or private vsegs
741// mapped in cluster[x][y], as specified in the mapping.
742// In each cluster all page tables for the different vspaces must be
743// packed in one vseg occupying one single BPP (Big Physical Page).
744//
745// For each vseg, the mapping is done in two steps:
746// 1) mapping : the boot_vseg_map() function allocates contiguous BPPs
747//    or SPPs (if the vseg is not associated to a peripheral), and register
748//    the physical base address in the vseg pbase field. It initialises the
749//    _ptabs_vaddr[] and _ptabs_paddr[] arrays if the vseg is a PTAB.
750//
751// 2) page table initialisation : the boot_vseg_pte() function initialise
752//    the PTEs (both PTE1 and PTE2) in one or several page tables:
753//    - PTEs are replicated in all vspaces for a global vseg.
754//    - PTEs are replicated in all clusters for a non local vseg.
755//
756// We must handle vsegs in the following order
757//   1) global vseg containing PTAB mapped in cluster[x][y],
758//   2) global vsegs occupying more than one BPP mapped in cluster[x][y],
759//   3) others global vsegs mapped in cluster[x][y],
760//   4) all private vsegs in all user spaces mapped in cluster[x][y].
761///////////////////////////////////////////////////////////////////////////////
762void boot_ptab_init( unsigned int cx,
763                     unsigned int cy ) 
764{
765    mapping_header_t*   header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
766    mapping_vspace_t*   vspace = _get_vspace_base(header);
767    mapping_vseg_t*     vseg   = _get_vseg_base(header);
768    mapping_cluster_t*  cluster ;
769    mapping_pseg_t*     pseg    ;
770
771    unsigned int vspace_id;
772    unsigned int vseg_id;
773
774    unsigned int procid     = _get_procid();
775    unsigned int lpid       = procid & ((1<<P_WIDTH)-1);
776
777    if( lpid )
778    {
779        _printf("\n[BOOT ERROR] in boot_ptab_init() : "
780                "P[%d][%d][%d] should not execute it\n", cx, cy, lpid );
781        _exit();
782    } 
783
784    if ( header->vspaces == 0 )
785    {
786        _printf("\n[BOOT ERROR] in boot_ptab_init() : "
787                "mapping %s contains no vspace\n", header->name );
788        _exit();
789    }
790
791    ///////// Phase 1 : global vseg containing the PTAB (two barriers required)
792
793    // get PTAB global vseg in cluster(cx,cy)
794    unsigned int found = 0;
795    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
796    {
797        pseg    = _get_pseg_base(header) + vseg[vseg_id].psegid;
798        cluster = _get_cluster_base(header) + pseg->clusterid;
799        if ( (vseg[vseg_id].type == VSEG_TYPE_PTAB) && 
800             (cluster->x == cx) && (cluster->y == cy) )
801        {
802            found = 1;
803            break;
804        }
805    }
806    if ( found == 0 )
807    {
808        _printf("\n[BOOT ERROR] in boot_ptab_init() : "
809                "cluster[%d][%d] contains no PTAB vseg\n", cx , cy );
810        _exit();
811    }
812
813    boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
814
815    //////////////////////////////////////////////
816    _simple_barrier_wait( &_barrier_all_clusters );
817    //////////////////////////////////////////////
818
819    boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
820
821    //////////////////////////////////////////////
822    _simple_barrier_wait( &_barrier_all_clusters );
823    //////////////////////////////////////////////
824
825    ///////// Phase 2 : global vsegs occupying more than one BPP
826
827    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
828    {
829        pseg    = _get_pseg_base(header) + vseg[vseg_id].psegid;
830        cluster = _get_cluster_base(header) + pseg->clusterid;
831        if ( (vseg[vseg_id].length > 0x200000) &&
832             (vseg[vseg_id].mapped == 0) &&
833             (cluster->x == cx) && (cluster->y == cy) )
834        {
835            boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
836            boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
837        }
838    }
839
840    ///////// Phase 3 : all others global vsegs
841
842    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
843    { 
844        pseg    = _get_pseg_base(header) + vseg[vseg_id].psegid;
845        cluster = _get_cluster_base(header) + pseg->clusterid;
846        if ( (vseg[vseg_id].mapped == 0) && 
847             (cluster->x == cx) && (cluster->y == cy) )
848        {
849            boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
850            boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
851        }
852    }
853
854    ///////// Phase 4 : all private vsegs
855
856    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
857    {
858        for (vseg_id = vspace[vspace_id].vseg_offset;
859             vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs);
860             vseg_id++) 
861        {
862            pseg    = _get_pseg_base(header) + vseg[vseg_id].psegid;
863            cluster = _get_cluster_base(header) + pseg->clusterid;
864            if ( (cluster->x == cx) && (cluster->y == cy) )
865            {
866                boot_vseg_map( &vseg[vseg_id], vspace_id );
867                boot_vseg_pte( &vseg[vseg_id], vspace_id );
868            }
869        }
870    }
871
872    //////////////////////////////////////////////
873    _simple_barrier_wait( &_barrier_all_clusters );
874    //////////////////////////////////////////////
875
876} // end boot_ptab_init()
877
878////////////////////////////////////////////////////////////////////////////////
879// This function should be executed by P[0][0][0] only. It complete the
880// page table initialisation, taking care of all global vsegs that are
881// not mapped in a cluster containing a processor, and have not been
882// handled by the boot_ptab_init(x,y) function.
883// An example of such vsegs are the external peripherals in TSAR_LETI platform.
884////////////////////////////////////////////////////////////////////////////////
885void boot_ptab_extend()
886{
887
888    mapping_header_t*   header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
889    mapping_vseg_t*     vseg   = _get_vseg_base(header);
890
891    unsigned int vseg_id;
892
893    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
894    {
895        if ( vseg[vseg_id].mapped == 0 ) 
896        {
897            boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
898            boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
899        }
900    }
901}  // end boot_ptab_extend()
902
903///////////////////////////////////////////////////////////////////////////////
904// This function returns in the vbase and length buffers the virtual base
905// address and the length of the  segment allocated to the schedulers array
906// in the cluster defined by the clusterid argument.
907///////////////////////////////////////////////////////////////////////////////
908void boot_get_sched_vaddr( unsigned int  cluster_id,
909                           unsigned int* vbase, 
910                           unsigned int* length )
911{
912    mapping_header_t* header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
913    mapping_vseg_t*   vseg   = _get_vseg_base(header);
914    mapping_pseg_t*   pseg   = _get_pseg_base(header);
915
916    unsigned int vseg_id;
917    unsigned int found = 0;
918
919    for ( vseg_id = 0 ; (vseg_id < header->vsegs) && (found == 0) ; vseg_id++ )
920    {
921        if ( (vseg[vseg_id].type == VSEG_TYPE_SCHED) && 
922             (pseg[vseg[vseg_id].psegid].clusterid == cluster_id ) )
923        {
924            *vbase  = vseg[vseg_id].vbase;
925            *length = vseg[vseg_id].length;
926            found = 1;
927        }
928    }
929    if ( found == 0 )
930    {
931        mapping_cluster_t* cluster = _get_cluster_base(header);
932        _printf("\n[BOOT ERROR] No vseg of type SCHED in cluster [%d,%d]\n",
933                cluster[cluster_id].x, cluster[cluster_id].y );
934        _exit();
935    }
936} // end boot_get_sched_vaddr()
937
938////////////////////////////////////////////////////////////////////////////////////
939// This function is executed in parallel by all processors P[x][y][0].
940// It initialises all schedulers in cluster [x][y]. The MMU must be activated.
941// It is split in two phases separated by a synchronisation barrier.
942// - In Step 1, it initialises the _schedulers[x][y][l] pointers array,
943//              the idle_task context and the HWI / PTI vectors.
944// - In Step 2, it scan all tasks in all vspaces to complete the tasks contexts,
945//              initialisation as specified in the mapping_info data structure,
946//              and set the CP0_SCHED register.
947////////////////////////////////////////////////////////////////////////////////////
948void boot_scheduler_init( unsigned int x, 
949                          unsigned int y )
950{
951    mapping_header_t*    header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
952    mapping_cluster_t*   cluster = _get_cluster_base(header);
953    mapping_vspace_t*    vspace  = _get_vspace_base(header);
954    mapping_vseg_t*      vseg    = _get_vseg_base(header);
955    mapping_task_t*      task    = _get_task_base(header);
956    mapping_periph_t*    periph  = _get_periph_base(header);
957    mapping_irq_t*       irq     = _get_irq_base(header);
958
959    unsigned int         periph_id; 
960    unsigned int         irq_id;
961    unsigned int         vspace_id;
962    unsigned int         vseg_id;
963    unsigned int         task_id; 
964
965    unsigned int         sched_vbase;          // schedulers array vbase address
966    unsigned int         sched_length;         // schedulers array length
967    static_scheduler_t*  psched;               // pointer on processor scheduler
968
969    unsigned int cluster_id = x * Y_SIZE + y; 
970    unsigned int nprocs = cluster[cluster_id].procs;
971    unsigned int lpid;                       
972   
973    /////////////////////////////////////////////////////////////////////////
974    // Step 1 : initialize the schedulers[] array of pointers,
975    //          the idle task context and the HWI and PTI interrupt vectors.
976    //          The WTI interrupt vector entries corresponding to interrupts
977    //          generated by the PIC component are handled later.
978
979    // get scheduler array virtual base address in cluster[x,y]
980    boot_get_sched_vaddr( cluster_id, &sched_vbase, &sched_length );
981
982    if ( sched_length < (nprocs<<13) ) // 8 Kbytes per scheduler
983    {
984        _printf("\n[BOOT ERROR] Sched segment too small in cluster[%d,%d]\n", x, y );
985        _exit();
986    }
987
988    // loop on local processors
989    for ( lpid = 0 ; lpid < nprocs ; lpid++ )
990    {
991        // get scheduler pointer and initialise the schedulers pointers array
992        psched = (static_scheduler_t*)(sched_vbase + (lpid<<13));
993        _schedulers[x][y][lpid] = psched;
994
995        // initialise the "tasks" and "current" variables default values
996        psched->tasks   = 0;
997        psched->current = IDLE_TASK_INDEX;
998
999        // default values for HWI / PTI / SWI vectors (valid bit = 0)
1000        unsigned int slot;
1001        for (slot = 0; slot < 32; slot++)
1002        {
1003            psched->hwi_vector[slot] = 0;
1004            psched->pti_vector[slot] = 0;
1005            psched->wti_vector[slot] = 0;
1006        }
1007
1008        // WTI[lpid] <= ISR_WAKUP / PTI[lpid] <= ISR_TICK
1009        psched->wti_vector[lpid] = ISR_WAKUP | 0x80000000;
1010        psched->pti_vector[lpid] = ISR_TICK  | 0x80000000;
1011
1012        // initializes the idle_task context:
1013        // - the SR slot is 0xFF03 because this task run in kernel mode.
1014        // - it uses the page table of vspace[0]
1015        // - it uses the kernel TTY terminal
1016        // - slots containing addresses (SP,RA,EPC) are initialised by kernel_init()
1017
1018        psched->context[IDLE_TASK_INDEX][CTX_CR_ID]   = 0;
1019        psched->context[IDLE_TASK_INDEX][CTX_SR_ID]   = 0xFF03;
1020        psched->context[IDLE_TASK_INDEX][CTX_PTPR_ID] = _ptabs_paddr[0][x][y]>>13;
1021        psched->context[IDLE_TASK_INDEX][CTX_PTAB_ID] = _ptabs_vaddr[0][x][y];
1022        psched->context[IDLE_TASK_INDEX][CTX_TTY_ID]  = 0;
1023        psched->context[IDLE_TASK_INDEX][CTX_LTID_ID] = IDLE_TASK_INDEX;
1024        psched->context[IDLE_TASK_INDEX][CTX_VSID_ID] = 0;
1025        psched->context[IDLE_TASK_INDEX][CTX_RUN_ID]  = 1;
1026    }
1027
1028    // scan local peripherals to get local XCU
1029    mapping_periph_t*  xcu = NULL;
1030
1031    for ( periph_id = cluster[cluster_id].periph_offset ;
1032          periph_id < cluster[cluster_id].periph_offset + cluster[cluster_id].periphs;
1033          periph_id++ )
1034    {
1035        if( periph[periph_id].type == PERIPH_TYPE_XCU ) 
1036        {
1037            xcu = &periph[periph_id];
1038
1039            if ( xcu->arg0 < (nprocs * header->irq_per_proc) )
1040            {
1041                _printf("\n[BOOT ERROR] Not enough inputs for XCU[%d,%d]\n", x, y );
1042                _exit();
1043            }
1044        }
1045    } 
1046
1047    if ( xcu == NULL )
1048    {         
1049        _printf("\n[BOOT ERROR] missing XCU in cluster[%d,%d]\n", x , y );
1050        _exit();
1051    }
1052
1053    // scan HWIs connected to local XCU
1054    // for round-robin allocation to local processors
1055    lpid = 0;
1056    for ( irq_id = xcu->irq_offset ;
1057          irq_id < xcu->irq_offset + xcu->irqs ;
1058          irq_id++ )
1059    {
1060        unsigned int type    = irq[irq_id].srctype;
1061        unsigned int srcid   = irq[irq_id].srcid;
1062        unsigned int isr     = irq[irq_id].isr & 0xFFFF;
1063        unsigned int channel = irq[irq_id].channel << 16;
1064
1065        if ( (type != IRQ_TYPE_HWI) || (srcid > 31) )
1066        {
1067            _printf("\n[BOOT ERROR] Bad IRQ in cluster[%d,%d]\n", x, y );
1068            _exit();
1069        }
1070
1071        _schedulers[x][y][lpid]->hwi_vector[srcid] = isr | channel | 0x80000000;
1072
1073        lpid = (lpid + 1) % nprocs; 
1074    } // end for irqs
1075
1076    //////////////////////////////////////////////
1077    _simple_barrier_wait( &_barrier_all_clusters );
1078    //////////////////////////////////////////////
1079
1080    ////////////////////////////////////////////////////////////////////////
1081    // Step 2 : Initialise the tasks context. The context of task placed
1082    //          on  processor P must be stored in the scheduler of P.
1083    //          This require two nested loops: loop on the tasks, and loop
1084    //          on the local processors. We complete the scheduler when the
1085    //          required placement fit one local processor.
1086
1087    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
1088    {
1089        // We must set the PTPR depending on the vspace, because the start_vector
1090        // and the stack address are defined in virtual space.
1091        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id][x][y] >> 13) );
1092
1093        // loop on the tasks in vspace (task_id is the global index in mapping)
1094        for (task_id = vspace[vspace_id].task_offset;
1095             task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks);
1096             task_id++) 
1097        {
1098            // get the required task placement coordinates [x,y,p]
1099            unsigned int req_x      = cluster[task[task_id].clusterid].x;
1100            unsigned int req_y      = cluster[task[task_id].clusterid].y;
1101            unsigned int req_p      = task[task_id].proclocid;                 
1102
1103            // ctx_sr : value required before an eret instruction
1104            unsigned int ctx_sr = 0x2000FF13;
1105
1106            // ctx_ptpr : page table physical base address (shifted by 13 bit)
1107            unsigned int ctx_ptpr = (_ptabs_paddr[vspace_id][req_x][req_y] >> 13);
1108
1109            // ctx_ptab : page_table virtual base address
1110            unsigned int ctx_ptab = _ptabs_vaddr[vspace_id][req_x][req_y];
1111
1112            // ctx_epc : Get the virtual address of the memory location containing
1113            // the task entry point : the start_vector is stored by GCC in the seg_data
1114            // segment and we must wait the .elf loading to get the entry point value...
1115            vseg_id = vspace[vspace_id].start_vseg_id;     
1116            unsigned int ctx_epc = vseg[vseg_id].vbase + (task[task_id].startid)*4;
1117
1118            // ctx_sp :  Get the vseg containing the stack
1119            vseg_id = task[task_id].stack_vseg_id;
1120            unsigned int ctx_sp = vseg[vseg_id].vbase + vseg[vseg_id].length;
1121
1122            // get vspace thread index
1123            unsigned int thread_id = task[task_id].trdid;
1124
1125            // loop on the local processors
1126            for ( lpid = 0 ; lpid < nprocs ; lpid++ )
1127            {
1128                if ( (x == req_x) && (y == req_y) && (req_p == lpid) )   // fit
1129                {
1130                    // pointer on selected scheduler
1131                    psched = _schedulers[x][y][lpid];
1132
1133                    // get local task index in scheduler
1134                    unsigned int ltid = psched->tasks;
1135
1136                    // update the "tasks" and "current" fields in scheduler:
1137                    psched->tasks   = ltid + 1;
1138                    psched->current = 0;
1139
1140                    // initializes the task context
1141                    psched->context[ltid][CTX_CR_ID]     = 0;
1142                    psched->context[ltid][CTX_SR_ID]     = ctx_sr;
1143                    psched->context[ltid][CTX_SP_ID]     = ctx_sp;
1144                    psched->context[ltid][CTX_EPC_ID]    = ctx_epc;
1145                    psched->context[ltid][CTX_PTPR_ID]   = ctx_ptpr;
1146                    psched->context[ltid][CTX_PTAB_ID]   = ctx_ptab;
1147                    psched->context[ltid][CTX_LTID_ID]   = ltid;
1148                    psched->context[ltid][CTX_GTID_ID]   = task_id;
1149                    psched->context[ltid][CTX_TRDID_ID]  = thread_id;
1150                    psched->context[ltid][CTX_VSID_ID]   = vspace_id;
1151                    psched->context[ltid][CTX_RUN_ID]    = 1;
1152
1153                    psched->context[ltid][CTX_TTY_ID]    = 0xFFFFFFFF;
1154                    psched->context[ltid][CTX_CMA_FB_ID] = 0xFFFFFFFF;
1155                    psched->context[ltid][CTX_CMA_RX_ID] = 0xFFFFFFFF;
1156                    psched->context[ltid][CTX_CMA_TX_ID] = 0xFFFFFFFF;
1157                    psched->context[ltid][CTX_NIC_RX_ID] = 0xFFFFFFFF;
1158                    psched->context[ltid][CTX_NIC_TX_ID] = 0xFFFFFFFF;
1159                    psched->context[ltid][CTX_TIM_ID]    = 0xFFFFFFFF;
1160                    psched->context[ltid][CTX_HBA_ID]    = 0xFFFFFFFF;
1161
1162#if BOOT_DEBUG_SCHED
1163_printf("\nTask %s in vspace %s allocated to P[%d,%d,%d]\n"
1164        " - ctx[LTID]  = %d\n"
1165        " - ctx[SR]    = %x\n"
1166        " - ctx[SP]    = %x\n"
1167        " - ctx[EPC]   = %x\n"
1168        " - ctx[PTPR]  = %x\n"
1169        " - ctx[PTAB]  = %x\n"
1170        " - ctx[VSID]  = %d\n"
1171        " - ctx[TRDID] = %d\n",
1172        task[task_id].name,
1173        vspace[vspace_id].name,
1174        x, y, lpid,
1175        psched->context[ltid][CTX_LTID_ID],
1176        psched->context[ltid][CTX_SR_ID],
1177        psched->context[ltid][CTX_SP_ID],
1178        psched->context[ltid][CTX_EPC_ID],
1179        psched->context[ltid][CTX_PTPR_ID],
1180        psched->context[ltid][CTX_PTAB_ID],
1181        psched->context[ltid][CTX_VSID_ID],
1182        psched->context[ltid][CTX_TRDID_ID] );
1183#endif
1184                } // end if FIT
1185            } // end for loop on local procs
1186        } // end loop on tasks
1187    } // end loop on vspaces
1188} // end boot_scheduler_init()
1189
1190
1191/////////////////////////////////////////////////////////////////////////////
1192// This function loops on all processors in all clusters to display
1193// the interrupt vectors for each processor.
1194/////////////////////////////////////////////////////////////////////////////
1195void boot_sched_irq_display()
1196{
1197    unsigned int         cx;
1198    unsigned int         cy;
1199    unsigned int         lpid;
1200    unsigned int         slot;
1201    unsigned int         entry;
1202
1203    mapping_header_t*    header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1204    mapping_cluster_t*   cluster = _get_cluster_base(header);
1205
1206    static_scheduler_t*  psched; 
1207
1208    for ( cx = 0 ; cx < X_SIZE ; cx++ )
1209    {
1210        for ( cy = 0 ; cy < Y_SIZE ; cy++ )
1211        {
1212            unsigned int cluster_id = (cx * Y_SIZE) + cy;
1213            unsigned int nprocs = cluster[cluster_id].procs;
1214
1215            for ( lpid = 0 ; lpid < nprocs ; lpid++ )
1216            {
1217                psched = _schedulers[cx][cy][lpid];
1218       
1219                _printf("\n[BOOT] scheduler for proc[%d,%d,%d] : ntasks = %d\n",
1220                        cx , cy , lpid , psched->tasks );
1221
1222                for ( slot = 0 ; slot < 32 ; slot++ )
1223                {
1224                    entry = psched->hwi_vector[slot];
1225                    if ( entry & 0x80000000 ) 
1226                    _printf(" - HWI %d / isrtype = %d / channel = %d\n",
1227                            slot , (entry & 0xFFFF) , ((entry >> 16) & 0x7FFF) );
1228                }
1229                for ( slot = 0 ; slot < 32 ; slot++ )
1230                {
1231                    entry = psched->wti_vector[slot];
1232                    if ( entry & 0x80000000 ) 
1233                    _printf(" - WTI %d / isrtype = %d / channel = %d\n",
1234                            slot , (entry & 0xFFFF) , ((entry >> 16) & 0x7FFF) );
1235                }
1236                for ( slot = 0 ; slot < 32 ; slot++ )
1237                {
1238                    entry = psched->pti_vector[slot];
1239                    if ( entry & 0x80000000 ) 
1240                    _printf(" - PTI %d / isrtype = %d / channel = %d\n",
1241                            slot , (entry & 0xFFFF) , ((entry >> 16) & 0x7FFF) );
1242                }
1243            }
1244        }
1245    } 
1246}  // end boot_sched_display()
1247
1248
1249/////////////////////////////////////////////////////////////////////////////
1250// This function complete the schedulers initialisation when the platform
1251// contains a PIC component in the IO cluster.
1252// It is executed by P[0][0][0] only.
1253// It scan HWIs connected to PIC for Round Robin allocation to processors,
1254// as WTI. It allocates one WTI per processor, starting from P[0,0,0],
1255// and increments (cluster_id, lpid) as required.
1256/////////////////////////////////////////////////////////////////////////////
1257void boot_pic_wti_init()
1258{
1259    mapping_header_t*    header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1260    mapping_cluster_t*   cluster = _get_cluster_base(header);
1261    mapping_periph_t*    periph  = _get_periph_base(header);
1262    mapping_irq_t*       irq     = _get_irq_base(header);
1263
1264    unsigned int         periph_id;   // peripheral index in mapping_info
1265    unsigned int         irq_id;      // irq index in mapping_info
1266
1267    // get cluster_io index in mapping
1268    unsigned int         x_io       = header->x_io; 
1269    unsigned int         y_io       = header->y_io; 
1270    unsigned int         cluster_io = (x_io * Y_SIZE) + y_io; 
1271   
1272    // scan peripherals in cluster_io to find PIC
1273    mapping_periph_t*    pic = NULL;
1274
1275    for ( periph_id = cluster[cluster_io].periph_offset ;
1276          periph_id < cluster[cluster_io].periph_offset + cluster[cluster_io].periphs;
1277          periph_id++ )
1278    {
1279        if ( periph[periph_id].type == PERIPH_TYPE_PIC ) 
1280        {
1281            pic = &periph[periph_id];
1282            break;
1283        }
1284    }
1285
1286    if ( pic == NULL )  return;
1287
1288    // initialize WTI channel allocators in all clusters
1289    unsigned int x;
1290    unsigned int y;
1291    for ( x = 0 ; x < X_SIZE ; x++ )
1292    {
1293        for ( y = 0 ; y < Y_SIZE ; y++ )
1294        {
1295            _wti_channel_alloc[x][y] = NB_PROCS_MAX;
1296        }
1297    }
1298
1299    // scan IRQS defined in PIC
1300    unsigned int  cluster_id = 0;
1301    unsigned int  lpid       = 0;
1302    unsigned int  cx         = cluster[cluster_id].x;
1303    unsigned int  cy         = cluster[cluster_id].y;
1304
1305    for ( irq_id = pic->irq_offset ;
1306          irq_id < pic->irq_offset + pic->irqs ;
1307          irq_id++ )
1308    {
1309        // compute next values for cluster_id, lpid, cx, cy
1310        // if no more WTI allocatable in current cluster
1311        unsigned int overflow = 0;
1312
1313        while ( (lpid >= cluster[cluster_id].procs) ||
1314                (_wti_channel_alloc[cx][cy] >= 32) )
1315        {
1316            cluster_id = (cluster_id + 1) % (X_SIZE*Y_SIZE);
1317            cx         = cluster[cluster_id].x;
1318            cy         = cluster[cluster_id].y;
1319            lpid       = 0;
1320
1321            overflow++;
1322
1323            if ( overflow > 1024 )
1324            {
1325                _printf("\n[BOOT ERROR] Not enough processors for external IRQs\n");
1326                _exit();
1327            }
1328        } 
1329        // allocate a WTI to processor defined by (cluster_id,lpid)
1330        unsigned int type    = irq[irq_id].srctype;
1331        unsigned int srcid   = irq[irq_id].srcid;
1332        unsigned int isr     = irq[irq_id].isr & 0xFFFF;
1333        unsigned int channel = irq[irq_id].channel << 16;
1334
1335        if ( (type != IRQ_TYPE_HWI) || (srcid > 31) )
1336        {
1337            _printf("\n[BOOT ERROR] in boot_pic_wti_init() Bad IRQ type\n");
1338            _exit();
1339        }
1340
1341        // get scheduler address for selected processor
1342        static_scheduler_t* psched = _schedulers[cx][cy][lpid];
1343
1344        // update WTI vector for selected processor
1345        unsigned int index            = _wti_channel_alloc[cx][cy];
1346        psched->wti_vector[index]     = isr | channel | 0x80000000;
1347
1348        // update IRQ fields in mapping for PIC initialisation
1349        irq[irq_id].dest_id = index;
1350        irq[irq_id].dest_xy = (cx << Y_WIDTH) + cy;
1351
1352        // update pointers
1353        _wti_channel_alloc[cx][cy] = index + 1;
1354        lpid                       = lpid + 1;
1355
1356    }  // end for IRQs
1357
1358#if BOOT_DEBUG_SCHED
1359boot_sched_irq_display();
1360#endif
1361
1362} // end boot_pic_wti_init()
1363               
1364//////////////////////////////////////////////////////////////////////////////////
1365// This function loads the map.bin file from block device.
1366//////////////////////////////////////////////////////////////////////////////////
1367void boot_mapping_init()
1368{
1369    // open file "map.bin"
1370    int fd_id = _fat_open( IOC_BOOT_MODE,
1371                           "map.bin",
1372                           0 );         // no creation
1373    if ( fd_id == -1 )
1374    {
1375        _printf("\n[BOOT ERROR] : map.bin file not found \n");
1376        _exit();
1377    }
1378
1379#if BOOT_DEBUG_MAPPING
1380_printf("\n[BOOT] map.bin file successfully open at cycle %d\n", _get_proctime() );
1381#endif
1382
1383    // get "map.bin" file size (from fat) and check it
1384    unsigned int size    = fat.fd[fd_id].file_size;
1385
1386    if ( size > SEG_BOOT_MAPPING_SIZE )
1387    {
1388        _printf("\n[BOOT ERROR] : allocated segment too small for map.bin file\n");
1389        _exit();
1390    }
1391
1392#if BOOT_DEBUG_MAPPING
1393_printf("\n[BOOT] map.bin buffer pbase = %x / buffer size = %x / file_size = %x\n",
1394        SEG_BOOT_MAPPING_BASE , SEG_BOOT_MAPPING_SIZE , size );
1395#endif
1396
1397    // load "map.bin" file into buffer
1398    unsigned int nblocks = size >> 9;
1399    unsigned int offset  = size & 0x1FF;
1400    if ( offset ) nblocks++;
1401
1402    unsigned int ok = _fat_read( IOC_BOOT_MODE,
1403                                 fd_id, 
1404                                 (unsigned int*)SEG_BOOT_MAPPING_BASE, 
1405                                 nblocks,       
1406                                 0 );      // offset
1407    if ( ok == -1 )
1408    {
1409        _printf("\n[BOOT ERROR] : unable to load map.bin file \n");
1410        _exit();
1411    }
1412
1413#if BOOT_DEBUG_MAPPING
1414_printf("\n[BOOT] map.bin file successfully loaded at cycle %d\n", _get_proctime() );
1415#endif
1416
1417    // check mapping signature, number of clusters, number of vspaces 
1418    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1419    if ( (header->signature != IN_MAPPING_SIGNATURE) ||
1420         (header->x_size    != X_SIZE)               || 
1421         (header->y_size    != Y_SIZE)               ||
1422         (header->vspaces   > GIET_NB_VSPACE_MAX)    )
1423    {
1424        _printf("\n[BOOT ERROR] Illegal mapping signature: %x\n", header->signature );
1425        _exit();
1426    }
1427
1428#if BOOT_DEBUG_MAPPING
1429unsigned int  line;
1430unsigned int* pointer = (unsigned int*)SEG_BOOT_MAPPING_BASE;
1431_printf("\n[BOOT] First block of mapping\n");
1432for ( line = 0 ; line < 8 ; line++ )
1433{
1434    _printf(" | %x | %x | %x | %x | %x | %x | %x | %x |\n",
1435            *(pointer + 0),
1436            *(pointer + 1),
1437            *(pointer + 2),
1438            *(pointer + 3),
1439            *(pointer + 4),
1440            *(pointer + 5),
1441            *(pointer + 6),
1442            *(pointer + 7) );
1443
1444    pointer = pointer + 8;
1445}
1446#endif
1447
1448#if BOOT_DEBUG_MAPPING
1449_printf("\n[BOOT] map.bin file checked at cycle %d\n", _get_proctime() );
1450#endif
1451
1452    // close file "map.bin"
1453    _fat_close( fd_id );
1454   
1455} // end boot_mapping_init()
1456
1457
1458/////////////////////////////////////////////////////////////////////////////////////
1459// This function load all loadable segments for one .elf file, identified
1460// by the "pathname" argument. Some loadable segments can be copied in several
1461// clusters: same virtual address but different physical addresses. 
1462// - It open the file.
1463// - It loads the complete file in the dedicated boot_elf_buffer.
1464// - It copies each loadable segments  at the virtual address defined in
1465//   the .elf file, making several copies if the target vseg is not local.
1466// - It closes the file.
1467// This function is supposed to be executed by processor[0,0,0].
1468// Note:
1469//   We must use physical addresses to reach the destination buffers that
1470//   can be located in remote clusters. We use either a _physical_memcpy(),
1471//   or a _dma_physical_copy() if DMA is available.
1472//////////////////////////////////////////////////////////////////////////////////////
1473void load_one_elf_file( unsigned int is_kernel,     // kernel file if non zero
1474                        char*        pathname,
1475                        unsigned int vspace_id )    // to scan the proper vspace
1476{
1477    mapping_header_t  * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1478    mapping_vspace_t  * vspace  = _get_vspace_base(header);
1479    mapping_vseg_t    * vseg    = _get_vseg_base(header);
1480
1481    unsigned int seg_id;
1482
1483#if BOOT_DEBUG_ELF
1484_printf("\n[BOOT] Start searching file %s at cycle %d\n", 
1485        pathname, _get_proctime() );
1486#endif
1487
1488    // open .elf file
1489    int fd_id = _fat_open( IOC_BOOT_MODE,
1490                           pathname,
1491                           0 );      // no creation
1492    if ( fd_id < 0 )
1493    {
1494        _printf("\n[BOOT ERROR] load_one_elf_file() : %s not found\n", pathname );
1495        _exit();
1496    }
1497
1498    // check buffer size versus file size
1499    if ( fat.fd[fd_id].file_size > GIET_ELF_BUFFER_SIZE )
1500    {
1501        _printf("\n[BOOT ERROR] in load_one_elf_file() : %s / size = %x "
1502                "larger than GIET_ELF_BUFFER_SIZE = %x\n",
1503                pathname , fat.fd[fd_id].file_size , GIET_ELF_BUFFER_SIZE );
1504        _exit();
1505    }
1506
1507    // compute number of sectors
1508    unsigned int nbytes   = fat.fd[fd_id].file_size;
1509    unsigned int nsectors = nbytes>>9;
1510    if( nbytes & 0x1FF) nsectors++;
1511
1512    // load file in elf buffer
1513    if( _fat_read( IOC_BOOT_MODE, 
1514                   fd_id, 
1515                   boot_elf_buffer,
1516                   nsectors,
1517                   0 ) != nsectors )
1518    {
1519        _printf("\n[BOOT ERROR] load_one_elf_file() : unexpected EOF for file %s\n",
1520                pathname );
1521        _exit();
1522    }
1523
1524    // Check ELF Magic Number in ELF header
1525    Elf32_Ehdr* elf_header_ptr = (Elf32_Ehdr*)boot_elf_buffer;
1526
1527    if ( (elf_header_ptr->e_ident[EI_MAG0] != ELFMAG0) ||
1528         (elf_header_ptr->e_ident[EI_MAG1] != ELFMAG1) ||
1529         (elf_header_ptr->e_ident[EI_MAG2] != ELFMAG2) ||
1530         (elf_header_ptr->e_ident[EI_MAG3] != ELFMAG3) )
1531    {
1532        _printf("\n[BOOT ERROR] load_elf() : file %s does not use ELF format\n",
1533                pathname );
1534        _exit();
1535    }
1536
1537    // get program header table pointer
1538    unsigned int pht_index = elf_header_ptr->e_phoff;
1539    if( pht_index == 0 )
1540    {
1541        _printf("\n[BOOT ERROR] load_one_elf_file() : file %s "
1542                "does not contain loadable segment\n", pathname );
1543        _exit();
1544    }
1545    Elf32_Phdr* elf_pht_ptr = (Elf32_Phdr*)(boot_elf_buffer + pht_index);
1546
1547    // get number of segments
1548    unsigned int nsegments   = elf_header_ptr->e_phnum;
1549
1550    // Loop on loadable segments in the .elf file
1551    for (seg_id = 0 ; seg_id < nsegments ; seg_id++)
1552    {
1553        if(elf_pht_ptr[seg_id].p_type == PT_LOAD)
1554        {
1555            // Get segment attributes
1556            unsigned int seg_vaddr  = elf_pht_ptr[seg_id].p_vaddr;
1557            unsigned int seg_offset = elf_pht_ptr[seg_id].p_offset;
1558            unsigned int seg_filesz = elf_pht_ptr[seg_id].p_filesz;
1559            unsigned int seg_memsz  = elf_pht_ptr[seg_id].p_memsz;
1560
1561#if BOOT_DEBUG_ELF
1562_printf("\n[BOOT] Segment %d : vaddr = %x / size = %x\n",
1563        seg_id , seg_vaddr , seg_filesz );
1564#endif
1565
1566            if( seg_memsz < seg_filesz )
1567            {
1568                _printf("\n[BOOT ERROR] load_one_elf_file() : segment at vaddr = %x"
1569                        " in file %s has memsize < filesize \n", seg_vaddr, pathname );
1570                _exit();
1571            }
1572
1573            // fill empty space with 0 as required
1574            if( seg_memsz > seg_filesz )
1575            {
1576                unsigned int i; 
1577                for( i = seg_filesz ; i < seg_memsz ; i++ ) 
1578                   boot_elf_buffer[i+seg_offset] = 0;
1579            } 
1580
1581            unsigned int src_vaddr = (unsigned int)boot_elf_buffer + seg_offset;
1582
1583            // search all vsegs matching the virtual address
1584            unsigned int vseg_first;
1585            unsigned int vseg_last;
1586            unsigned int vseg_id;
1587            unsigned int found = 0;
1588            if ( is_kernel )
1589            {
1590                vseg_first = 0;
1591                vseg_last  = header->globals;
1592            }
1593            else
1594            {
1595                vseg_first = vspace[vspace_id].vseg_offset;
1596                vseg_last  = vseg_first + vspace[vspace_id].vsegs;
1597            }
1598
1599            for ( vseg_id = vseg_first ; vseg_id < vseg_last ; vseg_id++ )
1600            {
1601                if ( seg_vaddr == vseg[vseg_id].vbase )  // matching
1602                {
1603                    found = 1;
1604
1605                    // get destination buffer physical address and size
1606                    paddr_t      seg_paddr  = vseg[vseg_id].pbase;
1607                    unsigned int seg_size   = vseg[vseg_id].length;
1608                   
1609#if BOOT_DEBUG_ELF
1610_printf("   loaded into vseg %s at paddr = %l / buffer size = %x\n",
1611        vseg[vseg_id].name , seg_paddr , seg_size );
1612#endif
1613                    // check vseg size
1614                    if ( seg_size < seg_filesz )
1615                    {
1616                        _printf("\n[BOOT ERROR] in load_one_elf_file() : vseg %s "
1617                                "is to small for loadable segment %x in file %s\n",
1618                                vseg[vseg_id].name , seg_vaddr , pathname );
1619                        _exit();
1620                    }
1621
1622                    // copy the segment from boot buffer to destination buffer
1623                    // using DMA channel[0,0,0] if it is available.
1624                    if( NB_DMA_CHANNELS > 0 )
1625                    {
1626                        _dma_physical_copy( 0,                  // DMA in cluster[0,0]
1627                                            0,                  // DMA channel 0
1628                                            (paddr_t)seg_paddr, // destination paddr
1629                                            (paddr_t)src_vaddr, // source paddr
1630                                            seg_filesz );       // size
1631                    }
1632                    else
1633                    {
1634                        _physical_memcpy( (paddr_t)seg_paddr,   // destination paddr
1635                                          (paddr_t)src_vaddr,   // source paddr
1636                                          seg_filesz );         // size
1637                    }
1638                }
1639            }  // end for vsegs in vspace
1640
1641            // check at least one matching vseg
1642            if ( found == 0 )
1643            {
1644                _printf("\n[BOOT ERROR] in load_one_elf_file() : vseg for loadable "
1645                        "segment %x in file %s not found "
1646                        "check consistency between the .py and .ld files\n",
1647                        seg_vaddr, pathname );
1648                _exit();
1649            }
1650        }
1651    }  // end for loadable segments
1652
1653    // close .elf file
1654    _fat_close( fd_id );
1655
1656    _printf("\n[BOOT] File %s loaded at cycle %d\n", 
1657            pathname , _get_proctime() );
1658
1659} // end load_one_elf_file()
1660
1661
1662/////i////////////////////////////////////////////////////////////////////////////////
1663// This function uses the map.bin data structure to load the "kernel.elf" file
1664// as well as the various "application.elf" files into memory.
1665// - The "preloader.elf" file is not loaded, because it has been burned in the ROM.
1666// - The "boot.elf" file is not loaded, because it has been loaded by the preloader.
1667// This function scans all vsegs defined in the map.bin data structure to collect
1668// all .elf files pathnames, and calls the load_one_elf_file() for each .elf file.
1669// As the code can be replicated in several vsegs, the same code can be copied
1670// in one or several clusters by the load_one_elf_file() function.
1671//////////////////////////////////////////////////////////////////////////////////////
1672void boot_elf_load()
1673{
1674    mapping_header_t* header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1675    mapping_vspace_t* vspace = _get_vspace_base( header );
1676    mapping_vseg_t*   vseg   = _get_vseg_base( header );
1677
1678    unsigned int      vspace_id;
1679    unsigned int      vseg_id;
1680    unsigned int      found;
1681
1682    // Scan all global vsegs to find the pathname to the kernel.elf file
1683    found = 0;
1684    for( vseg_id = 0 ; vseg_id < header->globals ; vseg_id++ )
1685    {
1686        if(vseg[vseg_id].type == VSEG_TYPE_ELF) 
1687        {   
1688            found = 1;
1689            break;
1690        }
1691    }
1692
1693    // We need one kernel.elf file
1694    if (found == 0)
1695    {
1696        _printf("\n[BOOT ERROR] boot_elf_load() : kernel.elf file not found\n");
1697        _exit();
1698    }
1699
1700    // Load the kernel
1701    load_one_elf_file( 1,                           // kernel file
1702                       vseg[vseg_id].binpath,       // file pathname
1703                       0 );                         // vspace 0
1704
1705    // loop on the vspaces, scanning all vsegs in the vspace,
1706    // to find the pathname of the .elf file associated to the vspace.
1707    for( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
1708    {
1709        // loop on the private vsegs
1710        unsigned int found = 0;
1711        for (vseg_id = vspace[vspace_id].vseg_offset;
1712             vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs);
1713             vseg_id++) 
1714        {
1715            if(vseg[vseg_id].type == VSEG_TYPE_ELF) 
1716            {   
1717                found = 1;
1718                break;
1719            }
1720        }
1721
1722        // We want one .elf file per vspace
1723        if (found == 0)
1724        {
1725            _printf("\n[BOOT ERROR] boot_elf_load() : "
1726                    ".elf file not found for vspace %s\n", vspace[vspace_id].name );
1727            _exit();
1728        }
1729
1730        load_one_elf_file( 0,                          // not a kernel file
1731                           vseg[vseg_id].binpath,      // file pathname
1732                           vspace_id );                // vspace index
1733
1734    }  // end for vspaces
1735
1736} // end boot_elf_load()
1737
1738////////////////////////////////////////////////////////////////////////////////
1739// This function intializes the external peripherals in cluster_io.
1740////////////////////////////////////////////////////////////////////////////////
1741void boot_peripherals_init() 
1742{
1743    mapping_header_t * header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1744    mapping_cluster_t * cluster = _get_cluster_base(header);
1745    mapping_periph_t * periph   = _get_periph_base(header);
1746    mapping_irq_t * irq         = _get_irq_base(header);
1747
1748    unsigned int periph_id;
1749    unsigned int channel_id;
1750
1751#if BOOT_DEBUG_PERI
1752_printf("\n[BOOT] External peripherals initialisation in cluster[%d,%d]\n",
1753        X_IO , Y_IO );
1754#endif
1755
1756    // get pointer on cluster_io
1757    mapping_cluster_t * cluster_io = &cluster[X_IO * Y_SIZE + Y_IO];
1758
1759    // loop on peripherals
1760    for (periph_id = cluster_io->periph_offset;
1761         periph_id < cluster_io->periph_offset + cluster_io->periphs; 
1762         periph_id++) 
1763    {
1764        unsigned int type       = periph[periph_id].type;
1765        unsigned int subtype    = periph[periph_id].subtype;
1766        unsigned int channels   = periph[periph_id].channels;
1767
1768        switch (type) 
1769        {
1770            case PERIPH_TYPE_IOC:    // vci_block_device component
1771            {
1772                if ( subtype == IOC_SUBTYPE_BDV )
1773                {
1774                    _bdv_init();
1775                }
1776                else if ( subtype == IOC_SUBTYPE_HBA ) 
1777                {
1778                    for (channel_id = 0; channel_id < channels; channel_id++) 
1779                        _hba_init( channel_id );
1780                }
1781                else if ( subtype == IOC_SUBTYPE_SPI ) 
1782                {
1783                    //TODO
1784                }
1785                break;
1786            }
1787            case PERIPH_TYPE_TTY:    // vci_multi_tty component
1788            {
1789                for (channel_id = 0; channel_id < channels; channel_id++) 
1790                {
1791                    _tty_init( channel_id );
1792                }
1793                break;
1794            }
1795            case PERIPH_TYPE_NIC:    // vci_multi_nic component
1796            {
1797                _nic_global_init( 1,      // broadcast accepted
1798                                  1,      // bypass activated
1799                                  0,      // tdm non activated
1800                                  0 );    // tdm period
1801                break;
1802            }
1803            case PERIPH_TYPE_IOB:    // vci_io_bridge component
1804            {
1805                if (GIET_USE_IOMMU) 
1806                {
1807                    // TODO
1808                    // get the iommu page table physical address
1809                    // set IOMMU page table address
1810                    // pseg_base[IOB_IOMMU_PTPR] = ptab_pbase;   
1811                    // activate IOMMU
1812                    // pseg_base[IOB_IOMMU_ACTIVE] = 1;       
1813                }
1814                break;
1815            }
1816            case PERIPH_TYPE_PIC:    // vci_iopic component
1817            {
1818                // scan all IRQs defined in mapping for PIC component,
1819                // and initialises addresses for WTI IRQs
1820                for ( channel_id = periph[periph_id].irq_offset ;
1821                      channel_id < periph[periph_id].irq_offset + 
1822                      periph[periph_id].irqs ; channel_id++ )
1823                {
1824                    unsigned int hwi_id     = irq[channel_id].srcid;   // HWI in PIC
1825                    unsigned int wti_id     = irq[channel_id].dest_id; // WTI in XCU
1826                    unsigned int cluster_xy = irq[channel_id].dest_xy; // XCU coordinates
1827                    unsigned int vaddr;
1828
1829                    _xcu_get_wti_address( wti_id, &vaddr );
1830                    _pic_init( hwi_id, vaddr, cluster_xy ); 
1831
1832#if BOOT_DEBUG_PERI
1833_printf("[BOOT] PIC : hwi_index = %d => wti_index = %d for XCU[%d,%d]\n",
1834        hwi_id , wti_id , cluster_xy >> Y_WIDTH , cluster_xy & ((1<<Y_WIDTH)-1) ); 
1835#endif
1836                }
1837                break;
1838            }
1839        }  // end switch periph type
1840    } // end loop on peripherals
1841} // end boot_peripherals_init()
1842
1843///////////////////////////////////////////////////////////////////////////////////////
1844// This function is executed in parallel by all processors[x][y][0].
1845// It initialises the physical memory allocator in each cluster containing a RAM pseg.
1846///////////////////////////////////////////////////////////////////////////////////////
1847void boot_pmem_init( unsigned int cx,
1848                     unsigned int cy ) 
1849{
1850    mapping_header_t*  header     = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1851    mapping_cluster_t* cluster    = _get_cluster_base(header);
1852    mapping_pseg_t*    pseg       = _get_pseg_base(header);
1853
1854    unsigned int pseg_id;
1855    unsigned int procid     = _get_procid();
1856    unsigned int lpid       = procid & ((1<<P_WIDTH)-1);
1857
1858    if( lpid )
1859    {
1860        _printf("\n[BOOT ERROR] boot_pmem_init() : "
1861        "P[%d][%d][%d] should not execute it\n", cx, cy, lpid );
1862        _exit();
1863    }   
1864
1865    // scan the psegs in local cluster to find  pseg of type RAM
1866    unsigned int found      = 0;
1867    unsigned int cluster_id = cx * Y_SIZE + cy;
1868    unsigned int pseg_min   = cluster[cluster_id].pseg_offset;
1869    unsigned int pseg_max   = pseg_min + cluster[cluster_id].psegs;
1870    for ( pseg_id = pseg_min ; pseg_id < pseg_max ; pseg_id++ )
1871    {
1872        if ( pseg[pseg_id].type == PSEG_TYPE_RAM )
1873        {
1874            unsigned int base = (unsigned int)pseg[pseg_id].base;
1875            unsigned int size = (unsigned int)pseg[pseg_id].length;
1876            _pmem_alloc_init( cx, cy, base, size );
1877            found = 1;
1878
1879#if BOOT_DEBUG_PT
1880_printf("\n[BOOT] pmem allocator initialised in cluster[%d][%d]"
1881        " : base = %x / size = %x\n", cx , cy , base , size );
1882#endif
1883            break;
1884        }
1885    }
1886
1887    if ( found == 0 )
1888    {
1889        _printf("\n[BOOT ERROR] boot_pmem_init() : no RAM in cluster[%d][%d]\n",
1890              cx , cy );
1891        _exit();
1892    }   
1893} // end boot_pmem_init()
1894 
1895/////////////////////////////////////////////////////////////////////////
1896// This function is the entry point of the boot code for all processors.
1897/////////////////////////////////////////////////////////////////////////
1898void boot_init() 
1899{
1900
1901    unsigned int       gpid       = _get_procid();
1902    unsigned int       cx         = gpid >> (Y_WIDTH + P_WIDTH);
1903    unsigned int       cy         = (gpid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1904    unsigned int       lpid       = gpid & ((1 << P_WIDTH) -1);
1905
1906    // Phase ONE : only P[0][0][0] execute it
1907    if ( gpid == 0 )   
1908    {
1909        unsigned int cid;  // index for loops
1910
1911        // initialises the TTY0 spin lock
1912        _spin_lock_init( &_tty0_spin_lock );
1913
1914        _printf("\n[BOOT] P[0,0,0] starts at cycle %d\n", _get_proctime() );
1915
1916        // initialises the FAT
1917        _fat_init( IOC_BOOT_MODE );
1918
1919        _printf("\n[BOOT] FAT initialised at cycle %d\n", _get_proctime() );
1920
1921        // Load the map.bin file into memory
1922        boot_mapping_init();
1923
1924        mapping_header_t*  header     = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1925        mapping_cluster_t* cluster    = _get_cluster_base(header);
1926
1927        _printf("\n[BOOT] Mapping %s loaded at cycle %d\n",
1928                header->name , _get_proctime() );
1929
1930        // initialises the barrier for all clusters containing processors
1931        unsigned int nclusters = 0;
1932        for ( cid = 0 ; cid < X_SIZE*Y_SIZE ; cid++ )
1933        {
1934            if ( cluster[cid].procs ) nclusters++ ;
1935        } 
1936
1937        _simple_barrier_init( &_barrier_all_clusters , nclusters );
1938
1939        // wake up all processors P[x][y][0]
1940        for ( cid = 1 ; cid < X_SIZE*Y_SIZE ; cid++ ) 
1941        {
1942            unsigned int x          = cluster[cid].x;
1943            unsigned int y          = cluster[cid].y;
1944            unsigned int cluster_xy = (x << Y_WIDTH) + y;
1945
1946            if ( cluster[cid].procs ) 
1947            {
1948                unsigned long long paddr = (((unsigned long long)cluster_xy)<<32) +
1949                                           SEG_XCU_BASE + XCU_REG( XCU_WTI_REG , 0 );
1950
1951                _physical_write( paddr , (unsigned int)boot_entry );
1952            }
1953        }
1954
1955        _printf("\n[BOOT] Processors P[x,y,0] start at cycle %d\n", _get_proctime() );
1956    }
1957
1958    // Phase TWO : All processors P[x][y][0] execute it in parallel
1959    if( lpid == 0 )
1960    {
1961        // Initializes physical memory allocator in cluster[cx][cy]
1962        boot_pmem_init( cx , cy );
1963
1964        // Build page table in cluster[cx][cy]
1965        boot_ptab_init( cx , cy );
1966
1967        //////////////////////////////////////////////
1968        _simple_barrier_wait( &_barrier_all_clusters );
1969        //////////////////////////////////////////////
1970
1971        // P[0][0][0] complete page tables with vsegs
1972        // mapped in clusters without processors
1973        if ( gpid == 0 )   
1974        {
1975            // complete page tables initialisation
1976            boot_ptab_extend();
1977
1978            _printf("\n[BOOT] Physical memory allocators and page tables"
1979                    " initialized at cycle %d\n", _get_proctime() );
1980        }
1981
1982        //////////////////////////////////////////////
1983        _simple_barrier_wait( &_barrier_all_clusters );
1984        //////////////////////////////////////////////
1985
1986        // All processors P[x,y,0] activate MMU (using local PTAB)
1987        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0][cx][cy]>>13) );
1988        _set_mmu_mode( 0xF );
1989       
1990        // Each processor P[x,y,0] initialises all schedulers in cluster[x,y]
1991        boot_scheduler_init( cx , cy );
1992
1993        // Each processor P[x][y][0] initialises its CP0_SCHED register
1994        _set_sched( (unsigned int)_schedulers[cx][cy][0] );
1995
1996        //////////////////////////////////////////////
1997        _simple_barrier_wait( &_barrier_all_clusters );
1998        //////////////////////////////////////////////
1999       
2000        // Processor P[0,0,0] completes schedulers with PIC-WTI
2001        // initialises external peripherals and load .elf files.
2002        if ( gpid == 0 ) 
2003        {
2004            // complete schedulers initialisation
2005            boot_pic_wti_init();
2006
2007            _printf("\n[BOOT] Schedulers initialised at cycle %d\n", _get_proctime() );
2008
2009            // initialize non replicated peripherals
2010            boot_peripherals_init();
2011
2012            _printf("\n[BOOT] Peripherals initialised at cycle %d\n", _get_proctime() );
2013
2014            // Loading all .elf files
2015            boot_elf_load();
2016        }
2017
2018        //////////////////////////////////////////////
2019        _simple_barrier_wait( &_barrier_all_clusters );
2020        //////////////////////////////////////////////
2021       
2022        // each processor P[x][y][0] wake up other processors in same cluster
2023        mapping_header_t*  header     = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
2024        mapping_cluster_t* cluster    = _get_cluster_base(header);
2025        unsigned int       cluster_xy = (cx << Y_WIDTH) + cy;
2026        unsigned int       cluster_id = (cx * Y_SIZE) + cy;
2027        unsigned int p;
2028        for ( p = 1 ; p < cluster[cluster_id].procs ; p++ )
2029        {
2030            _xcu_send_wti( cluster_xy , p , (unsigned int)boot_entry );
2031        }
2032
2033        if ( gpid == 0 )    // only P[0][0][0] makes display
2034        _printf("\n[BOOT] All processors start at cycle %d\n", _get_proctime() );
2035    }
2036
2037    // Other processors than P[x][y][0] activate MMU (using local PTAB)
2038    if ( lpid != 0 )
2039    {
2040        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0][cx][cy]>>13) );
2041        _set_mmu_mode( 0xF );
2042    }
2043
2044    // All processors set CP0_SCHED register
2045    _set_sched( (unsigned int)_schedulers[cx][cy][lpid] );
2046
2047    // All processors reset BEV bit in SR to use GIET_VM exception handler
2048    _set_sr( 0 );
2049
2050    // All processors jump to kernel_init
2051    unsigned int kernel_entry = (unsigned int)&kernel_init_vbase;
2052    asm volatile( "jr   %0" ::"r"(kernel_entry) );
2053
2054} // end boot_init()
2055
2056
2057// Local Variables:
2058// tab-width: 4
2059// c-basic-offset: 4
2060// c-file-offsets:((innamespace . 0)(inline-open . 0))
2061// indent-tabs-mode: nil
2062// End:
2063// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
2064
Note: See TracBrowser for help on using the repository browser.