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

Last change on this file since 416 was 412, checked in by alain, 10 years ago

Major evolution: the page table initialisation has been
completely redesigned to support both big pages (2 Mbytes)
and small pages (4 Kbytes) for both kernel and user vsegs.

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