source: trunk/boot/tsar_mips32/boot.c

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

cosmetic

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