2 Copyright � 2013-2015, The AROS Development Team. All rights reserved.
9 #include <exec/types.h>
10 #include <aros/macros.h>
13 #include <utility/tagitem.h>
14 #include <aros/macros.h>
15 #include <aros/kernel.h>
20 #include <hardware/bcm2708.h>
21 #include <hardware/bcm2708_boot.h>
22 #include <hardware/videocore.h>
25 #include "serialdebug.h"
31 #include "devicetree.h"
37 #define ARM_PERIIOBASE (__arm_periiobase)
39 uint32_t __arm_periiobase
= 0;
41 extern void mem_init(void);
42 extern unsigned int uartclock
;
43 extern unsigned int uartdivint
;
44 extern unsigned int uartdivfrac
;
45 extern unsigned int uartbaud
;
47 asm(" .section .aros.startup \n"
48 " .globl bootstrap \n"
49 " .type bootstrap,%function \n"
51 " mrs r4, cpsr_all \n" /* Check if in hypervisor mode */
52 " and r4, r4, #0x1f \n"
57 " cps #0x13 \n" /* Should be in SVC (supervisor) mode already, but just incase.. */
58 " setend be \n" /* Switch to big endian mode */
59 " ldr sp, tmp_stack_ptr \n"
63 " adr r4, continue_boot \n"
65 " mrs r4, cpsr_all \n"
66 " and r4, r4, #0x1f \n"
67 " orr r4, r4, #0x13 \n"
68 " msr SPSR_hyp, r4 \n"
72 ".string \"$VER: arosraspi-be.img v40.46 (" __DATE__
")\"\n"
77 // The bootstrap tmp stack is re-used by the reset handler so we store it at this fixed location
78 static __used
void * tmp_stack_ptr
__attribute__((used
, section(".aros.startup"))) = (void *)(0x1000 - 16);
79 static struct TagItem
*boottag
;
80 static unsigned long *mem_upper
;
81 static void *pkg_image
= NULL
;
82 static uint32_t pkg_size
= 0;
86 static const char bootstrapName
[] = "Bootstrap/ARM v7-a BigEndian";
90 volatile unsigned int *vc_msg
= (unsigned int *) BOOTMEMADDR(bm_mboxmsg
);
92 kprintf("[BOOT] Query VC memory\n");
93 vc_msg
[0] = AROS_LONG2LE(8 * 4);
94 vc_msg
[1] = AROS_LONG2LE(VCTAG_REQ
);
95 vc_msg
[2] = AROS_LONG2LE(VCTAG_GETVCRAM
);
96 vc_msg
[3] = AROS_LONG2LE(8);
102 vcmb_write(VCMB_BASE
, VCMB_PROPCHAN
, (void *)vc_msg
);
103 vc_msg
= vcmb_read(VCMB_BASE
, VCMB_PROPCHAN
);
105 kprintf("[BOOT] Base = %08x, Size = %08x\n", AROS_LE2LONG(vc_msg
[5]), AROS_LE2LONG(vc_msg
[6]));
107 boottag
->ti_Tag
= KRN_VMEMLower
;
108 boottag
->ti_Data
= AROS_LE2LONG(vc_msg
[5]);
111 boottag
->ti_Tag
= KRN_VMEMUpper
;
112 boottag
->ti_Data
= AROS_LE2LONG(vc_msg
[5]) + AROS_LE2LONG(vc_msg
[6]);
115 mmu_map_section(AROS_LE2LONG(vc_msg
[5]), AROS_LE2LONG(vc_msg
[5]), AROS_LE2LONG(vc_msg
[6]), 1, 0, 3, 0);
120 of_node_t
*mem
= dt_find_node("/memory");
122 kprintf("[BOOT] Query system memory\n");
125 of_property_t
*p
= dt_find_property(mem
, "reg");
127 if (p
!= NULL
&& p
->op_length
)
129 uint32_t *addr
= p
->op_value
;
130 uint32_t lower
= AROS_BE2LONG(*addr
++);
131 uint32_t upper
= AROS_BE2LONG(*addr
++);
133 kprintf("[BOOT] System memory range: %08x-%08x\n", lower
, upper
-1);
135 if (((upper
- lower
) >> 20) < 256) {
136 kprintf("[BOOT] MISMATCHED FILES: start.elf and fixup.dat do not fit to each other!\n");
137 while(1) asm volatile("wfi");
140 boottag
->ti_Tag
= KRN_MEMLower
;
141 if ((boottag
->ti_Data
= lower
) < sizeof(struct bcm2708bootmem
))
142 boottag
->ti_Data
= sizeof(struct bcm2708bootmem
); // Skip the *reserved* space for the cpu vectors/boot tmp stack/kernel private data.
145 boottag
->ti_Tag
= KRN_MEMUpper
;
146 boottag
->ti_Data
= upper
;
148 mem_upper
= &boottag
->ti_Data
;
152 mmu_map_section(lower
, lower
, upper
- lower
, 1, 1, 3, 1);
157 void boot(uintptr_t dummy
, uintptr_t arch
, struct tag
* atags
, uintptr_t a
)
159 uint32_t tmp
, initcr
;
160 void (*entry
)(struct TagItem
*);
162 boottag
= tmp_stack_ptr
- BOOT_STACK_SIZE
- BOOT_TAGS_SIZE
;
165 * Disable MMU, enable caches and branch prediction. Also enabled unaligned memory
166 * access. Exceptions are set to run in big-endian mode and this is the mode
167 * in which page tables are written.
169 asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r"(initcr
));
171 tmp
&= ~1; /* Disable MMU */
172 tmp
|= (1 << 2) | (1 << 12) | (1 << 11); /* I and D caches, branch prediction */
173 tmp
= (tmp
& ~2) | (1 << 22); /* Unaligned access enable */
174 tmp
|= (1 << 25); /* EE bit for exceptions set - big endian */
175 /* This bit sets also endianess of page tables */
176 asm volatile ("mcr p15, 0, %0, c1, c0, 0" : : "r"(tmp
));
178 /* Prepare MMU tables but do not load them yet */
181 /* Initialize simplistic local memory allocator */
184 int dt_mem_usage
= mem_avail();
185 /* Parse device tree */
187 dt_mem_usage
-= mem_avail();
189 /* Prepare mapping for peripherals. Use the data from device tree here */
190 of_node_t
*e
= dt_find_node("/soc");
193 of_property_t
*p
= dt_find_property(e
, "ranges");
194 uint32_t *ranges
= p
->op_value
;
195 int32_t len
= p
->op_length
;
199 uint32_t addr_bus
, addr_cpu
;
202 addr_bus
= AROS_BE2LONG(*ranges
++);
203 addr_cpu
= AROS_BE2LONG(*ranges
++);
204 addr_len
= AROS_BE2LONG(*ranges
++);
208 /* If periiobase was not set yet, do it now */
209 if (__arm_periiobase
== 0) {
210 __arm_periiobase
= (uint32_t)addr_cpu
;
213 /* Prepare mapping - device type */
214 mmu_map_section(addr_cpu
, addr_cpu
, addr_len
, 1, 0, 3, 0);
220 while(1) asm volatile("wfe");
224 kprintf("\n\n[BOOT] Big-Endian AROS %s\n", bootstrapName
);
225 kprintf("[BOOT] Booted on %s\n", dt_find_property(dt_find_node("/"), "model")->op_value
);
227 /* first of all, store the arch for the kernel to use .. */
228 boottag
->ti_Tag
= KRN_Platform
;
229 boottag
->ti_Data
= (IPTR
)arch
;
233 Check if device tree contains /soc/local_intc entry. In this case assume RasPi 2 or 3 with smp setup.
234 Neither PiZero nor classic Pi provide this entry.
236 e
= dt_find_node("/__symbols__");
239 of_property_t
*p
= dt_find_property(e
, "local_intc");
243 kprintf("[BOOT] local_intc points to %s\n", p
->op_value
);
245 e
= dt_find_node(p
->op_value
);
246 p
= dt_find_property(e
, "reg");
247 uint32_t *reg
= p
->op_value
;
249 kprintf("[BOOT] Mapping local interrupt area at %p-%p\n", reg
[0], reg
[0] + reg
[1] - 1);
251 /* Prepare mapping - device type */
252 mmu_map_section(reg
[0], reg
[0], reg
[1] < 0x100000 ? 0x100000 : reg
[1], 0, 0, 3, 0);
258 e
= dt_find_node("/leds");
262 kprintf("[BOOT] Configuring LEDs\n");
263 ForeachNode(&e
->on_children
, led
)
265 of_property_t
*p
= dt_find_property(led
, "gpios");
267 if (p
&& p
->op_length
>= 8) {
268 uint32_t *data
= p
->op_value
;
269 uint32_t phandle
= AROS_BE2LONG(data
[0]);
270 gpio
= AROS_BE2LONG(data
[1]);
271 of_node_t
*bus
= dt_find_node_by_phandle(phandle
);
273 kprintf("[BOOT] %s: GPIO%d (%08x %08x %08x)\n", led
->on_name
, gpio
,
274 AROS_BE2LONG(data
[0]), AROS_BE2LONG(data
[1]), AROS_BE2LONG(data
[2]));
277 kprintf("[BOOT] LED attached to %s\n", bus
->on_name
);
279 if (strncmp(bus
->on_name
, "gpio", 4) == 0)
281 int gpio_sel
= gpio
/ 10;
282 int gpio_soff
= 3 * (gpio
- 10 * gpio_sel
);
284 kprintf("[BOOT] GPFSEL=%x, bit=%d\n", gpio_sel
* 4, gpio_soff
);
286 /* Configure GPIO as output */
287 tmp
= rd32le(GPFSEL0
+ 4*gpio_sel
);
288 tmp
&= ~(7 << gpio_soff
); // GPIO 47 = 001 - output
289 tmp
|= (1 << gpio_soff
);
290 wr32le(GPFSEL0
+ 4*gpio_sel
, tmp
);
293 wr32le(GPCLR0
+ 4 * (gpio
/ 32), 1 << (gpio
% 32));
300 kprintf("[BOOT] DT memory usage: %d\n", dt_mem_usage
);
302 boottag
->ti_Tag
= KRN_BootLoader
;
303 boottag
->ti_Data
= (IPTR
)bootstrapName
;
308 boottag
->ti_Tag
= KRN_FuncPutC
;
309 boottag
->ti_Data
= (IPTR
)fb_Putc
;
314 kprintf("[BOOT] UART clock speed: %d\n", uartclock
);
315 kprintf("[BOOT] using %d.%d divisor for %d baud\n", uartdivint
, uartdivfrac
, uartbaud
);
317 asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r"(tmp
));
318 kprintf("[BOOT] control register init:%08x, now:%08x\n", initcr
, tmp
);
320 asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r"(tmp
));
321 kprintf("[BOOT] main id register: %08x\n", tmp
);
327 kprintf("[BOOT] Bootstrap @ %08x-%08x\n", &__bootstrap_start
, &__bootstrap_end
);
329 boottag
->ti_Tag
= KRN_ProtAreaStart
;
330 boottag
->ti_Data
= (IPTR
)&__bootstrap_start
;
333 boottag
->ti_Tag
= KRN_ProtAreaEnd
;
334 boottag
->ti_Data
= (IPTR
)&__bootstrap_end
;
337 kprintf("[BOOT] Topmost address for kernel: %p\n", *mem_upper
);
339 e
= dt_find_node("/chosen");
342 of_property_t
*p
= dt_find_property(e
, "linux,initrd-start");
344 pkg_image
= (void*)(*((uint32_t *)p
->op_value
));
348 p
= dt_find_property(e
, "linux,initrd-end");
350 pkg_size
= *((uint32_t *)p
->op_value
) - (uint32_t)pkg_image
;
355 kprintf("[BOOT] BSP image: %08x-%08x\n", pkg_image
, (int32_t)pkg_image
+ pkg_size
- 1);
357 kprintf("[BOOT] mem_avail=%d\n", mem_avail());
359 unsigned long total_size_ro
= 0, total_size_rw
= 0;
364 *mem_upper
= *mem_upper
& ~4095;
366 unsigned long kernel_phys
= *mem_upper
;
367 unsigned long kernel_virt
= kernel_phys
;
369 uint32_t size_ro
, size_rw
;
371 /* Calculate total size of kernel and modules */
372 getElfSize(&_binary_core_bin_start
, &size_rw
, &size_ro
);
374 total_size_ro
= size_ro
= (size_ro
+ 4095) & ~4095;
375 total_size_rw
= size_rw
= (size_rw
+ 4095) & ~4095;
377 if (pkg_image
&& pkg_size
)
379 uint8_t *base
= pkg_image
;
381 if (base
[0] == 0x7f && base
[1] == 'E' && base
[2] == 'L' && base
[3] == 'F')
383 getElfSize(base
, &size_rw
, &size_ro
);
385 total_size_ro
+= (size_ro
+ 4095) & ~4095;
386 total_size_rw
+= (size_rw
+ 4095) & ~4095;
388 else if (base
[0] == 'P' && base
[1] == 'K' && base
[2] == 'G' && base
[3] == 0x01)
390 uint8_t *file
= base
+4;
391 uint32_t total_length
= AROS_BE2LONG(*(uint32_t*)file
); /* Total length of the module */
392 const uint8_t *file_end
= base
+total_length
;
393 uint32_t len
, cnt
= 0;
397 while(file
< file_end
)
399 //const char *filename = remove_path(file+4);
401 /* get text length */
402 len
= AROS_BE2LONG(*(uint32_t*)file
);
406 len
= AROS_BE2LONG(*(uint32_t *)file
);
410 getElfSize(file
, &size_rw
, &size_ro
);
412 total_size_ro
+= (size_ro
+ 4095) & ~4095;
413 total_size_rw
+= (size_rw
+ 4095) & ~4095;
415 /* go to the next file */
422 /* Reserve space for flattened device tree */
423 total_size_ro
+= (dt_total_size() + 31) & ~31;
425 /* Reserve space for unpacked device tree */
426 total_size_ro
+= (dt_mem_usage
+ 31) & ~31;
428 /* Align space to 1MB boundary - it will save some space in MMU tables */
429 total_size_ro
= (total_size_ro
+ 1024*1024-1) & 0xfff00000;
430 total_size_rw
= (total_size_rw
+ 1024*1024-1) & 0xfff00000;
432 kernel_phys
= *mem_upper
- total_size_ro
- total_size_rw
;
433 kernel_virt
= KERNEL_VIRT_ADDRESS
;
435 bzero((void*)kernel_phys
, total_size_ro
+ total_size_rw
);
437 kprintf("[BOOT] Physical address of kernel: %p\n", kernel_phys
);
438 kprintf("[BOOT] Virtual address of kernel: %p\n", kernel_virt
);
440 if (dt_total_size() > 0)
442 long dt_size
= (dt_total_size() + 31) & ~31;
443 /* Copy device tree to the end of kernel RO area */
444 memcpy((void*)(kernel_phys
+ total_size_ro
- dt_size
), atags
, dt_size
);
445 fdt
= (void*)(kernel_virt
+ total_size_ro
- dt_size
);
447 /* Store device tree */
448 boottag
->ti_Tag
= KRN_FlattenedDeviceTree
;
449 boottag
->ti_Data
= (IPTR
)kernel_virt
+ total_size_ro
- dt_size
;
452 kprintf("[BOOT] Device tree (size: %d) moved to %p, phys %p\n", dt_total_size(), boottag
[-1].ti_Data
, kernel_phys
+ total_size_ro
- dt_size
);
455 *mem_upper
= kernel_phys
;
457 DBOOT(kprintf("[BOOT] Topmost memory address: %p\n", *mem_upper
));
459 /* Unmap memory at physical location of kernel. In future this has to be eventually changed */
460 mmu_unmap_section(kernel_phys
, total_size_ro
+ total_size_rw
);
462 /* map kernel memory for user access */
463 mmu_map_section(kernel_phys
, kernel_virt
, total_size_ro
, 1, 1, 2, 1);
464 mmu_map_section(kernel_phys
+ total_size_ro
, kernel_virt
+ total_size_ro
, total_size_rw
, 1, 1, 3, 1);
466 entry
= (void (*)(struct TagItem
*))kernel_virt
;
468 initAllocator(kernel_phys
, kernel_phys
+ total_size_ro
, kernel_virt
- kernel_phys
);
470 boottag
->ti_Tag
= KRN_KernelLowest
;
471 boottag
->ti_Data
= kernel_virt
;
474 boottag
->ti_Tag
= KRN_KernelHighest
;
475 boottag
->ti_Data
= kernel_virt
+ ((total_size_ro
+ 4095) & ~4095) + ((total_size_rw
+ 4095) & ~4095);
478 boottag
->ti_Tag
= KRN_KernelPhysLowest
;
479 boottag
->ti_Data
= kernel_phys
;
482 loadElf(&_binary_core_bin_start
);
484 if (pkg_image
&& pkg_size
)
486 uint8_t *base
= pkg_image
;
488 if (base
[0] == 0x7f && base
[1] == 'E' && base
[2] == 'L' && base
[3] == 'F')
490 kprintf("[BOOT] Kernel image is ELF file\n");
494 else if (base
[0] == 'P' && base
[1] == 'K' && base
[2] == 'G' && base
[3] == 0x01)
496 kprintf("[BOOT] Kernel image is a package:\n");
498 uint8_t *file
= base
+4;
499 uint32_t total_length
= AROS_BE2LONG(*(uint32_t*)file
); /* Total length of the module */
500 const uint8_t *file_end
= base
+total_length
;
501 uint32_t len
, cnt
= 0;
503 kprintf("[BOOT] Package size: %dKB", total_length
>> 10);
507 while(file
< file_end
)
509 const char *filename
= remove_path(file
+4);
511 /* get text length */
512 len
= AROS_BE2LONG(*(uint32_t*)file
);
513 /* display the file name */
515 kprintf("\n[BOOT] %s", filename
);
517 kprintf(", %s", filename
);
521 len
= AROS_BE2LONG(*(uint32_t *)file
);
527 /* go to the next file */
535 arm_flush_cache(kernel_phys
, total_size_ro
+ total_size_rw
);
537 boottag
->ti_Tag
= KRN_KernelBss
;
538 boottag
->ti_Data
= (IPTR
)tracker
;
544 int memory_used
= mem_used();
546 /* If device tree is in high kernel memory then parse it again */
547 if (dt_total_size() > 0)
549 void * dt_location
= (void *)(KERNEL_VIRT_ADDRESS
+ total_size_ro
- ((dt_total_size() + 31) & ~31) - ((dt_mem_usage
+ 31) & ~31));
550 kprintf("[BOOT] Creating device tree in kernel area at %p\n", dt_location
);
552 explicit_mem_init(dt_location
, (dt_mem_usage
+ 31) & ~31);
555 boottag
->ti_Tag
= KRN_OpenFirmwareTree
;
556 boottag
->ti_Data
= (IPTR
)dt_location
;
559 e
= dt_find_node("/chosen");
562 of_property_t
*p
= dt_find_property(e
, "bootargs");
565 boottag
->ti_Tag
= KRN_CmdLine
;
566 boottag
->ti_Data
= (IPTR
)p
->op_value
;
569 kprintf("[BOOT] Kernel parameters @ %p: %s\n", p
->op_value
, p
->op_value
);
574 boottag
->ti_Tag
= TAG_DONE
;
575 boottag
->ti_Data
= 0;
577 kprintf("[BOOT] Kernel taglist contains %d entries\n", ((intptr_t)boottag
- (intptr_t)(tmp_stack_ptr
- BOOT_STACK_SIZE
- BOOT_TAGS_SIZE
))/sizeof(struct TagItem
));
578 kprintf("[BOOT] Bootstrap wasted %d bytes of memory for kernels use\n", memory_used
);
580 kprintf("[BOOT] Heading over to AROS kernel @ %08x\n", entry
);
582 entry((struct TagItem
*)(tmp_stack_ptr
- BOOT_STACK_SIZE
- BOOT_TAGS_SIZE
));
584 kprintf("[BOOT] Back? Something wrong happened...\n");
586 while(1) asm volatile("wfe");