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

Last change on this file since 79 was 68, checked in by alain, 7 years ago

Fix bug in kernel_init, and reduce size of remote_fifo.

File size: 36.8 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
[6]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                        kernel_entry;    // kernel entry point
[1]112
[6]113// address used by the WTI to activate remote CP0s
[1]114
[6]115extern void                     boot_entry();    // boot_loader entry point
[1]116
[6]117/*********************************************************************************
118 * This function returns the printable string for each device type
119 ********************************************************************************/
[1]120char * device_type_str( uint32_t dev_type )
121{
[6]122    if     ( dev_type == DEV_TYPE_RAM_SCL ) return "RAM_SCL";
123    else if( dev_type == DEV_TYPE_ROM_SCL ) return "ROM_SCL";
124    else if( dev_type == DEV_TYPE_FBF_SCL ) return "FBF_SCL";
125    else if( dev_type == DEV_TYPE_IOB_TSR ) return "IOB_TSR";
[1]126    else if( dev_type == DEV_TYPE_IOC_BDV ) return "IOC_BDV";
127    else if( dev_type == DEV_TYPE_IOC_HBA ) return "IOC_HBA";
128    else if( dev_type == DEV_TYPE_IOC_SDC ) return "IOC_SDC";
129    else if( dev_type == DEV_TYPE_IOC_SPI ) return "IOC_SPI";
130    else if( dev_type == DEV_TYPE_IOC_RDK ) return "IOC_RDK";
[6]131    else if( dev_type == DEV_TYPE_MMC_TSR ) return "MMC_TSR";
132    else if( dev_type == DEV_TYPE_DMA_SCL ) return "DMA_SCL";
133    else if( dev_type == DEV_TYPE_NIC_CBF ) return "NIC_CBF";
134    else if( dev_type == DEV_TYPE_TIM_SCL ) return "TIM_SCL";
135    else if( dev_type == DEV_TYPE_TXT_TTY ) return "TXT_TTY";
136    else if( dev_type == DEV_TYPE_ICU_XCU ) return "ICU_XCU";
137    else if( dev_type == DEV_TYPE_PIC_TSR ) return "PIC_TSR";
138    else                                    return "undefined";
[1]139}
140
[6]141/************************************************************************************
[1]142 * This function loads the arch_info.bin file into the boot cluster memory.
[6]143 ***********************************************************************************/
[1]144static void boot_archinfo_load()
145{
146    archinfo_header_t* header = (archinfo_header_t*)ARCHINFO_BASE; 
147   
148    // Load file into memory
149    if (boot_fat32_load(ARCHINFO_PATHNAME, ARCHINFO_BASE, ARCHINFO_MAX_SIZE))
150    {
151        boot_printf("\n[BOOT ERROR]: boot_archinfo_load(): "
152                    "<%s> file not found\n",
153                    ARCHINFO_PATHNAME);
154        boot_exit();
155    }
156
157    if (header->signature != ARCHINFO_SIGNATURE)
158    {
159        boot_printf("\n[BOOT_ERROR]: boot_archinfo_load(): "
160                    "<%s> file signature should be %x\n",
161                    ARCHINFO_PATHNAME, ARCHINFO_SIGNATURE);
162        boot_exit();
163    }
164
165#if DEBUG_BOOT_INFO
[6]166boot_printf("\n[BOOT INFO] in %s : file %s loaded at address = %x\n",
167            __FUNCTION__ , ARCHINFO_PATHNAME , ARCHINFO_BASE );
[1]168#endif
169
170} // boot_archinfo_load()
171
[6]172/**************************************************************************************
173 * This function loads the 'kernel.elf' file into the boot cluster memory buffer,
174 * analyzes it, and places the the two seg_kcode & seg_kdata segments at their final
175 * physical adresses (just after the preloader zone).       
176 * It set the global variables defining the kernel layout.
177 *************************************************************************************/
[1]178static void boot_kernel_load()
179{
[6]180    Elf32_Ehdr * elf_header;      // pointer on kernel.elf header. 
181    Elf32_Phdr * program_header;  // pointer on kernel.elf program header.
182    uint32_t     phdr_offset;     // program header offset in kernel.elf file.
183    uint32_t     segments_nb;     // number of segments in kernel.elf file.
184    uint32_t     seg_src_addr;    // segment address in kernel.elf file (source).
185    uint32_t     seg_paddr;       // segment local physical address of segment
186    uint32_t     seg_offset;      // segment offset in kernel.elf file
187    uint32_t     seg_filesz;      // segment size (bytes) in kernel.elf file
188    uint32_t     seg_memsz;       // segment size (bytes) in memory image.
189    bool_t       kcode_found;     // kcode segment found.
190    bool_t       kdata_found;     // kdata segment found.
191    uint32_t     seg_id;          // iterator for segments loop.
[1]192
[6]193#if DEBUG_BOOT_ELF
194boot_printf("\n[BOOT INFO] %s enters for file %s at cycle %d\n",
195            __FUNCTION__ , KERNEL_PATHNAME , boot_get_proctime() );
196#endif
[1]197
[6]198    // Load kernel.elf file into memory buffer
199    if ( boot_fat32_load(KERNEL_PATHNAME, KERN_BASE, KERN_MAX_SIZE) )
[1]200    {
[6]201        boot_printf("\n[BOOT ERROR] in %s : <%s> file not found\n",
[1]202                    KERNEL_PATHNAME);
203        boot_exit();
204    }
205
[6]206    // get pointer to kernel.elf header 
[1]207    elf_header = (Elf32_Ehdr*)KERN_BASE;
208
[6]209    // check signature
[1]210    if ((elf_header->e_ident[EI_MAG0] != ELFMAG0)   ||
211        (elf_header->e_ident[EI_MAG1] != ELFMAG1)   ||
212        (elf_header->e_ident[EI_MAG2] != ELFMAG2)   ||
213        (elf_header->e_ident[EI_MAG3] != ELFMAG3))
214    {
215        boot_printf("\n[BOOT_ERROR]: boot_kernel_load(): "
216                    "<%s> is not an ELF file\n",
217                    KERNEL_PATHNAME);
218        boot_exit();
219    }
220
[6]221    // Get program header table offset and number of segments
[1]222    phdr_offset     = elf_header->e_phoff;
223    segments_nb     = elf_header->e_phnum;
224
[6]225    // Get program header table pointer
[1]226    program_header  = (Elf32_Phdr*)(KERN_BASE + phdr_offset);
227
[6]228    // loop on segments
229    kcode_found = false;
230    kdata_found = false;
[1]231    for (seg_id = 0; seg_id < segments_nb; seg_id++) 
232    {
[6]233        if (program_header[seg_id].p_type == PT_LOAD)   // Found one loadable segment
[1]234        {
[6]235            // Get segment attributes.
[1]236            seg_paddr    = program_header[seg_id].p_paddr;   
237            seg_offset   = program_header[seg_id].p_offset;
238            seg_filesz   = program_header[seg_id].p_filesz;
239            seg_memsz    = program_header[seg_id].p_memsz;
240
[6]241            // get segment base address in buffer
[1]242            seg_src_addr = (uint32_t)KERN_BASE + seg_offset;
243
[6]244            // Load segment to its final physical memory address
245            boot_memcpy( (void*)seg_paddr, 
246                         (void*)seg_src_addr, 
247                         seg_filesz );
248
249#if DEBUG_BOOT_ELF
250boot_printf("\n[BOOT INFO] in %s for file %s : found loadable segment\n"
251            "   base = %x / size = %x\n",
252            __FUNCTION__ , KERNEL_PATHNAME , seg_paddr , seg_memsz );
253#endif
254
[1]255            // Fill remaining memory with zero if (filesz < memsz).
[6]256            if( seg_memsz < seg_filesz )
[1]257            {
[6]258                boot_memset( (void*)(seg_paddr + seg_filesz), 0, seg_memsz - seg_filesz);
[1]259            }
260
[6]261            // Note: we suppose that the 'kernel.elf' file contains only 2
262            // loadable segments ktext & kdata and that the main
263            // difference between these two is the WRITE permission: ktext
264            // contains read-only instructions and read_only data,
265            // while kdata contains writable data.
266
267            if ((program_header[seg_id].p_flags & PF_W) == 0)  // kcode segment
[1]268            {
[6]269                if( kcode_found )
270                {
271                    boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
272                                "   two loadable kcode segments found\n",
273                                __FUNCTION__ , KERNEL_PATHNAME );
274                    boot_exit();
275                } 
276
277                kcode_found     = true;
278                seg_kcode_base = seg_paddr;
279                seg_kcode_size = seg_memsz;
[1]280            }
[6]281            else                                               // kdata segment
282            {
283                if( kdata_found )
284                {
285                    boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
286                                "   two loadable kdata segments found\n",
287                                __FUNCTION__ , KERNEL_PATHNAME );
288                    boot_exit();
289                } 
290
291                kdata_found     = true;
292                seg_kdata_base = seg_paddr;
293                seg_kdata_size = seg_memsz;
294            }
[1]295        }
296    }
297
[6]298    // check kcode & kdata segments found
299    if( kcode_found == false )
300    {
301        boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
302                    "   kcode segment not found\n",
303                    __FUNCTION__ , KERNEL_PATHNAME );
304        boot_exit();
305    }
306    if( kdata_found == false )
307    {
308        boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
309                    "   kdata segment not found\n",
310                    __FUNCTION__ , KERNEL_PATHNAME );
311        boot_exit();
312    }
313
314    // set entry point
[1]315    kernel_entry = (uint32_t)elf_header->e_entry;
316
[6]317#if DEBUG_BOOT_ELF
318boot_printf("\n[BOOT INFO] %s successfully completed for file %s at cycle %d\n",
319            __FUNCTION__ , KERNEL_PATHNAME , boot_get_proctime() );
320#endif
321
[1]322} // boot_kernel_load()
323
[6]324/*************************************************************************************
325 * This function initializes the  boot_info_t structure for a given cluster.
326 * @ boot_info  : pointer to local boot_info_t structure 
327 * @ cxy        : cluster identifier                   
328 ************************************************************************************/
[1]329static void boot_info_init( boot_info_t * boot_info,
330                            cxy_t         cxy )
331{
[6]332    archinfo_header_t  * header;
[1]333    archinfo_core_t    * core_base;     
334    archinfo_cluster_t * cluster_base; 
335    archinfo_device_t  * device_base;
336    archinfo_irq_t     * irq_base; 
337
338    archinfo_cluster_t * cluster; 
[6]339    archinfo_cluster_t * my_cluster = NULL;   // target cluster
340    archinfo_cluster_t * io_cluster = NULL;   // cluster containing ext. peripherals
341
[1]342    archinfo_core_t    * core;
343    uint32_t             core_id; 
344    archinfo_device_t  * device;
345    uint32_t             device_id;
346    archinfo_irq_t     * irq; 
347    uint32_t             irq_id;
[50]348    uint32_t             end;
349    uint32_t             rsvd_pages; 
[1]350    boot_device_t      * boot_dev; 
351
[6]352    // get pointer on ARCHINFO header  and on the four arch_info arrays
353    header       = (archinfo_header_t*)ARCHINFO_BASE;
354    core_base    = archinfo_get_core_base   (header);
355    cluster_base = archinfo_get_cluster_base(header);
356    device_base  = archinfo_get_device_base (header);
357    irq_base     = archinfo_get_irq_base    (header);
358
[1]359    // Initialize global platform parameters
360    boot_info->x_size       = header->x_size;
361    boot_info->y_size       = header->y_size;
362    boot_info->x_width      = header->x_width;
363    boot_info->y_width      = header->y_width;
364    boot_info->paddr_width  = header->paddr_width;
365    boot_info->io_cxy       = header->io_cxy;
366
[50]367    // Initialize kernel segments from global variables
[6]368    boot_info->kernel_code_start = seg_kcode_base;
369    boot_info->kernel_code_end   = seg_kcode_base + seg_kcode_size;
370    boot_info->kernel_data_start = seg_kdata_base;
371    boot_info->kernel_data_end   = seg_kdata_base + seg_kdata_size;
[1]372
[6]373    // loop on arch_info clusters to get relevant pointers
[1]374    for (cluster =  cluster_base;
375         cluster < &cluster_base[header->x_size * header->y_size];
376         cluster++)
377    {
[6]378        if( cluster->cxy  == cxy )            my_cluster = cluster;
379        if( cluster->cxy  == header->io_cxy ) io_cluster = cluster;
380    }
[1]381
[6]382    if( my_cluster == NULL ) 
383    {
384        boot_printf("\n[ERROR] in %s : cannot found cluster %x in arch_info\n",
385                    __FUNCTION__ , cxy );
386        boot_exit();
387    }
[1]388
[6]389    if( io_cluster == NULL ) 
390    {
391        boot_printf("\n[ERROR] in %s : cannot found io_cluster %x in arch_info\n",
392                    __FUNCTION__ , header->io_cxy );
393        boot_exit();
394    }
395
[13]396    // loop on arch-info peripherals in io_cluster,
[6]397    // to initialize the boot_info array of external peripherals
398
[1]399#if DEBUG_BOOT_INFO
[13]400boot_printf("\n[BOOT INFO] %s : external peripherals at cycle %d\n",
401            __FUNCTION__ , cxy , boot_get_proctime() );
[1]402#endif
[6]403
404    device_id = 0;
405    for (device = &device_base[io_cluster->device_offset];
406         device < &device_base[io_cluster->device_offset + io_cluster->devices];
407         device++ )
408    {
409        // initialise one entry for each external peripheral
410        if( (device->type != DEV_TYPE_RAM_SCL) &&
411            (device->type != DEV_TYPE_ICU_XCU) &&
412            (device->type != DEV_TYPE_MMC_TSR) &&
413            (device->type != DEV_TYPE_DMA_SCL) ) 
[1]414        {
[6]415            boot_dev = &boot_info->ext_dev[device_id];
[1]416
[6]417            boot_dev->type     = device->type;
418            boot_dev->base     = device->base;
419            boot_dev->channels = device->channels;
420            boot_dev->param0   = device->arg0;   
421            boot_dev->param1   = device->arg1;   
422            boot_dev->param2   = device->arg2;   
423            boot_dev->param3   = device->arg3;   
424            boot_dev->irqs     = device->irqs;   
425
426            device_id++;
427
[1]428#if DEBUG_BOOT_INFO
[6]429boot_printf("  - %s : base = %l / size = %l / channels = %d / irqs = %d\n",
430            device_type_str( device->type ) , device->base , device->size ,
431            device->channels , device->irqs );   
[1]432#endif
[13]433        }
[6]434   
435        // Initialize array of irq descriptors for PIC
436        if (device->type == DEV_TYPE_PIC_TSR) 
437        {
438            for (irq_id = 0; irq_id < CONFIG_MAX_IRQS_PER_PIC; irq_id++)
439            {
440                boot_dev->irq[irq_id].valid  = 0;
441            }
[1]442
[6]443            for (irq = &irq_base[device->irq_offset];
444                 irq < &irq_base[device->irq_offset + device->irqs];
445                 irq++)
446            {
447                boot_dev->irq[irq->port].valid    = 1;
448                boot_dev->irq[irq->port].dev_type = irq->dev_type;
449                boot_dev->irq[irq->port].channel  = irq->channel;
450                boot_dev->irq[irq->port].is_rx    = irq->is_rx;
451
452#if DEBUG_BOOT_INFO
453boot_printf("    . irq_port = %d / source = %s / channel = %d / is_rx = %d\n",
454            irq->port , device_type_str( irq->dev_type ) , irq->channel , irq->is_rx );
455#endif
456            }
[1]457        }
[13]458    }   // end loop on io_cluster peripherals
[1]459
[6]460    // initialize number of external peripherals
461    boot_info->ext_dev_nr = device_id;
462
463    // Initialize cluster specific resources
464    boot_info->cxy  = my_cluster->cxy;
465
466#if DEBUG_BOOT_INFO
467boot_printf("\n[BOOT INFO] %s : cores in cluster %x\n", __FUNCTION__ );
468#endif
469
470    // Initialize array of core descriptors
471    core_id = 0;
472    for (core = &core_base[my_cluster->core_offset];
473         core < &core_base[my_cluster->core_offset + my_cluster->cores];
474         core++ )
475    {
476        boot_info->core[core_id].gid = (gid_t)core->gid;
477        boot_info->core[core_id].lid = (lid_t)core->lid; 
478        boot_info->core[core_id].cxy = (cxy_t)core->cxy;
479
480#if DEBUG_BOOT_INFO
481boot_printf("  - core_gid = %x : cxy = %x / lid = %d\n", 
482            core->gid , core->cxy , core->lid );
483#endif
484        core_id++;
485    }
486
487    // Initialize number of cores in my_cluster
488    boot_info->cores_nr = core_id;
489
[13]490    // initialise internal devices (RAM, XCU, MMC, DMA)
491    // set default values, then scan all local devices
[6]492
493#if DEBUG_BOOT_INFO
494boot_printf("\n[BOOT INFO] %s : internal peripherals in cluster %x\n", __FUNCTION__ );
495#endif
496
[13]497    boot_info->pages_nr         = 0; 
498    boot_info->dev_icu.channels = 0;
499    boot_info->dev_mmc.channels = 0;
500    boot_info->dev_dma.channels = 0;
501
[6]502    for (device = &device_base[my_cluster->device_offset];
503         device < &device_base[my_cluster->device_offset + my_cluster->devices];
504         device++ )
505    {
506        if (device->type == DEV_TYPE_RAM_SCL)
507        {
[50]508            // set number of physical memory pages
509            boot_info->pages_nr   = device->size >> CONFIG_PPM_PAGE_SHIFT;
[6]510
[1]511#if DEBUG_BOOT_INFO
[50]512boot_printf("  - RAM : %x pages\n", boot_info->pages_nr );
[1]513#endif
[6]514        }
[13]515        else if (device->type == DEV_TYPE_ICU_XCU) 
[6]516        {
[13]517            boot_dev = &boot_info->dev_icu;
518
519            boot_dev->type     = device->type;
520            boot_dev->base     = device->base;
521            boot_dev->channels = device->channels;
522            boot_dev->param0   = device->arg0;   
523            boot_dev->param1   = device->arg1;   
524            boot_dev->param2   = device->arg2;   
525            boot_dev->param3   = device->arg3;   
526            boot_dev->irqs     = device->irqs; 
527
528#if DEBUG_BOOT_INFO
529boot_printf("  - XCU : base = %l / size = %l / channels = %d / irqs = %d\n",
530            device->base , device->size , device->channels , device->irqs );   
531#endif
532
[6]533            for (irq_id = 0; irq_id < CONFIG_MAX_HWIS_PER_ICU; irq_id++)
534            {
535                boot_dev->irq[irq_id].valid  = 0;
[1]536            }
537
[6]538            for (irq = &irq_base[device->irq_offset];
539                 irq < &irq_base[device->irq_offset + device->irqs];
540                 irq++)
[1]541            {
[6]542                boot_dev->irq[irq->port].valid    = 1;
543                boot_dev->irq[irq->port].dev_type = irq->dev_type;
544                boot_dev->irq[irq->port].channel  = irq->channel;
545                boot_dev->irq[irq->port].is_rx    = irq->is_rx;
[1]546
547#if DEBUG_BOOT_INFO
548boot_printf("    . irq_port = %d / source = %s / channel = %d / is_rx = %d\n",
549            irq->port , device_type_str( irq->dev_type ) , irq->channel , irq->is_rx );
550#endif
551
552            }
553        }
[13]554        else if( device->type == DEV_TYPE_MMC_TSR )
555        {
556            boot_dev = &boot_info->dev_mmc;
[1]557
[13]558            boot_dev->type     = device->type;
559            boot_dev->base     = device->base;
560            boot_dev->channels = device->channels;
561            boot_dev->irqs     = 0;
[1]562
[13]563#if DEBUG_BOOT_INFO
564boot_printf("  - MMC : base = %l / size = %l / channels = %d / irqs = %d\n",
565            device->base , device->size , device->channels , device->irqs );   
566#endif
567        }
568        else if( device->type == DEV_TYPE_DMA_SCL )
569        {           
570            boot_dev = &boot_info->dev_dma;
571
572            boot_dev->type     = device->type;
573            boot_dev->base     = device->base;
574            boot_dev->channels = device->channels;
575            boot_dev->irqs     = 0;
576
577#if DEBUG_BOOT_INFO
578boot_printf("  - DMA : base = %l / size = %l / channels = %d / irqs = %d\n",
579            device->base , device->size , device->channels , device->irqs );   
580#endif
581        }
582    }  // end loop on local peripherals
583
[50]584    // Get the top address of the kernel segments
585    end = (boot_info->kernel_code_end > boot_info->kernel_data_end ) ?
586          boot_info->kernel_code_end : boot_info->kernel_data_end;
587
[68]588    // Set number of pages occupied by the kernel code
589    boot_info->pages_offset = ( (end & CONFIG_PPM_PAGE_MASK) == 0 ) ?
[50]590                 (end >> CONFIG_PPM_PAGE_SHIFT) : (end >> CONFIG_PPM_PAGE_SHIFT) + 1;
591
[68]592    // No "reserved zones" for the TSAR architecture
593    boot_info->rsvd_nr = 0;
[50]594
595#if DEBUG_BOOT_INFO
596boot_printf("\n[BOOT INFO] %s : Kernel Reserved Zone / base = 0 / npages = %d at cycle %d\n", 
597            __FUNCTION__ , rsvd_pages ,boot_get_proctime() );
598#endif
599
[6]600    // set boot_info signature
601    boot_info->signature = BOOT_INFO_SIGNATURE;
602
[1]603} // boot_info_init()
604
[6]605/***********************************************************************************
606 * This function check the local boot_info_t structure for a given core.
607 * @ boot_info  : pointer to local 'boot_info_t' structure to be checked.
608 * @ lid        : core local identifier, index the core descriptor table.
609 **********************************************************************************/
[1]610static void boot_check_core( boot_info_t * boot_info, 
611                             lid_t         lid)
612{
613    gid_t         gid;        // global hardware identifier of this core
614    boot_core_t * this;       // BOOT_INFO core descriptor of this core. 
615
616    // Get core hardware identifier
617    gid = (gid_t)boot_get_procid();
618
619    // get pointer on core descriptor
620    this = &boot_info->core[lid];
621
622    if ( (this->gid != gid) ||  (this->cxy != boot_info->cxy) )
623    {
624        boot_printf("\n[BOOT ERROR] in boot_check_core() :\n"
625                    " - boot_info cxy = %x\n"
626                    " - boot_info lid = %d\n"
627                    " - boot_info gid = %x\n"
628                    " - actual    gid = %x\n",
629                    this->cxy , this->lid , this->gid , gid );
630        boot_exit();
631    }
632
633} // boot_check_core()
634
[6]635/*********************************************************************************
636 * This function is called by CP0 in cluster(0,0) to activate all other CP0s.
[1]637 * It returns the number of CP0s actually activated.
[6]638 ********************************************************************************/
639static uint32_t boot_wake_all_cp0s()
[1]640{
[6]641    archinfo_header_t*  header;         // Pointer on ARCHINFO header
642    archinfo_cluster_t* cluster_base;   // Pointer on ARCHINFO clusters base
643    archinfo_cluster_t* cluster;        // Iterator for loop on clusters
644    archinfo_device_t*  device_base;    // Pointer on ARCHINFO devices base
645    archinfo_device_t*  device;         // Iterator for loop on devices
646    uint32_t            cp0_nb = 0;     // CP0s counter
[1]647
648    header       = (archinfo_header_t*)ARCHINFO_BASE;
649    cluster_base = archinfo_get_cluster_base(header);
650    device_base  = archinfo_get_device_base (header); 
651
652    // loop on all clusters
653    for (cluster = cluster_base;
654         cluster < &cluster_base[header->x_size * header->y_size];
655         cluster++)
656    {
657        // Skip boot cluster.
658        if (cluster->cxy == BOOT_CORE_CXY)
659            continue;
660           
661        // Skip clusters without core (thus without CP0).
662        if (cluster->cores == 0)
663            continue;
664
665        // Skip clusters without device (thus without XICU).
666        if (cluster->devices == 0)
667            continue;
668
[6]669        // search XICU device associated to CP0, and send a WTI to activate it
[1]670        for (device = &device_base[cluster->device_offset];
671             device < &device_base[cluster->device_offset + cluster->devices];
672             device++)
673        {
[6]674            if (device->type == DEV_TYPE_ICU_XCU)
[1]675            {
[6]676
677#if DEBUG_BOOT_WAKUP
678boot_printf("\n[BOOT] core[%x][0] activated at cycle %d\n",
679            cluster->cxy , boot_get_proctime );
680#endif
681
[1]682                boot_remote_sw((xptr_t)device->base, (uint32_t)boot_entry);
683                cp0_nb++;
684            }
685        }
686    }
687    return cp0_nb;
688
689} // boot_wake_cp0()
690
[6]691/*********************************************************************************
692 * This function is called by all CP0 to activate all local CPi cores.
693 * @ boot_info  : pointer to local 'boot_info_t' structure, used to find
694 *                the XICU device associated with local CPi base addresses.
695 *********************************************************************************/
696static void boot_wake_local_cores(boot_info_t * boot_info)
[1]697{
[6]698    boot_device_t *  device;         // Iterator on devices
699    unsigned int     core_id;        // Iterator on cores
[1]700
[13]701    device = &boot_info->dev_icu;
702 
703    // loop on cores
704    for (core_id = 1; core_id < boot_info->cores_nr; core_id++)
[1]705    {
[6]706
707#if DEBUG_BOOT_WAKUP
708boot_printf("\n[BOOT] core[%x][%d] activated at cycle %d\n",
709             boot_info->cxy , core_id , boot_get_proctime() );
710#endif
[13]711        boot_remote_sw( (xptr_t)(device->base + (core_id << 2)) , (uint32_t)boot_entry ); 
[1]712    }
713} // boot_wake_local_cores()
714
715
[6]716/*********************************************************************************
[1]717 * This main function of the boot-loader is called by the  boot_entry() 
718 * function, and executed by all cores.
719 * The arguments values are computed by the boot_entry code.
[6]720 * @ lid    : core local identifier,
[1]721 * @ cxy    : cluster identifier,
[6]722 *********************************************************************************/
[1]723void boot_loader( lid_t lid, 
724                  cxy_t cxy )
725{
[6]726    boot_info_t * boot_info;       // pointer on local boot_info_t structure
[1]727
728    if (lid == 0) 
729    {
[6]730        /****************************************************
731         * PHASE A : only CP0 in boot cluster executes it
732         ***************************************************/
[1]733        if (cxy == BOOT_CORE_CXY)
734        {
[6]735            boot_printf("\n[BOOT] core[%x][%d] enters at cycle %d\n",
736                        cxy , lid , boot_get_proctime() );
[1]737
738            // Initialize IOC driver
739            if      (USE_IOC_BDV) boot_bdv_init();
740            else if (USE_IOC_HBA) boot_hba_init();
[6]741            // else if (USE_IOC_SDC) boot_sdc_init();
742            // else if (USE_IOC_SPI) boot_spi_init();
[1]743            else if (!USE_IOC_RDK)
744            {
[6]745                boot_printf("\n[BOOT ERROR] in %s : no IOC driver\n");
[1]746                boot_exit();
747            }
748
[6]749            // Initialize FAT32.
[1]750            boot_fat32_init();
751
[6]752            // Load the 'kernel.elf' file into memory from IOC, and set   
753            // the global variables defining the kernel layout     
754            boot_kernel_load();
755
756            boot_printf("\n[BOOT] core[%x][%d] loaded kernel at cycle %d\n",
757                        cxy , lid , boot_get_proctime() );
758
[1]759            // Load the arch_info.bin file into memory.
760            boot_archinfo_load();
761
[6]762            // Get local boot_info_t structure base address.
[1]763            // It is the first structure in the .kdata segment.
[6]764            boot_info = (boot_info_t *)seg_kdata_base;
[1]765
[6]766            // Initialize local boot_info_t structure.
767            boot_info_init( boot_info , cxy );
768
769            // check boot_info signature
[1]770            if (boot_info->signature != BOOT_INFO_SIGNATURE)
771            {
[6]772                boot_printf("\n[BOOT ERROR] in %s reported by core[%x][%d]\n"
773                            "  illegal boot_info signature / should be %x\n",
774                            __FUNCTION__ , cxy , lid , BOOT_INFO_SIGNATURE );
[1]775                boot_exit();
776            }
777
[6]778            boot_printf("\n[BOOT] core[%x][%d] loaded boot_info at cycle %d\n",
779                        cxy , lid , boot_get_proctime() );
[1]780
781            // Check core information.
782            boot_check_core(boot_info, lid);
783
[6]784            // Activate other CP0s / get number of active CP0s
785            active_cp0s_nr = boot_wake_all_cp0s() + 1;
[1]786
[6]787            // Wait until all clusters (i.e all CP0s) ready to enter kernel.
788            boot_remote_barrier( XPTR( BOOT_CORE_CXY , &global_barrier ) ,
789                                 active_cp0s_nr );
[1]790
[6]791            // activate other local cores
792            boot_wake_local_cores( boot_info );
[1]793
[6]794            // Wait until all local cores in cluster ready
795            boot_remote_barrier( XPTR( cxy , &local_barrier ) , 
796                                 boot_info->cores_nr );
[1]797        }
[6]798        /******************************************************************
799         * PHASE B : all CP0s other than CP0 in boot cluster execute it
800         *****************************************************************/
[1]801        else
802        {
[6]803            // at this point, all INSTRUCTION address extension registers
804            // point on cluster(0,0), but the DATA extension registers point
805            // already on the local cluster to use the local stack.
806            // To access the bootloader global variables we must first copy
807            // the boot code (data and instructions) in the local cluster.
808            boot_remote_memcpy( XPTR( cxy           , BOOT_BASE ),
809                                XPTR( BOOT_CORE_CXY , BOOT_BASE ),
810                                BOOT_MAX_SIZE );
[1]811
[6]812            // from now, it is safe to refer to the boot code global variables
813            boot_printf("\n[BOOT] core[%x][%d] replicated boot code at cycle %d\n",
814                        cxy , lid , boot_get_proctime() );
[1]815
[6]816            // switch to the INSTRUCTION local memory space, to avoid contention.
[1]817            asm volatile("mtc2  %0, $25" :: "r"(cxy));
818
[6]819            // Copy the arch_info.bin file into the local memory.
[1]820            boot_remote_memcpy(XPTR(cxy,           ARCHINFO_BASE),
821                               XPTR(BOOT_CORE_CXY, ARCHINFO_BASE),
[6]822                               ARCHINFO_MAX_SIZE );
[1]823
[6]824            boot_printf("\n[BOOT] core[%x][%d] replicated arch_info at cycle %d\n",
825                        cxy , lid , boot_get_proctime() );
[1]826
[6]827            // Copy the kcode segment into local memory
828            boot_remote_memcpy( XPTR( cxy           , seg_kcode_base ),
829                                XPTR( BOOT_CORE_CXY , seg_kcode_base ),
830                                seg_kcode_size );
[1]831
[6]832            // Copy the kdata segment into local memory
833            boot_remote_memcpy( XPTR( cxy           , seg_kdata_base ),
834                                XPTR( BOOT_CORE_CXY , seg_kdata_base ),
835                                seg_kdata_size );
836
837            boot_printf("\n[BOOT] core[%x][%d] replicated kernel code at cycle %d\n",
838                        cxy , lid , boot_get_proctime() );
839
840            // Get local boot_info_t structure base address.
841            boot_info = (boot_info_t*)seg_kdata_base;
842
[1]843            // Initialize local boot_info_t structure.
[6]844            boot_info_init( boot_info , cxy );
[1]845
846            // Check core information.
[6]847            boot_check_core( boot_info , lid );
[1]848
[6]849            // get number of active clusters from BOOT_CORE cluster
850            uint32_t count = boot_remote_lw( XPTR( BOOT_CORE_CXY , &active_cp0s_nr ) );
[1]851
[6]852            // Wait until all clusters (i.e all CP0s) ready to enter kernel
853            boot_remote_barrier( XPTR( BOOT_CORE_CXY , &global_barrier ) , count );
[1]854
[6]855            // activate other local cores
856            boot_wake_local_cores( boot_info );
857
858            // Wait until all local cores in cluster ready
859            boot_remote_barrier( XPTR( cxy , &local_barrier ) , 
860                                 boot_info->cores_nr );
[1]861        }
862    }
863    else
864    {
865        /***************************************************************
[6]866         * PHASE C: all non CP0 cores in all clusters execute it
[1]867         **************************************************************/
868
[6]869        // Switch to the INSTRUCTIONS local memory space
870        // to avoid contention at the boot cluster.
871        asm volatile("mtc2  %0, $25" :: "r"(cxy));
[1]872
[6]873        // Get local boot_info_t structure base address.
874        boot_info = (boot_info_t *)seg_kdata_base;
[1]875
[6]876        // Check core information
877        boot_check_core(boot_info, lid);
[1]878
[6]879        // Wait until all local cores in cluster ready
880        boot_remote_barrier( XPTR( cxy , &local_barrier ) , boot_info->cores_nr );
[1]881    }
882
[13]883    // Ech core compute stack pointer to the kernel idle-thread descriptor.
884    // The array of idle-thread descriptors is allocated in the kdata segment,
885    // just after the boot_info structure
[1]886
[13]887    uint32_t sp;
888    uint32_t base;
889    uint32_t offset = sizeof( boot_info_t );
890    uint32_t pmask  = CONFIG_PPM_PAGE_MASK;
891    uint32_t psize  = CONFIG_PPM_PAGE_SIZE;
892
893    // compute base address of idle thread descriptors array
894    if( offset & pmask ) base = seg_kdata_base + (offset & ~pmask) + psize;
895    else                 base = seg_kdata_base + offset;
896
897    // compute stack pointer
898    sp = base + ((lid + 1) * CONFIG_THREAD_DESC_SIZE) - 16;
899
900    // Each cores initialise stack pointer,
[6]901    // reset the BEV bit in status register,
902    // register "boot_info" argument in a0,
903    // and jump to kernel_entry.
904    asm volatile( "mfc0  $27,  $12           \n"
905                  "lui   $26,  0xFFBF        \n"
906                  "ori   $26,  $26,  0xFFFF  \n"
907                  "and   $27,  $27,  $26     \n"
908                  "mtc0  $27,  $12           \n" 
909                  "move  $4,   %0            \n"
910                  "move  $29,  %1            \n"
911                  "jr    %2                  \n"
[13]912                  :: "r"(boot_info) , "r"(sp) , "r"(kernel_entry) );
[6]913
[1]914} // boot_loader()
Note: See TracBrowser for help on using the repository browser.