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

Last change on this file since 449 was 436, checked in by alain, 10 years ago

Introducing dynamic allocation of peripheral channel (for TIM, TTY, CMA, NIC)

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