source: trunk/boot/tsar_mips32/boot.c @ 578

Last change on this file since 578 was 578, checked in by alain, 3 years ago

remove params-hard-simu.mk and params-hard-real.mk files from svn.

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