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

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

Fix several bugs to use the instruction MMU in kernel mode
in replacement of the instruction address extension register,
and remove the "kentry" segment.

This version is running on the tsar_generic_iob" platform.

One interesting bug: the cp0_ebase defining the kernel entry point
(for interrupts, exceptions and syscalls) must be initialized
early in kernel_init(), because the VFS initialisation done by
kernel_ini() uses RPCs, and RPCs uses Inter-Processor-Interrup.

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, __FUNCTION__, 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.