source: trunk/boot/tsar_mips32/boot.c

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

cosmetic

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