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

Last change on this file since 529 was 527, checked in by alain, 10 years ago

1) Introducing dynamic routing of external IRQs when the platform
contains an IOPIC component.
2) Improving parallel boot for elf files: The FAT access is done by
P[0,0,0] only, but the code replication in all cluster is done
in parallel by all P[x,y,0] processors.

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