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"
30 #include "devicetree.h"
35 #define ARM_PERIIOBASE (__arm_periiobase)
37 uint32_t __arm_periiobase
;
39 extern void mem_init(void);
40 extern unsigned int uartclock
;
41 extern unsigned int uartdivint
;
42 extern unsigned int uartdivfrac
;
43 extern unsigned int uartbaud
;
45 asm(" .section .aros.startup \n"
46 " .globl bootstrap \n"
47 " .type bootstrap,%function \n"
49 " mrs r4, cpsr_all \n" /* Check if in hypervisor mode */
50 " and r4, r4, #0x1f \n"
55 " cps #0x13 \n" /* Should be in SVC (supervisor) mode already, but just incase.. */
56 " setend be \n" /* Switch to big endian mode */
57 " ldr sp, tmp_stack_ptr \n"
61 " ldr r4, =continue_boot \n"
63 " mrs r4, cpsr_all \n"
64 " and r4, r4, #0x1f \n"
65 " orr r4, r4, #0x13 \n"
66 " msr SPSR_hyp, r4 \n"
70 ".string \"$VER: arosraspi.img v40.46 (" __DATE__
")\"\n"
75 // The bootstrap tmp stack is re-used by the reset handler so we store it at this fixed location
76 static __used
void * tmp_stack_ptr
__attribute__((used
, section(".aros.startup"))) = (void *)(0x1000 - 16);
77 static struct TagItem
*boottag
;
78 static unsigned long *mem_upper
;
79 static void *pkg_image
= NULL
;
80 static uint32_t pkg_size
= 0;
84 static const char bootstrapName
[] = "Bootstrap/ARM BCM2708";
87 void check_device_tree(void *dt
)
89 struct fdt_header
*hdr
= dt
;
90 char * strings
= NULL
;
91 uint32_t * data
= NULL
;
94 kprintf("[BOOT] Checking device tree at %p\n", dt
);
95 kprintf("[BOOT] magic=%08x\n", hdr
->magic
);
96 kprintf("[BOOT] size=%d\n", hdr
->totalsize
);
97 kprintf("[BOOT] off_dt_struct=%d\n", hdr
->off_dt_struct
);
98 kprintf("[BOOT] off_dt_strings=%d\n", hdr
->off_dt_strings
);
99 kprintf("[BOOT] off_mem_rsvmap=%d\n", hdr
->off_mem_rsvmap
);
101 strings
= dt
+ hdr
->off_dt_strings
;
102 data
= dt
+ hdr
->off_dt_struct
;
104 if (hdr
->off_mem_rsvmap
) {
105 struct fdt_reserve_entry
*rsrvd
= dt
+ hdr
->off_mem_rsvmap
;
107 while (rsrvd
->address
!= 0 || rsrvd
->size
!= 0) {
108 kprintf("[BOOT] reserved: %08x-%08x\n", (uint32_t)rsrvd
->address
, (uint32_t)(rsrvd
->address
+ rsrvd
->size
- 1));
123 kprintf("[BOOT] %snode: %s\n", &fill
[depth
], (char *)data
);
125 data
+= (strlen((char *)data
) + 4) / 4;
129 uint32_t len
= *data
++;
130 uint32_t nameoff
= *data
++;
131 uint8_t *propval
= (uint8_t *)data
;
132 kprintf("[BOOT] %s %s = ", &fill
[depth
], &strings
[nameoff
], len
);
136 kprintf(" %02x", *propval
++);
145 } while (token
!= FDT_END
);
150 volatile unsigned int *vc_msg
= (unsigned int *) BOOTMEMADDR(bm_mboxmsg
);
152 kprintf("[BOOT] Query VC memory\n");
153 vc_msg
[0] = AROS_LONG2LE(8 * 4);
154 vc_msg
[1] = AROS_LONG2LE(VCTAG_REQ
);
155 vc_msg
[2] = AROS_LONG2LE(VCTAG_GETVCRAM
);
156 vc_msg
[3] = AROS_LONG2LE(8);
162 vcmb_write((void *)VCMB_BASE
, VCMB_PROPCHAN
, (void *)vc_msg
);
163 vc_msg
= vcmb_read((void *)VCMB_BASE
, VCMB_PROPCHAN
);
165 kprintf("[BOOT] Base = %08x, Size = %08x\n", AROS_LE2LONG(vc_msg
[5]), AROS_LE2LONG(vc_msg
[6]));
167 boottag
->ti_Tag
= KRN_VMEMLower
;
168 boottag
->ti_Data
= AROS_LE2LONG(vc_msg
[5]);
171 boottag
->ti_Tag
= KRN_VMEMUpper
;
172 boottag
->ti_Data
= AROS_LE2LONG(vc_msg
[5]) + AROS_LE2LONG(vc_msg
[6]);
175 mmu_map_section(AROS_LE2LONG(vc_msg
[5]), AROS_LE2LONG(vc_msg
[5]), AROS_LE2LONG(vc_msg
[6]), 1, 0, 3, 0);
178 void boot(uintptr_t dummy
, uintptr_t arch
, struct tag
* atags
, uintptr_t a
)
180 uint32_t tmp
, initcr
;
182 void (*entry
)(struct TagItem
*);
188 * Disable MMU, enable caches and branch prediction. Also enabled unaligned memory
189 * access. Exceptions are set to run in big-endian mode and this is the mode
190 * in which page tables are written.
192 asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r"(initcr
));
194 tmp
&= ~1; /* Disable MMU */
195 tmp
|= (1 << 2) | (1 << 12) | (1 << 11); /* I and D caches, branch prediction */
196 tmp
= (tmp
& ~2) | (1 << 22); /* Unaligned access enable */
197 tmp
|= (1 << 25); /* EE bit for exceptions set - big endian */
198 /* This bit sets also endianess of page tables */
199 asm volatile ("mcr p15, 0, %0, c1, c0, 0" : : "r"(tmp
));
208 Check processor type - armv6 is old raspberry pi with SOC IO base at 0x20000000.
209 armv7 will be raspberry pi 2 with SOC IO base at 0x3f000000
211 asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r" (tmp
));
213 tmp
= (tmp
>> 4) & 0xfff;
215 /* tmp == 7 means armv6 architecture. */
216 if (tmp
== 0xc07) /* armv7, also RaspberryPi 2 */
218 __arm_periiobase
= BCM2836_PERIPHYSBASE
;
221 /* Clear terminal screen */
222 kprintf("\033[0H\033[0J");
224 /* prepare map for core boot vector(s) */
225 mmu_map_section(0x40000000, 0x40000000, 0x100000, 0, 0, 3, 0);
229 __arm_periiobase
= BCM2835_PERIPHYSBASE
;
230 /* Need to detect the plus board here in order to control LEDs properly */
232 kprintf("\033[0H\033[0J");
235 /* Prepare map for MMIO registers */
236 mmu_map_section(__arm_periiobase
, __arm_periiobase
, ARM_PERIIOSIZE
, 1, 0, 3, 0);
238 boottag
= tmp_stack_ptr
- BOOT_STACK_SIZE
- BOOT_TAGS_SIZE
;
240 /* first of all, store the arch for the kernel to use .. */
241 boottag
->ti_Tag
= KRN_Platform
;
242 boottag
->ti_Data
= (IPTR
)arch
;
250 * Either B+ or rpi2 board. Uses two leds (power and activity) on GPIOs
251 * 47 and 35. Enable both leds as output and turn both of them off.
253 * The power led will be brought back up once AROS boots.
256 tmp
= AROS_LE2LONG(*(volatile unsigned int *)GPFSEL4
);
257 tmp
&= ~(7 << 21); // GPIO 47 = 001 - output
259 *(volatile unsigned int *)GPFSEL4
= AROS_LONG2LE(tmp
);
261 tmp
= AROS_LE2LONG(*(volatile unsigned int *)GPFSEL3
);
262 tmp
&= ~(7 << 15); // GPIO 35 = 001 - output
264 *(volatile unsigned int *)GPFSEL3
= AROS_LONG2LE(tmp
);
267 *(volatile unsigned int *)GPCLR1
= AROS_LONG2LE((1 << (47-32)));
268 *(volatile unsigned int *)GPCLR1
= AROS_LONG2LE((1 << (35-32)));
273 * Classic rpi board has only one controlable LED - activity on GPIO 16. Turn it
274 * off now, kernel.resource will bring it back later.
277 tmp
= AROS_LE2LONG(*(volatile unsigned int *)GPFSEL1
);
278 tmp
&= ~(7 << 18); // GPIO 16 = 001 - output
280 *(volatile unsigned int *)GPFSEL1
= AROS_LONG2LE(tmp
);
282 *(volatile unsigned int *)GPSET0
= AROS_LONG2LE((1 << 16));
288 boottag
->ti_Tag
= KRN_BootLoader
;
289 boottag
->ti_Data
= (IPTR
)bootstrapName
;
295 boottag
->ti_Tag
= KRN_FuncPutC
;
296 boottag
->ti_Data
= (IPTR
)fb_Putc
;
302 kprintf("[BOOT] Big-Endian AROS %s\n", bootstrapName
);
303 kprintf("[BOOT] Arguments: %08x, %08x, %08x, %08x\n", dummy
, arch
, atags
, a
);
306 kprintf("[BOOT] UART clock speed: %d\n", uartclock
);
307 kprintf("[BOOT] using %d.%d divisor for %d baud\n", uartdivint
, uartdivfrac
, uartbaud
);
309 asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r"(tmp
));
310 kprintf("[BOOT] control register init:%08x, now:%08x\n", initcr
, tmp
);
312 asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r"(tmp
));
313 kprintf("[BOOT] main id register: %08x\n", tmp
);
318 kprintf("[BOOT] Booted on %s\n", dt_find_property(dt_find_node("/"), "model")->dtp_value
);
320 // parse_atags((void *)0x100);
323 kprintf("[BOOT] Bootstrap @ %08x-%08x\n", &__bootstrap_start
, &__bootstrap_end
);
325 boottag
->ti_Tag
= KRN_ProtAreaStart
;
326 boottag
->ti_Data
= (IPTR
)&__bootstrap_start
;
329 boottag
->ti_Tag
= KRN_ProtAreaEnd
;
330 boottag
->ti_Data
= (IPTR
)&__bootstrap_end
;
333 kprintf("[BOOT] Topmost address for kernel: %p\n", *mem_upper
);
337 *mem_upper
= *mem_upper
& ~4095;
339 unsigned long kernel_phys
= *mem_upper
;
340 unsigned long kernel_virt
= kernel_phys
;
342 unsigned long total_size_ro
, total_size_rw
;
343 uint32_t size_ro
, size_rw
;
345 /* Calculate total size of kernel and modules */
346 getElfSize(&_binary_core_bin_start
, &size_rw
, &size_ro
);
348 total_size_ro
= size_ro
= (size_ro
+ 4095) & ~4095;
349 total_size_rw
= size_rw
= (size_rw
+ 4095) & ~4095;
351 if (pkg_image
&& pkg_size
)
353 uint8_t *base
= pkg_image
;
355 if (base
[0] == 0x7f && base
[1] == 'E' && base
[2] == 'L' && base
[3] == 'F')
357 getElfSize(base
, &size_rw
, &size_ro
);
359 total_size_ro
+= (size_ro
+ 4095) & ~4095;
360 total_size_rw
+= (size_rw
+ 4095) & ~4095;
362 else if (base
[0] == 'P' && base
[1] == 'K' && base
[2] == 'G' && base
[3] == 0x01)
364 uint8_t *file
= base
+4;
365 uint32_t total_length
= AROS_BE2LONG(*(uint32_t*)file
); /* Total length of the module */
366 const uint8_t *file_end
= base
+total_length
;
367 uint32_t len
, cnt
= 0;
371 while(file
< file_end
)
373 //const char *filename = remove_path(file+4);
375 /* get text length */
376 len
= AROS_BE2LONG(*(uint32_t*)file
);
380 len
= AROS_BE2LONG(*(uint32_t *)file
);
384 getElfSize(file
, &size_rw
, &size_ro
);
386 total_size_ro
+= (size_ro
+ 4095) & ~4095;
387 total_size_rw
+= (size_rw
+ 4095) & ~4095;
389 /* go to the next file */
396 total_size_ro
= (total_size_ro
+ 1024*1024-1) & 0xfff00000;
397 total_size_rw
= (total_size_rw
+ 1024*1024-1) & 0xfff00000;
399 kernel_phys
= *mem_upper
- total_size_ro
- total_size_rw
;
400 kernel_virt
= 0xf8000000;
402 kprintf("[BOOT] Physical address of kernel: %p\n", kernel_phys
);
403 kprintf("[BOOT] Virtual address of kernel: %p\n", kernel_virt
);
405 *mem_upper
= kernel_phys
;
407 DBOOT(kprintf("[BOOT] Topmost memory address: %p\n", *mem_upper
));
409 /* Unmap memory at physical location of kernel. In future this has to be eventually changed */
410 mmu_unmap_section(kernel_phys
, total_size_ro
+ total_size_rw
);
412 /* map kernel memory for user access */
413 mmu_map_section(kernel_phys
, kernel_virt
, total_size_ro
, 1, 1, 2, 1);
414 mmu_map_section(kernel_phys
+ total_size_ro
, kernel_virt
+ total_size_ro
, total_size_rw
, 1, 1, 3, 1);
416 entry
= (void (*)(struct TagItem
*))kernel_virt
;
418 initAllocator(kernel_phys
, kernel_phys
+ total_size_ro
, kernel_virt
- kernel_phys
);
420 boottag
->ti_Tag
= KRN_KernelLowest
;
421 boottag
->ti_Data
= kernel_virt
;
424 boottag
->ti_Tag
= KRN_KernelHighest
;
425 boottag
->ti_Data
= kernel_virt
+ ((total_size_ro
+ 4095) & ~4095) + ((total_size_rw
+ 4095) & ~4095);
428 boottag
->ti_Tag
= KRN_KernelPhysLowest
;
429 boottag
->ti_Data
= kernel_phys
;
432 loadElf(&_binary_core_bin_start
);
434 if (pkg_image
&& pkg_size
)
436 uint8_t *base
= pkg_image
;
438 if (base
[0] == 0x7f && base
[1] == 'E' && base
[2] == 'L' && base
[3] == 'F')
440 kprintf("[BOOT] Kernel image is ELF file\n");
442 getElfSize(base
, &size_rw
, &size_ro
);
444 total_size_ro
+= (size_ro
+ 4095) & ~4095;
445 total_size_rw
+= (size_rw
+ 4095) & ~4095;
447 else if (base
[0] == 'P' && base
[1] == 'K' && base
[2] == 'G' && base
[3] == 0x01)
449 kprintf("[BOOT] Kernel image is a package:\n");
451 uint8_t *file
= base
+4;
452 uint32_t total_length
= AROS_BE2LONG(*(uint32_t*)file
); /* Total length of the module */
453 const uint8_t *file_end
= base
+total_length
;
454 uint32_t len
, cnt
= 0;
456 kprintf("[BOOT] Package size: %dKB", total_length
>> 10);
460 while(file
< file_end
)
462 const char *filename
= remove_path(file
+4);
464 /* get text length */
465 len
= AROS_BE2LONG(*(uint32_t*)file
);
466 /* display the file name */
468 kprintf("\n[BOOT] %s", filename
);
470 kprintf(", %s", filename
);
474 len
= AROS_BE2LONG(*(uint32_t *)file
);
480 total_size_ro
+= (size_ro
+ 4095) & ~4095;
481 total_size_rw
+= (size_rw
+ 4095) & ~4095;
483 /* go to the next file */
491 arm_flush_cache(kernel_phys
, total_size_ro
+ total_size_rw
);
493 boottag
->ti_Tag
= KRN_KernelBss
;
494 boottag
->ti_Data
= (IPTR
)tracker
;
498 boottag
->ti_Tag
= TAG_DONE
;
499 boottag
->ti_Data
= 0;
501 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
));
502 kprintf("[BOOT] Bootstrap wasted %d bytes of memory for kernels use\n", mem_used() );
506 kprintf("[BOOT] Heading over to AROS kernel @ %08x\n", entry
);
508 entry((struct TagItem
*)(tmp_stack_ptr
- BOOT_STACK_SIZE
- BOOT_TAGS_SIZE
));
510 kprintf("[BOOT] Back? Something wrong happened...\n");
512 while(1) asm volatile("wfe");