source: trunk/tools/bootloader_tsar/boot.c @ 315

Last change on this file since 315 was 296, checked in by alain, 7 years ago

Several modifs in the generic scheduler and in the hal_context to
fix the context switch mechanism.

File size: 38.9 KB
RevLine 
[6]1/*
2 * boot.c - TSAR bootloader implementation.
3 *
4 * Authors :   Alain Greiner / Vu Son  (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
[1]24/****************************************************************************
[6]25 * This file contains the ALMOS-MKH. boot-loader for the TSAR architecture. *
[1]26 *                                                                          *
27 * It supports clusterised shared memory multi-processor architectures,     *
[50]28 * where each processor core is identified by a composite index [cxy,lid]   *
[1]29 * with one physical memory bank per cluster.                               *
30 *                                                                          *
31 * The 'boot.elf' file (containing the boot-loader binary code) is stored   *
[50]32 * on disk and is loaded into memory by core[0,0] (cxy = 0 / lid = 0),      *
33 * and is copied in each other cluter by the local CP0 (lid = 0].           *
[1]34 *                                                                          *
[50]35 * 1) The boot-loader first phase is executed by core[0,0], while           *
[1]36 *    all other cores are waiting in the preloader.                         *
37 *    It does the following tasks:                                          *
[50]38 *      - load into the memory bank of cluster 0 the 'arch_info.bin'        *
[1]39 *        file (containing the hardware architecture description) and the   *
40 *        'kernel.elf' file, at temporary locations,                        *   
41 *      - initializes the 'boot_info_t' structure in cluster(0,0)           *
42 *        (there is 1 'boot_info_t' per cluster), which contains both       *
43 *        global and cluster specific information that will be used for     *
44 *        kernel initialisation.                                            *
45 *      - activate CP0s in all other clusters, using IPIs.                  *
46 *      - wait completion reports from CP0s on a global barrier.            *
47 *                                                                          *
48 * 2) The boot-loader second phase is then executed in parallel by all      *
[50]49 *    CP0s (other than core[0,0]). Each CP0 performs the following tasks:   *
[1]50 *      - copies into the memory bank of the local cluster the 'boot.elf',  *
51 *        the 'arch_info.bin' (at the same addresses as the 'boot.elf' and  *
52 *        the 'arch_info.bin' in the memory bank of the cluster(0,0), and   *
53 *        the kernel image (at address 0x0),                                *
54 *      - initializes the 'boot_info_t' structure of the local cluster,     *
55 *      - activate all other cores in the same cluster (CPi).               *
56 *      - wait local CPi completion reports on a local barrier.             *
57 *      - report completion to bscpu on the global barrier.                 *
58 *                                                                          *
59 * 3) The boot-loader third phase is executed in parallel by all cores.     *
60 *    After passing the global barrier the bscpu:                           *
[50]61 *      - activates the CPi of cluster(0),                                  *
[1]62 *      - blocks on the local barrier waiting for all local CPi to report   *
63 *        completion on the local barrier,                                  *
64 *      - moves the local kernel image from the temporary location to the   *
65 *        address 0x0, (erasing the preloader code).                        *
66 *                                                                          *
67 * 4) All cores have finished the boot phase, they jump to the kern_init()  *
68 *    function (maybe not at the same time).                                *
69 ****************************************************************************/
70
71#include <elf-types.h>
[6]72#include <hal_types.h>
[1]73
[13]74#include <kernel_config.h>
[1]75#include <boot_config.h>
76
77#include <arch_info.h>
78#include <boot_info.h>
79
80#include <boot_utils.h>
81#include <boot_fat32.h>
82#include <boot_bdv_driver.h>
83#include <boot_hba_driver.h>
84#include <boot_tty_driver.h>
85
[6]86/*****************************************************************************
87 *                                 Macros.                             
[1]88 ****************************************************************************/
89
90#define PAGE_ROUND_DOWN(x)  ((x) & (~PPM_PAGE_SIZE -1))
91#define PAGE_ROUND_UP(x)    (((x) + PPM_PAGE_SIZE-1) &   \
92                            (~(PPM_PAGE_SIZE-1)))
93
[6]94/*****************************************************************************
95 *                             Global variables.                           
[1]96 ****************************************************************************/
97
98// synchronization variables.
99
[6]100volatile boot_remote_spinlock_t tty0_lock;       // protect TTY0 access
101volatile boot_remote_barrier_t  global_barrier;  // synchronize CP0 cores
102volatile boot_remote_barrier_t  local_barrier;   // synchronize cores in one cluster
103uint32_t                        active_cp0s_nr;  // number of expected CP0s
104 
105// kernel segments layout variables
[1]106
[296]107uint32_t                        seg_kcode_base;   // kcode segment base address
108uint32_t                        seg_kcode_size;   // kcode segment size (bytes)
109uint32_t                        seg_kdata_base;   // kdata segment base address
110uint32_t                        seg_kdata_size;   // kdata segment size (bytes)
111uint32_t                        seg_kentry_base;  // kcode segment base address
112uint32_t                        seg_kentry_size;  // kcode segment size (bytes)
[279]113
[6]114uint32_t                        kernel_entry;    // kernel entry point
[1]115
[6]116// address used by the WTI to activate remote CP0s
[1]117
[6]118extern void                     boot_entry();    // boot_loader entry point
[1]119
[6]120/*********************************************************************************
121 * This function returns the printable string for each device type
122 ********************************************************************************/
[1]123char * device_type_str( uint32_t dev_type )
124{
[6]125    if     ( dev_type == DEV_TYPE_RAM_SCL ) return "RAM_SCL";
126    else if( dev_type == DEV_TYPE_ROM_SCL ) return "ROM_SCL";
127    else if( dev_type == DEV_TYPE_FBF_SCL ) return "FBF_SCL";
128    else if( dev_type == DEV_TYPE_IOB_TSR ) return "IOB_TSR";
[1]129    else if( dev_type == DEV_TYPE_IOC_BDV ) return "IOC_BDV";
130    else if( dev_type == DEV_TYPE_IOC_HBA ) return "IOC_HBA";
131    else if( dev_type == DEV_TYPE_IOC_SDC ) return "IOC_SDC";
132    else if( dev_type == DEV_TYPE_IOC_SPI ) return "IOC_SPI";
133    else if( dev_type == DEV_TYPE_IOC_RDK ) return "IOC_RDK";
[6]134    else if( dev_type == DEV_TYPE_MMC_TSR ) return "MMC_TSR";
135    else if( dev_type == DEV_TYPE_DMA_SCL ) return "DMA_SCL";
136    else if( dev_type == DEV_TYPE_NIC_CBF ) return "NIC_CBF";
137    else if( dev_type == DEV_TYPE_TIM_SCL ) return "TIM_SCL";
138    else if( dev_type == DEV_TYPE_TXT_TTY ) return "TXT_TTY";
139    else if( dev_type == DEV_TYPE_ICU_XCU ) return "ICU_XCU";
140    else if( dev_type == DEV_TYPE_PIC_TSR ) return "PIC_TSR";
141    else                                    return "undefined";
[1]142}
143
[6]144/************************************************************************************
[1]145 * This function loads the arch_info.bin file into the boot cluster memory.
[6]146 ***********************************************************************************/
[1]147static void boot_archinfo_load()
148{
149    archinfo_header_t* header = (archinfo_header_t*)ARCHINFO_BASE; 
150   
151    // Load file into memory
152    if (boot_fat32_load(ARCHINFO_PATHNAME, ARCHINFO_BASE, ARCHINFO_MAX_SIZE))
153    {
154        boot_printf("\n[BOOT ERROR]: boot_archinfo_load(): "
155                    "<%s> file not found\n",
156                    ARCHINFO_PATHNAME);
157        boot_exit();
158    }
159
160    if (header->signature != ARCHINFO_SIGNATURE)
161    {
162        boot_printf("\n[BOOT_ERROR]: boot_archinfo_load(): "
163                    "<%s> file signature should be %x\n",
164                    ARCHINFO_PATHNAME, ARCHINFO_SIGNATURE);
165        boot_exit();
166    }
167
168#if DEBUG_BOOT_INFO
[6]169boot_printf("\n[BOOT INFO] in %s : file %s loaded at address = %x\n",
170            __FUNCTION__ , ARCHINFO_PATHNAME , ARCHINFO_BASE );
[1]171#endif
172
173} // boot_archinfo_load()
174
[6]175/**************************************************************************************
176 * This function loads the 'kernel.elf' file into the boot cluster memory buffer,
[296]177 * analyzes it, and places the three kcode, kentry, kdata segments at their final
[279]178 * physical adresses (defined the .elf file).       
[6]179 * It set the global variables defining the kernel layout.
180 *************************************************************************************/
[1]181static void boot_kernel_load()
182{
[6]183    Elf32_Ehdr * elf_header;      // pointer on kernel.elf header. 
184    Elf32_Phdr * program_header;  // pointer on kernel.elf program header.
185    uint32_t     phdr_offset;     // program header offset in kernel.elf file.
186    uint32_t     segments_nb;     // number of segments in kernel.elf file.
187    uint32_t     seg_src_addr;    // segment address in kernel.elf file (source).
188    uint32_t     seg_paddr;       // segment local physical address of segment
189    uint32_t     seg_offset;      // segment offset in kernel.elf file
190    uint32_t     seg_filesz;      // segment size (bytes) in kernel.elf file
191    uint32_t     seg_memsz;       // segment size (bytes) in memory image.
192    bool_t       kcode_found;     // kcode segment found.
193    bool_t       kdata_found;     // kdata segment found.
[296]194    bool_t       kentry_found;    // kentry segment found.
[6]195    uint32_t     seg_id;          // iterator for segments loop.
[1]196
[6]197#if DEBUG_BOOT_ELF
198boot_printf("\n[BOOT INFO] %s enters for file %s at cycle %d\n",
199            __FUNCTION__ , KERNEL_PATHNAME , boot_get_proctime() );
200#endif
[1]201
[6]202    // Load kernel.elf file into memory buffer
203    if ( boot_fat32_load(KERNEL_PATHNAME, KERN_BASE, KERN_MAX_SIZE) )
[1]204    {
[6]205        boot_printf("\n[BOOT ERROR] in %s : <%s> file not found\n",
[1]206                    KERNEL_PATHNAME);
207        boot_exit();
208    }
209
[6]210    // get pointer to kernel.elf header 
[1]211    elf_header = (Elf32_Ehdr*)KERN_BASE;
212
[6]213    // check signature
[1]214    if ((elf_header->e_ident[EI_MAG0] != ELFMAG0)   ||
215        (elf_header->e_ident[EI_MAG1] != ELFMAG1)   ||
216        (elf_header->e_ident[EI_MAG2] != ELFMAG2)   ||
217        (elf_header->e_ident[EI_MAG3] != ELFMAG3))
218    {
219        boot_printf("\n[BOOT_ERROR]: boot_kernel_load(): "
220                    "<%s> is not an ELF file\n",
221                    KERNEL_PATHNAME);
222        boot_exit();
223    }
224
[6]225    // Get program header table offset and number of segments
[1]226    phdr_offset     = elf_header->e_phoff;
227    segments_nb     = elf_header->e_phnum;
228
[6]229    // Get program header table pointer
[1]230    program_header  = (Elf32_Phdr*)(KERN_BASE + phdr_offset);
231
[6]232    // loop on segments
[296]233    kcode_found  = false;
234    kdata_found  = false;
235    kentry_found = false;
[1]236    for (seg_id = 0; seg_id < segments_nb; seg_id++) 
237    {
[6]238        if (program_header[seg_id].p_type == PT_LOAD)   // Found one loadable segment
[1]239        {
[6]240            // Get segment attributes.
[1]241            seg_paddr    = program_header[seg_id].p_paddr;   
242            seg_offset   = program_header[seg_id].p_offset;
243            seg_filesz   = program_header[seg_id].p_filesz;
244            seg_memsz    = program_header[seg_id].p_memsz;
245
[6]246            // get segment base address in buffer
[1]247            seg_src_addr = (uint32_t)KERN_BASE + seg_offset;
248
[6]249            // Load segment to its final physical memory address
250            boot_memcpy( (void*)seg_paddr, 
251                         (void*)seg_src_addr, 
252                         seg_filesz );
253
254#if DEBUG_BOOT_ELF
255boot_printf("\n[BOOT INFO] in %s for file %s : found loadable segment\n"
256            "   base = %x / size = %x\n",
257            __FUNCTION__ , KERNEL_PATHNAME , seg_paddr , seg_memsz );
258#endif
259
[1]260            // Fill remaining memory with zero if (filesz < memsz).
[6]261            if( seg_memsz < seg_filesz )
[1]262            {
[6]263                boot_memset( (void*)(seg_paddr + seg_filesz), 0, seg_memsz - seg_filesz);
[1]264            }
265
[279]266            // Note: we suppose that the 'kernel.elf' file contains exactly
[296]267            // three loadable segments ktext, kentry, & kdata:
268            // - the kcode segment is read-only and base == KCODE_BASE
269            // - the kentry segment is read-only and base == KENTRY_BASE
[6]270
[279]271            if( ((program_header[seg_id].p_flags & PF_W) == 0) &&
[296]272                 (program_header[seg_id].p_paddr == KCODE_BASE) )     // kcode segment
[1]273            {
[6]274                if( kcode_found )
275                {
276                    boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
[279]277                                "   two kcode segments found\n",
[6]278                                __FUNCTION__ , KERNEL_PATHNAME );
279                    boot_exit();
280                } 
281
282                kcode_found     = true;
283                seg_kcode_base = seg_paddr;
284                seg_kcode_size = seg_memsz;
[1]285            }
[296]286            else if( program_header[seg_id].p_paddr == KENTRY_BASE ) // kentry segment
[6]287            {
[296]288                if( kentry_found )
[279]289                {
290                    boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
[296]291                                "   two kentry segments found\n",
[279]292                                __FUNCTION__ , KERNEL_PATHNAME );
293                    boot_exit();
294                } 
295
[296]296                kentry_found     = true;
297                seg_kentry_base = seg_paddr;
298                seg_kentry_size = seg_memsz;
[279]299            }
300            else                                                    // kdata segment
301            {
[6]302                if( kdata_found )
303                {
304                    boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
305                                "   two loadable kdata segments found\n",
306                                __FUNCTION__ , KERNEL_PATHNAME );
307                    boot_exit();
308                } 
309
310                kdata_found     = true;
311                seg_kdata_base = seg_paddr;
312                seg_kdata_size = seg_memsz;
313            }
[1]314        }
315    }
316
[6]317    // check kcode & kdata segments found
318    if( kcode_found == false )
319    {
[279]320        boot_printf("\n[BOOT_ERROR] in %s for file %s : seg_kcode not found\n",
[6]321                    __FUNCTION__ , KERNEL_PATHNAME );
322        boot_exit();
323    }
[296]324    if( kentry_found == false )
[279]325    {
[296]326        boot_printf("\n[BOOT_ERROR] in %s for file %s : seg_kentry not found\n",
[279]327                    __FUNCTION__ , KERNEL_PATHNAME );
328        boot_exit();
329    }
[6]330    if( kdata_found == false )
331    {
[279]332        boot_printf("\n[BOOT_ERROR] in %s for file %s : seg_kdata not found\n",
[6]333                    __FUNCTION__ , KERNEL_PATHNAME );
334        boot_exit();
335    }
336
[296]337    // check segments sizes
338    if( seg_kentry_size > KENTRY_MAX_SIZE )
339    {
340        boot_printf("\n[BOOT_ERROR] in %s for file %s : seg_kentry too large\n",
341                    __FUNCTION__ , KERNEL_PATHNAME );
342        boot_exit();
343    }
344
345    if( (seg_kcode_size + seg_kdata_size) > KCODE_MAX_SIZE )
346    {
347        boot_printf("\n[BOOT_ERROR] in %s for file %s : seg_kcode + seg_kdata too large\n",
348                    __FUNCTION__ , KERNEL_PATHNAME );
349    }
350
[6]351    // set entry point
[1]352    kernel_entry = (uint32_t)elf_header->e_entry;
353
[6]354#if DEBUG_BOOT_ELF
[279]355boot_printf("\n[BOOT INFO] %s completed for file %s at cycle %d\n",
[6]356            __FUNCTION__ , KERNEL_PATHNAME , boot_get_proctime() );
357#endif
358
[1]359} // boot_kernel_load()
360
[6]361/*************************************************************************************
362 * This function initializes the  boot_info_t structure for a given cluster.
363 * @ boot_info  : pointer to local boot_info_t structure 
364 * @ cxy        : cluster identifier                   
365 ************************************************************************************/
[1]366static void boot_info_init( boot_info_t * boot_info,
367                            cxy_t         cxy )
368{
[6]369    archinfo_header_t  * header;
[1]370    archinfo_core_t    * core_base;     
371    archinfo_cluster_t * cluster_base; 
372    archinfo_device_t  * device_base;
373    archinfo_irq_t     * irq_base; 
374
375    archinfo_cluster_t * cluster; 
[6]376    archinfo_cluster_t * my_cluster = NULL;   // target cluster
377    archinfo_cluster_t * io_cluster = NULL;   // cluster containing ext. peripherals
378
[1]379    archinfo_core_t    * core;
380    uint32_t             core_id; 
381    archinfo_device_t  * device;
382    uint32_t             device_id;
383    archinfo_irq_t     * irq; 
384    uint32_t             irq_id;
[50]385    uint32_t             end;
[1]386    boot_device_t      * boot_dev; 
387
[6]388    // get pointer on ARCHINFO header  and on the four arch_info arrays
389    header       = (archinfo_header_t*)ARCHINFO_BASE;
390    core_base    = archinfo_get_core_base   (header);
391    cluster_base = archinfo_get_cluster_base(header);
392    device_base  = archinfo_get_device_base (header);
393    irq_base     = archinfo_get_irq_base    (header);
394
[1]395    // Initialize global platform parameters
396    boot_info->x_size       = header->x_size;
397    boot_info->y_size       = header->y_size;
398    boot_info->x_width      = header->x_width;
399    boot_info->y_width      = header->y_width;
400    boot_info->paddr_width  = header->paddr_width;
401    boot_info->io_cxy       = header->io_cxy;
402
[50]403    // Initialize kernel segments from global variables
[296]404    boot_info->kcode_base  = seg_kcode_base;
405    boot_info->kcode_size  = seg_kcode_size;
406    boot_info->kdata_base  = seg_kdata_base;
407    boot_info->kdata_size  = seg_kdata_size;
408    boot_info->kentry_base = seg_kentry_base;
409    boot_info->kentry_size = seg_kentry_size;
[1]410
[6]411    // loop on arch_info clusters to get relevant pointers
[1]412    for (cluster =  cluster_base;
413         cluster < &cluster_base[header->x_size * header->y_size];
414         cluster++)
415    {
[6]416        if( cluster->cxy  == cxy )            my_cluster = cluster;
417        if( cluster->cxy  == header->io_cxy ) io_cluster = cluster;
418    }
[1]419
[6]420    if( my_cluster == NULL ) 
421    {
422        boot_printf("\n[ERROR] in %s : cannot found cluster %x in arch_info\n",
423                    __FUNCTION__ , cxy );
424        boot_exit();
425    }
[1]426
[6]427    if( io_cluster == NULL ) 
428    {
429        boot_printf("\n[ERROR] in %s : cannot found io_cluster %x in arch_info\n",
430                    __FUNCTION__ , header->io_cxy );
431        boot_exit();
432    }
433
[204]434    //////////////////////////////////////////////////////////
435    // initialize the boot_info array of external peripherals
[6]436
[1]437#if DEBUG_BOOT_INFO
[13]438boot_printf("\n[BOOT INFO] %s : external peripherals at cycle %d\n",
[188]439            __FUNCTION__ , boot_get_proctime() );
[1]440#endif
[6]441
442    device_id = 0;
443    for (device = &device_base[io_cluster->device_offset];
444         device < &device_base[io_cluster->device_offset + io_cluster->devices];
445         device++ )
446    {
[188]447        if( device_id >= CONFIG_MAX_EXT_DEV ) 
448        {
449            boot_printf("\n[ERROR] in %s : too much external devices in arch_info\n",
450                        __FUNCTION__ );
451            boot_exit();
452        }
453       
454        // keep only external devices
[6]455        if( (device->type != DEV_TYPE_RAM_SCL) &&
456            (device->type != DEV_TYPE_ICU_XCU) &&
457            (device->type != DEV_TYPE_MMC_TSR) &&
458            (device->type != DEV_TYPE_DMA_SCL) ) 
[1]459        {
[6]460            boot_dev = &boot_info->ext_dev[device_id];
[1]461
[6]462            boot_dev->type     = device->type;
463            boot_dev->base     = device->base;
464            boot_dev->channels = device->channels;
465            boot_dev->param0   = device->arg0;   
466            boot_dev->param1   = device->arg1;   
467            boot_dev->param2   = device->arg2;   
468            boot_dev->param3   = device->arg3;   
469            boot_dev->irqs     = device->irqs;   
470
471            device_id++;
472
[1]473#if DEBUG_BOOT_INFO
[6]474boot_printf("  - %s : base = %l / size = %l / channels = %d / irqs = %d\n",
475            device_type_str( device->type ) , device->base , device->size ,
476            device->channels , device->irqs );   
[1]477#endif
[13]478        }
[6]479   
[188]480        // handle IRQs for PIC
[6]481        if (device->type == DEV_TYPE_PIC_TSR) 
482        {
[188]483            for (irq_id = 0; irq_id < CONFIG_MAX_EXTERNAL_IRQS ; irq_id++)
[6]484            {
485                boot_dev->irq[irq_id].valid  = 0;
486            }
[1]487
[6]488            for (irq = &irq_base[device->irq_offset];
489                 irq < &irq_base[device->irq_offset + device->irqs];
490                 irq++)
491            {
492                boot_dev->irq[irq->port].valid    = 1;
493                boot_dev->irq[irq->port].dev_type = irq->dev_type;
494                boot_dev->irq[irq->port].channel  = irq->channel;
495                boot_dev->irq[irq->port].is_rx    = irq->is_rx;
496
497#if DEBUG_BOOT_INFO
498boot_printf("    . irq_port = %d / source = %s / channel = %d / is_rx = %d\n",
499            irq->port , device_type_str( irq->dev_type ) , irq->channel , irq->is_rx );
500#endif
501            }
[1]502        }
[13]503    }   // end loop on io_cluster peripherals
[1]504
[6]505    // initialize number of external peripherals
506    boot_info->ext_dev_nr = device_id;
507
508    // Initialize cluster specific resources
509    boot_info->cxy  = my_cluster->cxy;
510
511#if DEBUG_BOOT_INFO
[188]512boot_printf("\n[BOOT INFO] %s : cores in cluster %x\n", __FUNCTION__ , cxy );
[6]513#endif
514
[188]515    ////////////////////////////////////////
[6]516    // Initialize array of core descriptors
517    core_id = 0;
518    for (core = &core_base[my_cluster->core_offset];
519         core < &core_base[my_cluster->core_offset + my_cluster->cores];
520         core++ )
521    {
522        boot_info->core[core_id].gid = (gid_t)core->gid;
523        boot_info->core[core_id].lid = (lid_t)core->lid; 
524        boot_info->core[core_id].cxy = (cxy_t)core->cxy;
525
526#if DEBUG_BOOT_INFO
527boot_printf("  - core_gid = %x : cxy = %x / lid = %d\n", 
528            core->gid , core->cxy , core->lid );
529#endif
530        core_id++;
531    }
532
533    // Initialize number of cores in my_cluster
534    boot_info->cores_nr = core_id;
535
[188]536    //////////////////////////////////////////////////////////////////////
537    // initialise boot_info array of internal devices (RAM, ICU, MMC, DMA)
[6]538
539#if DEBUG_BOOT_INFO
[188]540boot_printf("\n[BOOT INFO] %s : internal peripherals in cluster %x\n", __FUNCTION__ , cxy );
[6]541#endif
542
[188]543    device_id = 0;
[6]544    for (device = &device_base[my_cluster->device_offset];
545         device < &device_base[my_cluster->device_offset + my_cluster->devices];
546         device++ )
547    {
[188]548        // keep only internal devices
549        if( (device->type == DEV_TYPE_RAM_SCL) ||
550            (device->type == DEV_TYPE_ICU_XCU) ||
551            (device->type == DEV_TYPE_MMC_TSR) ||
552            (device->type == DEV_TYPE_DMA_SCL) ) 
[6]553        {
[188]554            if (device->type == DEV_TYPE_RAM_SCL)   // RAM
555            {
556                // set number of physical memory pages
557                boot_info->pages_nr   = device->size >> CONFIG_PPM_PAGE_SHIFT;
[6]558
[1]559#if DEBUG_BOOT_INFO
[50]560boot_printf("  - RAM : %x pages\n", boot_info->pages_nr );
[1]561#endif
[188]562            }
563            else                                    // ICU / MMC / DMA
564            {
565                if( device_id >= CONFIG_MAX_INT_DEV ) 
566                {
567                    boot_printf("\n[ERROR] in %s : too much internal devices in cluster %x\n",
568                                __FUNCTION__ , cxy );
569                    boot_exit();
570                }
571       
572                boot_dev = &boot_info->int_dev[device_id];
[13]573
[188]574                boot_dev->type     = device->type;
575                boot_dev->base     = device->base;
576                boot_dev->channels = device->channels;
577                boot_dev->param0   = device->arg0;   
578                boot_dev->param1   = device->arg1;   
579                boot_dev->param2   = device->arg2;   
580                boot_dev->param3   = device->arg3;   
581                boot_dev->irqs     = device->irqs; 
[13]582
[188]583                device_id++;
584
[13]585#if DEBUG_BOOT_INFO
[188]586boot_printf("  - %s : base = %l / size = %l / channels = %d / irqs = %d\n",
587            device_type_str( device->type ) , device->base , device->size ,
588            device->channels , device->irqs );   
[13]589#endif
590
[188]591                // handle IRQs for ICU
592                if (device->type == DEV_TYPE_ICU_XCU) 
593                {
594                    for (irq_id = 0; irq_id < CONFIG_MAX_INTERNAL_IRQS ; irq_id++)
595                    {
596                        boot_dev->irq[irq_id].valid  = 0;
597                    }
[1]598
[188]599                    for (irq = &irq_base[device->irq_offset];
600                         irq < &irq_base[device->irq_offset + device->irqs] ; irq++)
601                    {
602                        boot_dev->irq[irq->port].valid    = 1;
603                        boot_dev->irq[irq->port].dev_type = irq->dev_type;
604                        boot_dev->irq[irq->port].channel  = irq->channel;
605                        boot_dev->irq[irq->port].is_rx    = irq->is_rx;
[1]606
607#if DEBUG_BOOT_INFO
608boot_printf("    . irq_port = %d / source = %s / channel = %d / is_rx = %d\n",
609            irq->port , device_type_str( irq->dev_type ) , irq->channel , irq->is_rx );
610#endif
611
[188]612                    }
613                }
[1]614            }
615        }
[188]616    }  // end loop on local peripherals
[1]617
[204]618    // initialize number of internal peripherals
[188]619    boot_info->int_dev_nr = device_id;
[1]620
[188]621   // Get the top address of the kernel segments
[296]622    end = boot_info->kdata_base + boot_info->kdata_size;
[50]623
[279]624    // compute number of physical pages occupied by the kernel code
[68]625    boot_info->pages_offset = ( (end & CONFIG_PPM_PAGE_MASK) == 0 ) ?
[50]626                 (end >> CONFIG_PPM_PAGE_SHIFT) : (end >> CONFIG_PPM_PAGE_SHIFT) + 1;
627
[296]628    // no reserved sones for TSAR architecture
629    boot_info->rsvd_nr = 0;
[50]630
[6]631    // set boot_info signature
632    boot_info->signature = BOOT_INFO_SIGNATURE;
633
[1]634} // boot_info_init()
635
[6]636/***********************************************************************************
637 * This function check the local boot_info_t structure for a given core.
638 * @ boot_info  : pointer to local 'boot_info_t' structure to be checked.
639 * @ lid        : core local identifier, index the core descriptor table.
640 **********************************************************************************/
[1]641static void boot_check_core( boot_info_t * boot_info, 
642                             lid_t         lid)
643{
644    gid_t         gid;        // global hardware identifier of this core
645    boot_core_t * this;       // BOOT_INFO core descriptor of this core. 
646
647    // Get core hardware identifier
648    gid = (gid_t)boot_get_procid();
649
650    // get pointer on core descriptor
651    this = &boot_info->core[lid];
652
653    if ( (this->gid != gid) ||  (this->cxy != boot_info->cxy) )
654    {
655        boot_printf("\n[BOOT ERROR] in boot_check_core() :\n"
656                    " - boot_info cxy = %x\n"
657                    " - boot_info lid = %d\n"
658                    " - boot_info gid = %x\n"
659                    " - actual    gid = %x\n",
660                    this->cxy , this->lid , this->gid , gid );
661        boot_exit();
662    }
663
664} // boot_check_core()
665
[6]666/*********************************************************************************
667 * This function is called by CP0 in cluster(0,0) to activate all other CP0s.
[1]668 * It returns the number of CP0s actually activated.
[6]669 ********************************************************************************/
670static uint32_t boot_wake_all_cp0s()
[1]671{
[6]672    archinfo_header_t*  header;         // Pointer on ARCHINFO header
673    archinfo_cluster_t* cluster_base;   // Pointer on ARCHINFO clusters base
674    archinfo_cluster_t* cluster;        // Iterator for loop on clusters
675    archinfo_device_t*  device_base;    // Pointer on ARCHINFO devices base
676    archinfo_device_t*  device;         // Iterator for loop on devices
677    uint32_t            cp0_nb = 0;     // CP0s counter
[1]678
679    header       = (archinfo_header_t*)ARCHINFO_BASE;
680    cluster_base = archinfo_get_cluster_base(header);
681    device_base  = archinfo_get_device_base (header); 
682
683    // loop on all clusters
684    for (cluster = cluster_base;
685         cluster < &cluster_base[header->x_size * header->y_size];
686         cluster++)
687    {
688        // Skip boot cluster.
689        if (cluster->cxy == BOOT_CORE_CXY)
690            continue;
691           
692        // Skip clusters without core (thus without CP0).
693        if (cluster->cores == 0)
694            continue;
695
696        // Skip clusters without device (thus without XICU).
697        if (cluster->devices == 0)
698            continue;
699
[6]700        // search XICU device associated to CP0, and send a WTI to activate it
[1]701        for (device = &device_base[cluster->device_offset];
702             device < &device_base[cluster->device_offset + cluster->devices];
703             device++)
704        {
[6]705            if (device->type == DEV_TYPE_ICU_XCU)
[1]706            {
[6]707
708#if DEBUG_BOOT_WAKUP
[296]709boot_printf("\n[BOOT] core[%x,0] activated at cycle %d\n",
[6]710            cluster->cxy , boot_get_proctime );
711#endif
712
[1]713                boot_remote_sw((xptr_t)device->base, (uint32_t)boot_entry);
714                cp0_nb++;
715            }
716        }
717    }
718    return cp0_nb;
719
720} // boot_wake_cp0()
721
[6]722/*********************************************************************************
[188]723 * This function is called by all CP0 to activate the other CPi cores.
724 * @ boot_info  : pointer to local 'boot_info_t' structure.
[6]725 *********************************************************************************/
726static void boot_wake_local_cores(boot_info_t * boot_info)
[1]727{
[188]728    unsigned int     core_id;       
[1]729
[188]730    // get pointer on XCU device descriptor in boot_info
731    boot_device_t *  xcu = &boot_info->int_dev[0];
[13]732 
733    // loop on cores
734    for (core_id = 1; core_id < boot_info->cores_nr; core_id++)
[1]735    {
[6]736
737#if DEBUG_BOOT_WAKUP
[296]738boot_printf("\n[BOOT] core[%x,%d] activated at cycle %d\n",
[6]739             boot_info->cxy , core_id , boot_get_proctime() );
740#endif
[188]741        // send an IPI
742        boot_remote_sw( (xptr_t)(xcu->base + (core_id << 2)) , (uint32_t)boot_entry ); 
[1]743    }
744} // boot_wake_local_cores()
745
746
[6]747/*********************************************************************************
[1]748 * This main function of the boot-loader is called by the  boot_entry() 
749 * function, and executed by all cores.
750 * The arguments values are computed by the boot_entry code.
[6]751 * @ lid    : core local identifier,
[1]752 * @ cxy    : cluster identifier,
[6]753 *********************************************************************************/
[1]754void boot_loader( lid_t lid, 
755                  cxy_t cxy )
756{
[6]757    boot_info_t * boot_info;       // pointer on local boot_info_t structure
[1]758
759    if (lid == 0) 
760    {
[6]761        /****************************************************
762         * PHASE A : only CP0 in boot cluster executes it
763         ***************************************************/
[1]764        if (cxy == BOOT_CORE_CXY)
765        {
[296]766            boot_printf("\n[BOOT] core[%x,%d] enters at cycle %d\n",
[6]767                        cxy , lid , boot_get_proctime() );
[1]768
769            // Initialize IOC driver
770            if      (USE_IOC_BDV) boot_bdv_init();
771            else if (USE_IOC_HBA) boot_hba_init();
[6]772            // else if (USE_IOC_SDC) boot_sdc_init();
773            // else if (USE_IOC_SPI) boot_spi_init();
[1]774            else if (!USE_IOC_RDK)
775            {
[6]776                boot_printf("\n[BOOT ERROR] in %s : no IOC driver\n");
[1]777                boot_exit();
778            }
779
[6]780            // Initialize FAT32.
[1]781            boot_fat32_init();
782
[6]783            // Load the 'kernel.elf' file into memory from IOC, and set   
784            // the global variables defining the kernel layout     
785            boot_kernel_load();
786
[296]787            boot_printf("\n[BOOT] core[%x,%d] loaded kernel at cycle %d\n",
[6]788                        cxy , lid , boot_get_proctime() );
789
[1]790            // Load the arch_info.bin file into memory.
791            boot_archinfo_load();
792
[6]793            // Get local boot_info_t structure base address.
[1]794            // It is the first structure in the .kdata segment.
[6]795            boot_info = (boot_info_t *)seg_kdata_base;
[1]796
[6]797            // Initialize local boot_info_t structure.
798            boot_info_init( boot_info , cxy );
799
800            // check boot_info signature
[1]801            if (boot_info->signature != BOOT_INFO_SIGNATURE)
802            {
[296]803                boot_printf("\n[BOOT ERROR] in %s reported by core[%x,%d]\n"
[6]804                            "  illegal boot_info signature / should be %x\n",
805                            __FUNCTION__ , cxy , lid , BOOT_INFO_SIGNATURE );
[1]806                boot_exit();
807            }
808
[296]809            boot_printf("\n[BOOT] core[%x,%d] loaded boot_info at cycle %d\n",
[6]810                        cxy , lid , boot_get_proctime() );
[1]811
812            // Check core information.
813            boot_check_core(boot_info, lid);
814
[6]815            // Activate other CP0s / get number of active CP0s
816            active_cp0s_nr = boot_wake_all_cp0s() + 1;
[1]817
[6]818            // Wait until all clusters (i.e all CP0s) ready to enter kernel.
819            boot_remote_barrier( XPTR( BOOT_CORE_CXY , &global_barrier ) ,
820                                 active_cp0s_nr );
[1]821
[6]822            // activate other local cores
823            boot_wake_local_cores( boot_info );
[1]824
[296]825// display address extensions
826uint32_t cp2_data_ext;
827uint32_t cp2_ins_ext;
828asm volatile( "mfc2   %0,  $24" : "=&r" (cp2_data_ext) );
829asm volatile( "mfc2   %0,  $25" : "=&r" (cp2_ins_ext) );
830boot_printf("\n[BOOT] core[%x,%d] CP2_DATA_EXT = %x / CP2_INS_EXT = %x\n",
831            cxy , lid , cp2_data_ext , cp2_ins_ext );
832
[6]833            // Wait until all local cores in cluster ready
834            boot_remote_barrier( XPTR( cxy , &local_barrier ) , 
835                                 boot_info->cores_nr );
[1]836        }
[6]837        /******************************************************************
838         * PHASE B : all CP0s other than CP0 in boot cluster execute it
839         *****************************************************************/
[1]840        else
841        {
[6]842            // at this point, all INSTRUCTION address extension registers
843            // point on cluster(0,0), but the DATA extension registers point
844            // already on the local cluster to use the local stack.
845            // To access the bootloader global variables we must first copy
846            // the boot code (data and instructions) in the local cluster.
847            boot_remote_memcpy( XPTR( cxy           , BOOT_BASE ),
848                                XPTR( BOOT_CORE_CXY , BOOT_BASE ),
849                                BOOT_MAX_SIZE );
[1]850
[6]851            // from now, it is safe to refer to the boot code global variables
[296]852            boot_printf("\n[BOOT] core[%x,%d] replicated boot code at cycle %d\n",
[6]853                        cxy , lid , boot_get_proctime() );
[1]854
[296]855                        // switch to the INSTRUCTION local memory space, to avoid contention.
[1]856            asm volatile("mtc2  %0, $25" :: "r"(cxy));
857
[6]858            // Copy the arch_info.bin file into the local memory.
[1]859            boot_remote_memcpy(XPTR(cxy,           ARCHINFO_BASE),
860                               XPTR(BOOT_CORE_CXY, ARCHINFO_BASE),
[6]861                               ARCHINFO_MAX_SIZE );
[1]862
[296]863            boot_printf("\n[BOOT] core[%x,%d] replicated arch_info at cycle %d\n",
[6]864                        cxy , lid , boot_get_proctime() );
[1]865
[6]866            // Copy the kcode segment into local memory
867            boot_remote_memcpy( XPTR( cxy           , seg_kcode_base ),
868                                XPTR( BOOT_CORE_CXY , seg_kcode_base ),
869                                seg_kcode_size );
[1]870
[6]871            // Copy the kdata segment into local memory
872            boot_remote_memcpy( XPTR( cxy           , seg_kdata_base ),
873                                XPTR( BOOT_CORE_CXY , seg_kdata_base ),
874                                seg_kdata_size );
875
[296]876            boot_printf("\n[BOOT] core[%x,%d] replicated kernel code at cycle %d\n",
[6]877                        cxy , lid , boot_get_proctime() );
878
879            // Get local boot_info_t structure base address.
880            boot_info = (boot_info_t*)seg_kdata_base;
881
[1]882            // Initialize local boot_info_t structure.
[6]883            boot_info_init( boot_info , cxy );
[1]884
885            // Check core information.
[6]886            boot_check_core( boot_info , lid );
[1]887
[6]888            // get number of active clusters from BOOT_CORE cluster
889            uint32_t count = boot_remote_lw( XPTR( BOOT_CORE_CXY , &active_cp0s_nr ) );
[1]890
[6]891            // Wait until all clusters (i.e all CP0s) ready to enter kernel
892            boot_remote_barrier( XPTR( BOOT_CORE_CXY , &global_barrier ) , count );
[1]893
[6]894            // activate other local cores
895            boot_wake_local_cores( boot_info );
896
[296]897// display address extensions
898uint32_t cp2_data_ext;
899uint32_t cp2_ins_ext;
900asm volatile( "mfc2   %0,  $24" : "=&r" (cp2_data_ext) );
901asm volatile( "mfc2   %0,  $25" : "=&r" (cp2_ins_ext) );
902boot_printf("\n[BOOT] core[%x,%d] CP2_DATA_EXT = %x / CP2_INS_EXT = %x\n",
903            cxy , lid , cp2_data_ext , cp2_ins_ext );
904
[6]905            // Wait until all local cores in cluster ready
906            boot_remote_barrier( XPTR( cxy , &local_barrier ) , 
907                                 boot_info->cores_nr );
[1]908        }
909    }
910    else
911    {
912        /***************************************************************
[6]913         * PHASE C: all non CP0 cores in all clusters execute it
[1]914         **************************************************************/
915
[6]916        // Switch to the INSTRUCTIONS local memory space
917        // to avoid contention at the boot cluster.
918        asm volatile("mtc2  %0, $25" :: "r"(cxy));
[1]919
[6]920        // Get local boot_info_t structure base address.
921        boot_info = (boot_info_t *)seg_kdata_base;
[1]922
[6]923        // Check core information
924        boot_check_core(boot_info, lid);
[1]925
[296]926// display address extensions
927uint32_t cp2_data_ext;
928uint32_t cp2_ins_ext;
929asm volatile( "mfc2   %0,  $24" : "=&r" (cp2_data_ext) );
930asm volatile( "mfc2   %0,  $25" : "=&r" (cp2_ins_ext) );
931boot_printf("\n[BOOT] core[%x,%d] CP2_DATA_EXT = %x / CP2_INS_EXT = %x\n",
932            cxy , lid , cp2_data_ext , cp2_ins_ext );
933
[6]934        // Wait until all local cores in cluster ready
935        boot_remote_barrier( XPTR( cxy , &local_barrier ) , boot_info->cores_nr );
[1]936    }
937
[13]938    // Ech core compute stack pointer to the kernel idle-thread descriptor.
939    // The array of idle-thread descriptors is allocated in the kdata segment,
940    // just after the boot_info structure
[1]941
[13]942    uint32_t sp;
943    uint32_t base;
944    uint32_t offset = sizeof( boot_info_t );
945    uint32_t pmask  = CONFIG_PPM_PAGE_MASK;
946    uint32_t psize  = CONFIG_PPM_PAGE_SIZE;
947
[296]948
[13]949    // compute base address of idle thread descriptors array
950    if( offset & pmask ) base = seg_kdata_base + (offset & ~pmask) + psize;
951    else                 base = seg_kdata_base + offset;
952
953    // compute stack pointer
954    sp = base + ((lid + 1) * CONFIG_THREAD_DESC_SIZE) - 16;
955
956    // Each cores initialise stack pointer,
[6]957    // reset the BEV bit in status register,
958    // register "boot_info" argument in a0,
959    // and jump to kernel_entry.
960    asm volatile( "mfc0  $27,  $12           \n"
961                  "lui   $26,  0xFFBF        \n"
962                  "ori   $26,  $26,  0xFFFF  \n"
963                  "and   $27,  $27,  $26     \n"
[296]964                  "mtc0  $27,  $12           \n"
[6]965                  "move  $4,   %0            \n"
966                  "move  $29,  %1            \n"
967                  "jr    %2                  \n"
[13]968                  :: "r"(boot_info) , "r"(sp) , "r"(kernel_entry) );
[6]969
[1]970} // boot_loader()
Note: See TracBrowser for help on using the repository browser.