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

Last change on this file since 637 was 637, checked in by alain, 5 years ago

Introduce the non-standard pthread_parallel_create() system call
and re-write the <fft> and <sort> applications to improve the
intrinsic paralelism in applications.

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