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

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

Introduce three new types of vsegs (KCODE,KDATA,KDEV)
to map the kernel vsegs in the process VSL and GPT.
This now used by both the TSAR and the I86 architectures.

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