source: trunk/tools/bootloader_tsar/boot.c@ 186

Last change on this file since 186 was 68, checked in by alain, 9 years ago

Fix bug in kernel_init, and reduce size of remote_fifo.

File size: 36.8 KB
Line 
1/*
2 * boot.c - TSAR bootloader implementation.
3 *
4 * Authors : Alain Greiner / Vu Son (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24/****************************************************************************
25 * This file contains the ALMOS-MKH. boot-loader for the TSAR architecture. *
26 * *
27 * It supports clusterised shared memory multi-processor architectures, *
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 and is loaded into memory by core[0,0] (cxy = 0 / lid = 0), *
33 * and is copied in each other cluter by the local CP0 (lid = 0]. *
34 * *
35 * 1) The boot-loader first phase is executed by core[0,0], while *
36 * all other cores are waiting in the preloader. *
37 * It does the following tasks: *
38 * - load into the memory bank of cluster 0 the 'arch_info.bin' *
39 * file (containing the hardware architecture description) and the *
40 * 'kernel.elf' file, at temporary locations, *
41 * - initializes the 'boot_info_t' structure in cluster(0,0) *
42 * (there is 1 'boot_info_t' per cluster), which contains both *
43 * global and cluster specific information that will be used for *
44 * kernel initialisation. *
45 * - activate CP0s in all other clusters, using IPIs. *
46 * - wait completion reports from CP0s on a global barrier. *
47 * *
48 * 2) The boot-loader second phase is then executed in parallel by all *
49 * CP0s (other than core[0,0]). Each CP0 performs the following tasks: *
50 * - copies into the memory bank of the local cluster the 'boot.elf', *
51 * the 'arch_info.bin' (at the same addresses as the 'boot.elf' and *
52 * the 'arch_info.bin' in the memory bank of the cluster(0,0), and *
53 * the kernel image (at address 0x0), *
54 * - initializes the 'boot_info_t' structure of the local cluster, *
55 * - activate all other cores in the same cluster (CPi). *
56 * - wait local CPi completion reports on a local barrier. *
57 * - report completion to bscpu on the global barrier. *
58 * *
59 * 3) The boot-loader third phase is executed in parallel by all cores. *
60 * After passing the global barrier the bscpu: *
61 * - activates the CPi of cluster(0), *
62 * - blocks on the local barrier waiting for all local CPi to report *
63 * completion on the local barrier, *
64 * - moves the local kernel image from the temporary location to the *
65 * address 0x0, (erasing the preloader code). *
66 * *
67 * 4) All cores have finished the boot phase, they jump to the kern_init() *
68 * function (maybe not at the same time). *
69 ****************************************************************************/
70
71#include <elf-types.h>
72#include <hal_types.h>
73
74#include <kernel_config.h>
75#include <boot_config.h>
76
77#include <arch_info.h>
78#include <boot_info.h>
79
80#include <boot_utils.h>
81#include <boot_fat32.h>
82#include <boot_bdv_driver.h>
83#include <boot_hba_driver.h>
84#include <boot_tty_driver.h>
85
86/*****************************************************************************
87 * Macros.
88 ****************************************************************************/
89
90#define PAGE_ROUND_DOWN(x) ((x) & (~PPM_PAGE_SIZE -1))
91#define PAGE_ROUND_UP(x) (((x) + PPM_PAGE_SIZE-1) & \
92 (~(PPM_PAGE_SIZE-1)))
93
94/*****************************************************************************
95 * Global variables.
96 ****************************************************************************/
97
98// synchronization variables.
99
100volatile boot_remote_spinlock_t tty0_lock; // protect TTY0 access
101volatile boot_remote_barrier_t global_barrier; // synchronize CP0 cores
102volatile boot_remote_barrier_t local_barrier; // synchronize cores in one cluster
103uint32_t active_cp0s_nr; // number of expected CP0s
104
105// kernel segments layout variables
106
107uint32_t seg_kcode_base; // kcode segment base address
108uint32_t seg_kcode_size; // kcode segment size (bytes)
109uint32_t seg_kdata_base; // kdata segment base address
110uint32_t seg_kdata_size; // kdata segment size (bytes)
111uint32_t kernel_entry; // kernel entry point
112
113// address used by the WTI to activate remote CP0s
114
115extern void boot_entry(); // boot_loader entry point
116
117/*********************************************************************************
118 * This function returns the printable string for each device type
119 ********************************************************************************/
120char * device_type_str( uint32_t dev_type )
121{
122 if ( dev_type == DEV_TYPE_RAM_SCL ) return "RAM_SCL";
123 else if( dev_type == DEV_TYPE_ROM_SCL ) return "ROM_SCL";
124 else if( dev_type == DEV_TYPE_FBF_SCL ) return "FBF_SCL";
125 else if( dev_type == DEV_TYPE_IOB_TSR ) return "IOB_TSR";
126 else if( dev_type == DEV_TYPE_IOC_BDV ) return "IOC_BDV";
127 else if( dev_type == DEV_TYPE_IOC_HBA ) return "IOC_HBA";
128 else if( dev_type == DEV_TYPE_IOC_SDC ) return "IOC_SDC";
129 else if( dev_type == DEV_TYPE_IOC_SPI ) return "IOC_SPI";
130 else if( dev_type == DEV_TYPE_IOC_RDK ) return "IOC_RDK";
131 else if( dev_type == DEV_TYPE_MMC_TSR ) return "MMC_TSR";
132 else if( dev_type == DEV_TYPE_DMA_SCL ) return "DMA_SCL";
133 else if( dev_type == DEV_TYPE_NIC_CBF ) return "NIC_CBF";
134 else if( dev_type == DEV_TYPE_TIM_SCL ) return "TIM_SCL";
135 else if( dev_type == DEV_TYPE_TXT_TTY ) return "TXT_TTY";
136 else if( dev_type == DEV_TYPE_ICU_XCU ) return "ICU_XCU";
137 else if( dev_type == DEV_TYPE_PIC_TSR ) return "PIC_TSR";
138 else return "undefined";
139}
140
141/************************************************************************************
142 * This function loads the arch_info.bin file into the boot cluster memory.
143 ***********************************************************************************/
144static void boot_archinfo_load()
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]: boot_archinfo_load(): "
152 "<%s> file not found\n",
153 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 the two seg_kcode & seg_kdata segments at their final
175 * physical adresses (just after the preloader zone).
176 * It set the global variables defining the kernel layout.
177 *************************************************************************************/
178static void boot_kernel_load()
179{
180 Elf32_Ehdr * elf_header; // pointer on kernel.elf header.
181 Elf32_Phdr * program_header; // pointer on kernel.elf program header.
182 uint32_t phdr_offset; // program header offset in kernel.elf file.
183 uint32_t segments_nb; // number of segments in kernel.elf file.
184 uint32_t seg_src_addr; // segment address in kernel.elf file (source).
185 uint32_t seg_paddr; // segment local physical address of segment
186 uint32_t seg_offset; // segment offset in kernel.elf file
187 uint32_t seg_filesz; // segment size (bytes) in kernel.elf file
188 uint32_t seg_memsz; // segment size (bytes) in memory image.
189 bool_t kcode_found; // kcode segment found.
190 bool_t kdata_found; // kdata segment found.
191 uint32_t seg_id; // iterator for segments loop.
192
193#if DEBUG_BOOT_ELF
194boot_printf("\n[BOOT INFO] %s enters for file %s at cycle %d\n",
195 __FUNCTION__ , KERNEL_PATHNAME , boot_get_proctime() );
196#endif
197
198 // Load kernel.elf file into memory buffer
199 if ( boot_fat32_load(KERNEL_PATHNAME, KERN_BASE, KERN_MAX_SIZE) )
200 {
201 boot_printf("\n[BOOT ERROR] in %s : <%s> file not found\n",
202 KERNEL_PATHNAME);
203 boot_exit();
204 }
205
206 // get pointer to kernel.elf header
207 elf_header = (Elf32_Ehdr*)KERN_BASE;
208
209 // check signature
210 if ((elf_header->e_ident[EI_MAG0] != ELFMAG0) ||
211 (elf_header->e_ident[EI_MAG1] != ELFMAG1) ||
212 (elf_header->e_ident[EI_MAG2] != ELFMAG2) ||
213 (elf_header->e_ident[EI_MAG3] != ELFMAG3))
214 {
215 boot_printf("\n[BOOT_ERROR]: boot_kernel_load(): "
216 "<%s> is not an ELF file\n",
217 KERNEL_PATHNAME);
218 boot_exit();
219 }
220
221 // Get program header table offset and number of segments
222 phdr_offset = elf_header->e_phoff;
223 segments_nb = elf_header->e_phnum;
224
225 // Get program header table pointer
226 program_header = (Elf32_Phdr*)(KERN_BASE + phdr_offset);
227
228 // loop on segments
229 kcode_found = false;
230 kdata_found = false;
231 for (seg_id = 0; seg_id < segments_nb; seg_id++)
232 {
233 if (program_header[seg_id].p_type == PT_LOAD) // Found one loadable segment
234 {
235 // Get segment attributes.
236 seg_paddr = program_header[seg_id].p_paddr;
237 seg_offset = program_header[seg_id].p_offset;
238 seg_filesz = program_header[seg_id].p_filesz;
239 seg_memsz = program_header[seg_id].p_memsz;
240
241 // get segment base address in buffer
242 seg_src_addr = (uint32_t)KERN_BASE + seg_offset;
243
244 // Load segment to its final physical memory address
245 boot_memcpy( (void*)seg_paddr,
246 (void*)seg_src_addr,
247 seg_filesz );
248
249#if DEBUG_BOOT_ELF
250boot_printf("\n[BOOT INFO] in %s for file %s : found loadable segment\n"
251 " base = %x / size = %x\n",
252 __FUNCTION__ , KERNEL_PATHNAME , seg_paddr , seg_memsz );
253#endif
254
255 // Fill remaining memory with zero if (filesz < memsz).
256 if( seg_memsz < seg_filesz )
257 {
258 boot_memset( (void*)(seg_paddr + seg_filesz), 0, seg_memsz - seg_filesz);
259 }
260
261 // Note: we suppose that the 'kernel.elf' file contains only 2
262 // loadable segments ktext & kdata and that the main
263 // difference between these two is the WRITE permission: ktext
264 // contains read-only instructions and read_only data,
265 // while kdata contains writable data.
266
267 if ((program_header[seg_id].p_flags & PF_W) == 0) // kcode segment
268 {
269 if( kcode_found )
270 {
271 boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
272 " two loadable kcode segments found\n",
273 __FUNCTION__ , KERNEL_PATHNAME );
274 boot_exit();
275 }
276
277 kcode_found = true;
278 seg_kcode_base = seg_paddr;
279 seg_kcode_size = seg_memsz;
280 }
281 else // kdata segment
282 {
283 if( kdata_found )
284 {
285 boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
286 " two loadable kdata segments found\n",
287 __FUNCTION__ , KERNEL_PATHNAME );
288 boot_exit();
289 }
290
291 kdata_found = true;
292 seg_kdata_base = seg_paddr;
293 seg_kdata_size = seg_memsz;
294 }
295 }
296 }
297
298 // check kcode & kdata segments found
299 if( kcode_found == false )
300 {
301 boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
302 " kcode segment not found\n",
303 __FUNCTION__ , KERNEL_PATHNAME );
304 boot_exit();
305 }
306 if( kdata_found == false )
307 {
308 boot_printf("\n[BOOT_ERROR] in %s for file %s :\n"
309 " kdata segment not found\n",
310 __FUNCTION__ , KERNEL_PATHNAME );
311 boot_exit();
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 successfully 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; // cluster containing ext. peripherals
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 uint32_t rsvd_pages;
350 boot_device_t * boot_dev;
351
352 // get pointer on ARCHINFO header and on the four arch_info arrays
353 header = (archinfo_header_t*)ARCHINFO_BASE;
354 core_base = archinfo_get_core_base (header);
355 cluster_base = archinfo_get_cluster_base(header);
356 device_base = archinfo_get_device_base (header);
357 irq_base = archinfo_get_irq_base (header);
358
359 // Initialize global platform parameters
360 boot_info->x_size = header->x_size;
361 boot_info->y_size = header->y_size;
362 boot_info->x_width = header->x_width;
363 boot_info->y_width = header->y_width;
364 boot_info->paddr_width = header->paddr_width;
365 boot_info->io_cxy = header->io_cxy;
366
367 // Initialize kernel segments from global variables
368 boot_info->kernel_code_start = seg_kcode_base;
369 boot_info->kernel_code_end = seg_kcode_base + seg_kcode_size;
370 boot_info->kernel_data_start = seg_kdata_base;
371 boot_info->kernel_data_end = seg_kdata_base + seg_kdata_size;
372
373 // loop on arch_info clusters to get relevant pointers
374 for (cluster = cluster_base;
375 cluster < &cluster_base[header->x_size * header->y_size];
376 cluster++)
377 {
378 if( cluster->cxy == cxy ) my_cluster = cluster;
379 if( cluster->cxy == header->io_cxy ) io_cluster = cluster;
380 }
381
382 if( my_cluster == NULL )
383 {
384 boot_printf("\n[ERROR] in %s : cannot found cluster %x in arch_info\n",
385 __FUNCTION__ , cxy );
386 boot_exit();
387 }
388
389 if( io_cluster == NULL )
390 {
391 boot_printf("\n[ERROR] in %s : cannot found io_cluster %x in arch_info\n",
392 __FUNCTION__ , header->io_cxy );
393 boot_exit();
394 }
395
396 // loop on arch-info peripherals in io_cluster,
397 // to initialize the boot_info array of external peripherals
398
399#if DEBUG_BOOT_INFO
400boot_printf("\n[BOOT INFO] %s : external peripherals at cycle %d\n",
401 __FUNCTION__ , cxy , boot_get_proctime() );
402#endif
403
404 device_id = 0;
405 for (device = &device_base[io_cluster->device_offset];
406 device < &device_base[io_cluster->device_offset + io_cluster->devices];
407 device++ )
408 {
409 // initialise one entry for each external peripheral
410 if( (device->type != DEV_TYPE_RAM_SCL) &&
411 (device->type != DEV_TYPE_ICU_XCU) &&
412 (device->type != DEV_TYPE_MMC_TSR) &&
413 (device->type != DEV_TYPE_DMA_SCL) )
414 {
415 boot_dev = &boot_info->ext_dev[device_id];
416
417 boot_dev->type = device->type;
418 boot_dev->base = device->base;
419 boot_dev->channels = device->channels;
420 boot_dev->param0 = device->arg0;
421 boot_dev->param1 = device->arg1;
422 boot_dev->param2 = device->arg2;
423 boot_dev->param3 = device->arg3;
424 boot_dev->irqs = device->irqs;
425
426 device_id++;
427
428#if DEBUG_BOOT_INFO
429boot_printf(" - %s : base = %l / size = %l / channels = %d / irqs = %d\n",
430 device_type_str( device->type ) , device->base , device->size ,
431 device->channels , device->irqs );
432#endif
433 }
434
435 // Initialize array of irq descriptors for PIC
436 if (device->type == DEV_TYPE_PIC_TSR)
437 {
438 for (irq_id = 0; irq_id < CONFIG_MAX_IRQS_PER_PIC; irq_id++)
439 {
440 boot_dev->irq[irq_id].valid = 0;
441 }
442
443 for (irq = &irq_base[device->irq_offset];
444 irq < &irq_base[device->irq_offset + device->irqs];
445 irq++)
446 {
447 boot_dev->irq[irq->port].valid = 1;
448 boot_dev->irq[irq->port].dev_type = irq->dev_type;
449 boot_dev->irq[irq->port].channel = irq->channel;
450 boot_dev->irq[irq->port].is_rx = irq->is_rx;
451
452#if DEBUG_BOOT_INFO
453boot_printf(" . irq_port = %d / source = %s / channel = %d / is_rx = %d\n",
454 irq->port , device_type_str( irq->dev_type ) , irq->channel , irq->is_rx );
455#endif
456 }
457 }
458 } // end loop on io_cluster peripherals
459
460 // initialize number of external peripherals
461 boot_info->ext_dev_nr = device_id;
462
463 // Initialize cluster specific resources
464 boot_info->cxy = my_cluster->cxy;
465
466#if DEBUG_BOOT_INFO
467boot_printf("\n[BOOT INFO] %s : cores in cluster %x\n", __FUNCTION__ );
468#endif
469
470 // Initialize array of core descriptors
471 core_id = 0;
472 for (core = &core_base[my_cluster->core_offset];
473 core < &core_base[my_cluster->core_offset + my_cluster->cores];
474 core++ )
475 {
476 boot_info->core[core_id].gid = (gid_t)core->gid;
477 boot_info->core[core_id].lid = (lid_t)core->lid;
478 boot_info->core[core_id].cxy = (cxy_t)core->cxy;
479
480#if DEBUG_BOOT_INFO
481boot_printf(" - core_gid = %x : cxy = %x / lid = %d\n",
482 core->gid , core->cxy , core->lid );
483#endif
484 core_id++;
485 }
486
487 // Initialize number of cores in my_cluster
488 boot_info->cores_nr = core_id;
489
490 // initialise internal devices (RAM, XCU, MMC, DMA)
491 // set default values, then scan all local devices
492
493#if DEBUG_BOOT_INFO
494boot_printf("\n[BOOT INFO] %s : internal peripherals in cluster %x\n", __FUNCTION__ );
495#endif
496
497 boot_info->pages_nr = 0;
498 boot_info->dev_icu.channels = 0;
499 boot_info->dev_mmc.channels = 0;
500 boot_info->dev_dma.channels = 0;
501
502 for (device = &device_base[my_cluster->device_offset];
503 device < &device_base[my_cluster->device_offset + my_cluster->devices];
504 device++ )
505 {
506 if (device->type == DEV_TYPE_RAM_SCL)
507 {
508 // set number of physical memory pages
509 boot_info->pages_nr = device->size >> CONFIG_PPM_PAGE_SHIFT;
510
511#if DEBUG_BOOT_INFO
512boot_printf(" - RAM : %x pages\n", boot_info->pages_nr );
513#endif
514 }
515 else if (device->type == DEV_TYPE_ICU_XCU)
516 {
517 boot_dev = &boot_info->dev_icu;
518
519 boot_dev->type = device->type;
520 boot_dev->base = device->base;
521 boot_dev->channels = device->channels;
522 boot_dev->param0 = device->arg0;
523 boot_dev->param1 = device->arg1;
524 boot_dev->param2 = device->arg2;
525 boot_dev->param3 = device->arg3;
526 boot_dev->irqs = device->irqs;
527
528#if DEBUG_BOOT_INFO
529boot_printf(" - XCU : base = %l / size = %l / channels = %d / irqs = %d\n",
530 device->base , device->size , device->channels , device->irqs );
531#endif
532
533 for (irq_id = 0; irq_id < CONFIG_MAX_HWIS_PER_ICU; irq_id++)
534 {
535 boot_dev->irq[irq_id].valid = 0;
536 }
537
538 for (irq = &irq_base[device->irq_offset];
539 irq < &irq_base[device->irq_offset + device->irqs];
540 irq++)
541 {
542 boot_dev->irq[irq->port].valid = 1;
543 boot_dev->irq[irq->port].dev_type = irq->dev_type;
544 boot_dev->irq[irq->port].channel = irq->channel;
545 boot_dev->irq[irq->port].is_rx = irq->is_rx;
546
547#if DEBUG_BOOT_INFO
548boot_printf(" . irq_port = %d / source = %s / channel = %d / is_rx = %d\n",
549 irq->port , device_type_str( irq->dev_type ) , irq->channel , irq->is_rx );
550#endif
551
552 }
553 }
554 else if( device->type == DEV_TYPE_MMC_TSR )
555 {
556 boot_dev = &boot_info->dev_mmc;
557
558 boot_dev->type = device->type;
559 boot_dev->base = device->base;
560 boot_dev->channels = device->channels;
561 boot_dev->irqs = 0;
562
563#if DEBUG_BOOT_INFO
564boot_printf(" - MMC : base = %l / size = %l / channels = %d / irqs = %d\n",
565 device->base , device->size , device->channels , device->irqs );
566#endif
567 }
568 else if( device->type == DEV_TYPE_DMA_SCL )
569 {
570 boot_dev = &boot_info->dev_dma;
571
572 boot_dev->type = device->type;
573 boot_dev->base = device->base;
574 boot_dev->channels = device->channels;
575 boot_dev->irqs = 0;
576
577#if DEBUG_BOOT_INFO
578boot_printf(" - DMA : base = %l / size = %l / channels = %d / irqs = %d\n",
579 device->base , device->size , device->channels , device->irqs );
580#endif
581 }
582 } // end loop on local peripherals
583
584 // Get the top address of the kernel segments
585 end = (boot_info->kernel_code_end > boot_info->kernel_data_end ) ?
586 boot_info->kernel_code_end : boot_info->kernel_data_end;
587
588 // Set number of pages occupied by the kernel code
589 boot_info->pages_offset = ( (end & CONFIG_PPM_PAGE_MASK) == 0 ) ?
590 (end >> CONFIG_PPM_PAGE_SHIFT) : (end >> CONFIG_PPM_PAGE_SHIFT) + 1;
591
592 // No "reserved zones" for the TSAR architecture
593 boot_info->rsvd_nr = 0;
594
595#if DEBUG_BOOT_INFO
596boot_printf("\n[BOOT INFO] %s : Kernel Reserved Zone / base = 0 / npages = %d at cycle %d\n",
597 __FUNCTION__ , rsvd_pages ,boot_get_proctime() );
598#endif
599
600 // set boot_info signature
601 boot_info->signature = BOOT_INFO_SIGNATURE;
602
603} // boot_info_init()
604
605/***********************************************************************************
606 * This function check the local boot_info_t structure for a given core.
607 * @ boot_info : pointer to local 'boot_info_t' structure to be checked.
608 * @ lid : core local identifier, index the core descriptor table.
609 **********************************************************************************/
610static void boot_check_core( boot_info_t * boot_info,
611 lid_t lid)
612{
613 gid_t gid; // global hardware identifier of this core
614 boot_core_t * this; // BOOT_INFO core descriptor of this core.
615
616 // Get core hardware identifier
617 gid = (gid_t)boot_get_procid();
618
619 // get pointer on core descriptor
620 this = &boot_info->core[lid];
621
622 if ( (this->gid != gid) || (this->cxy != boot_info->cxy) )
623 {
624 boot_printf("\n[BOOT ERROR] in boot_check_core() :\n"
625 " - boot_info cxy = %x\n"
626 " - boot_info lid = %d\n"
627 " - boot_info gid = %x\n"
628 " - actual gid = %x\n",
629 this->cxy , this->lid , this->gid , gid );
630 boot_exit();
631 }
632
633} // boot_check_core()
634
635/*********************************************************************************
636 * This function is called by CP0 in cluster(0,0) to activate all other CP0s.
637 * It returns the number of CP0s actually activated.
638 ********************************************************************************/
639static uint32_t boot_wake_all_cp0s()
640{
641 archinfo_header_t* header; // Pointer on ARCHINFO header
642 archinfo_cluster_t* cluster_base; // Pointer on ARCHINFO clusters base
643 archinfo_cluster_t* cluster; // Iterator for loop on clusters
644 archinfo_device_t* device_base; // Pointer on ARCHINFO devices base
645 archinfo_device_t* device; // Iterator for loop on devices
646 uint32_t cp0_nb = 0; // CP0s counter
647
648 header = (archinfo_header_t*)ARCHINFO_BASE;
649 cluster_base = archinfo_get_cluster_base(header);
650 device_base = archinfo_get_device_base (header);
651
652 // loop on all clusters
653 for (cluster = cluster_base;
654 cluster < &cluster_base[header->x_size * header->y_size];
655 cluster++)
656 {
657 // Skip boot cluster.
658 if (cluster->cxy == BOOT_CORE_CXY)
659 continue;
660
661 // Skip clusters without core (thus without CP0).
662 if (cluster->cores == 0)
663 continue;
664
665 // Skip clusters without device (thus without XICU).
666 if (cluster->devices == 0)
667 continue;
668
669 // search XICU device associated to CP0, and send a WTI to activate it
670 for (device = &device_base[cluster->device_offset];
671 device < &device_base[cluster->device_offset + cluster->devices];
672 device++)
673 {
674 if (device->type == DEV_TYPE_ICU_XCU)
675 {
676
677#if DEBUG_BOOT_WAKUP
678boot_printf("\n[BOOT] core[%x][0] activated at cycle %d\n",
679 cluster->cxy , boot_get_proctime );
680#endif
681
682 boot_remote_sw((xptr_t)device->base, (uint32_t)boot_entry);
683 cp0_nb++;
684 }
685 }
686 }
687 return cp0_nb;
688
689} // boot_wake_cp0()
690
691/*********************************************************************************
692 * This function is called by all CP0 to activate all local CPi cores.
693 * @ boot_info : pointer to local 'boot_info_t' structure, used to find
694 * the XICU device associated with local CPi base addresses.
695 *********************************************************************************/
696static void boot_wake_local_cores(boot_info_t * boot_info)
697{
698 boot_device_t * device; // Iterator on devices
699 unsigned int core_id; // Iterator on cores
700
701 device = &boot_info->dev_icu;
702
703 // loop on cores
704 for (core_id = 1; core_id < boot_info->cores_nr; core_id++)
705 {
706
707#if DEBUG_BOOT_WAKUP
708boot_printf("\n[BOOT] core[%x][%d] activated at cycle %d\n",
709 boot_info->cxy , core_id , boot_get_proctime() );
710#endif
711 boot_remote_sw( (xptr_t)(device->base + (core_id << 2)) , (uint32_t)boot_entry );
712 }
713} // boot_wake_local_cores()
714
715
716/*********************************************************************************
717 * This main function of the boot-loader is called by the boot_entry()
718 * function, and executed by all cores.
719 * The arguments values are computed by the boot_entry code.
720 * @ lid : core local identifier,
721 * @ cxy : cluster identifier,
722 *********************************************************************************/
723void boot_loader( lid_t lid,
724 cxy_t cxy )
725{
726 boot_info_t * boot_info; // pointer on local boot_info_t structure
727
728 if (lid == 0)
729 {
730 /****************************************************
731 * PHASE A : only CP0 in boot cluster executes it
732 ***************************************************/
733 if (cxy == BOOT_CORE_CXY)
734 {
735 boot_printf("\n[BOOT] core[%x][%d] enters at cycle %d\n",
736 cxy , lid , boot_get_proctime() );
737
738 // Initialize IOC driver
739 if (USE_IOC_BDV) boot_bdv_init();
740 else if (USE_IOC_HBA) boot_hba_init();
741 // else if (USE_IOC_SDC) boot_sdc_init();
742 // else if (USE_IOC_SPI) boot_spi_init();
743 else if (!USE_IOC_RDK)
744 {
745 boot_printf("\n[BOOT ERROR] in %s : no IOC driver\n");
746 boot_exit();
747 }
748
749 // Initialize FAT32.
750 boot_fat32_init();
751
752 // Load the 'kernel.elf' file into memory from IOC, and set
753 // the global variables defining the kernel layout
754 boot_kernel_load();
755
756 boot_printf("\n[BOOT] core[%x][%d] loaded kernel at cycle %d\n",
757 cxy , lid , boot_get_proctime() );
758
759 // Load the arch_info.bin file into memory.
760 boot_archinfo_load();
761
762 // Get local boot_info_t structure base address.
763 // It is the first structure in the .kdata segment.
764 boot_info = (boot_info_t *)seg_kdata_base;
765
766 // Initialize local boot_info_t structure.
767 boot_info_init( boot_info , cxy );
768
769 // check boot_info signature
770 if (boot_info->signature != BOOT_INFO_SIGNATURE)
771 {
772 boot_printf("\n[BOOT ERROR] in %s reported by core[%x][%d]\n"
773 " illegal boot_info signature / should be %x\n",
774 __FUNCTION__ , cxy , lid , BOOT_INFO_SIGNATURE );
775 boot_exit();
776 }
777
778 boot_printf("\n[BOOT] core[%x][%d] loaded boot_info at cycle %d\n",
779 cxy , lid , boot_get_proctime() );
780
781 // Check core information.
782 boot_check_core(boot_info, lid);
783
784 // Activate other CP0s / get number of active CP0s
785 active_cp0s_nr = boot_wake_all_cp0s() + 1;
786
787 // Wait until all clusters (i.e all CP0s) ready to enter kernel.
788 boot_remote_barrier( XPTR( BOOT_CORE_CXY , &global_barrier ) ,
789 active_cp0s_nr );
790
791 // activate other local cores
792 boot_wake_local_cores( boot_info );
793
794 // Wait until all local cores in cluster ready
795 boot_remote_barrier( XPTR( cxy , &local_barrier ) ,
796 boot_info->cores_nr );
797 }
798 /******************************************************************
799 * PHASE B : all CP0s other than CP0 in boot cluster execute it
800 *****************************************************************/
801 else
802 {
803 // at this point, all INSTRUCTION address extension registers
804 // point on cluster(0,0), but the DATA extension registers point
805 // already on the local cluster to use the local stack.
806 // To access the bootloader global variables we must first copy
807 // the boot code (data and instructions) in the local cluster.
808 boot_remote_memcpy( XPTR( cxy , BOOT_BASE ),
809 XPTR( BOOT_CORE_CXY , BOOT_BASE ),
810 BOOT_MAX_SIZE );
811
812 // from now, it is safe to refer to the boot code global variables
813 boot_printf("\n[BOOT] core[%x][%d] replicated boot code at cycle %d\n",
814 cxy , lid , boot_get_proctime() );
815
816 // switch to the INSTRUCTION local memory space, to avoid contention.
817 asm volatile("mtc2 %0, $25" :: "r"(cxy));
818
819 // Copy the arch_info.bin file into the local memory.
820 boot_remote_memcpy(XPTR(cxy, ARCHINFO_BASE),
821 XPTR(BOOT_CORE_CXY, ARCHINFO_BASE),
822 ARCHINFO_MAX_SIZE );
823
824 boot_printf("\n[BOOT] core[%x][%d] replicated arch_info at cycle %d\n",
825 cxy , lid , boot_get_proctime() );
826
827 // Copy the kcode segment into local memory
828 boot_remote_memcpy( XPTR( cxy , seg_kcode_base ),
829 XPTR( BOOT_CORE_CXY , seg_kcode_base ),
830 seg_kcode_size );
831
832 // Copy the kdata segment into local memory
833 boot_remote_memcpy( XPTR( cxy , seg_kdata_base ),
834 XPTR( BOOT_CORE_CXY , seg_kdata_base ),
835 seg_kdata_size );
836
837 boot_printf("\n[BOOT] core[%x][%d] replicated kernel code at cycle %d\n",
838 cxy , lid , boot_get_proctime() );
839
840 // Get local boot_info_t structure base address.
841 boot_info = (boot_info_t*)seg_kdata_base;
842
843 // Initialize local boot_info_t structure.
844 boot_info_init( boot_info , cxy );
845
846 // Check core information.
847 boot_check_core( boot_info , lid );
848
849 // get number of active clusters from BOOT_CORE cluster
850 uint32_t count = boot_remote_lw( XPTR( BOOT_CORE_CXY , &active_cp0s_nr ) );
851
852 // Wait until all clusters (i.e all CP0s) ready to enter kernel
853 boot_remote_barrier( XPTR( BOOT_CORE_CXY , &global_barrier ) , count );
854
855 // activate other local cores
856 boot_wake_local_cores( boot_info );
857
858 // Wait until all local cores in cluster ready
859 boot_remote_barrier( XPTR( cxy , &local_barrier ) ,
860 boot_info->cores_nr );
861 }
862 }
863 else
864 {
865 /***************************************************************
866 * PHASE C: all non CP0 cores in all clusters execute it
867 **************************************************************/
868
869 // Switch to the INSTRUCTIONS local memory space
870 // to avoid contention at the boot cluster.
871 asm volatile("mtc2 %0, $25" :: "r"(cxy));
872
873 // Get local boot_info_t structure base address.
874 boot_info = (boot_info_t *)seg_kdata_base;
875
876 // Check core information
877 boot_check_core(boot_info, lid);
878
879 // Wait until all local cores in cluster ready
880 boot_remote_barrier( XPTR( cxy , &local_barrier ) , boot_info->cores_nr );
881 }
882
883 // Ech core compute stack pointer to the kernel idle-thread descriptor.
884 // The array of idle-thread descriptors is allocated in the kdata segment,
885 // just after the boot_info structure
886
887 uint32_t sp;
888 uint32_t base;
889 uint32_t offset = sizeof( boot_info_t );
890 uint32_t pmask = CONFIG_PPM_PAGE_MASK;
891 uint32_t psize = CONFIG_PPM_PAGE_SIZE;
892
893 // compute base address of idle thread descriptors array
894 if( offset & pmask ) base = seg_kdata_base + (offset & ~pmask) + psize;
895 else base = seg_kdata_base + offset;
896
897 // compute stack pointer
898 sp = base + ((lid + 1) * CONFIG_THREAD_DESC_SIZE) - 16;
899
900 // Each cores initialise stack pointer,
901 // reset the BEV bit in status register,
902 // register "boot_info" argument in a0,
903 // and jump to kernel_entry.
904 asm volatile( "mfc0 $27, $12 \n"
905 "lui $26, 0xFFBF \n"
906 "ori $26, $26, 0xFFFF \n"
907 "and $27, $27, $26 \n"
908 "mtc0 $27, $12 \n"
909 "move $4, %0 \n"
910 "move $29, %1 \n"
911 "jr %2 \n"
912 :: "r"(boot_info) , "r"(sp) , "r"(kernel_entry) );
913
914} // boot_loader()
Note: See TracBrowser for help on using the repository browser.