- Rethink bootstrap workings: Use more c and less asm
[AROS.git] / arch / arm-sun4i / boot / boot.c
blobeeb769b234639129882ec40a36ee16b4bcbc4ca8
1 /*
2 Copyright © 2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
9 #include <inttypes.h>
10 #include <asm/cpu.h>
11 #include <asm/arm/mmu.h>
12 #include <asm/arm/cp15.h>
13 #include <utility/tagitem.h>
14 #include <aros/macros.h>
15 #include <string.h>
16 #include <stdlib.h>
18 #include "boot.h"
19 #include "atags.h"
20 #include "elf.h"
22 #include <hardware/sun4i/platform.h>
24 /* Parse ATAGS to find end of DRAM (align on mebibyte (or megabyte...) boundary) and set stack pointer there. "Push" ATAGS in stack and jump to C */
25 asm(" .section .aros.startup \n"
26 " .globl bootstrap \n"
27 " .type bootstrap,%function \n"
28 " \n"
29 "bootstrap: \n"
30 " mov r0, #0 \n"
31 " mov r4, #2 \n" /* Size of ATAGS + ATAG_NONE */
32 " mov sp, r0 \n"
33 " \n"
34 " mov r0, r2 \n"
35 " \n"
36 " mov r3, #0x0002 \n" /* ATAG_MEM */
37 " movt r3, #0x5441 \n"
38 " b .get_tag \n"
39 " \n"
40 ".tag_compare: \n"
41 " ldr ip, [r0, #4] \n"
42 " cmp ip, r3 \n"
43 " bne .get_tag \n"
44 " \n"
45 " cmp sp, #0 \n" /* Allow only one ATAG_MEM tag, else we get confused */
46 " bne .fancy_error_loop \n"
47 " \n"
48 " ldr sp, [r0, #12] \n" /* Initial stackpointer is end of DRAM */
49 " ldr r5, [r0, #8] \n"
50 " add sp, sp, r5 \n" /* Align on last mebibyte (or megabyte...) */
51 " lsr sp, sp, #20 \n"
52 " lsl sp, sp, #20 \n" /* sp = 0x8000 0000 on pcDuino (0x4000 0000 - 0x7fff ffff DRAM)*/
53 " \n"
54 ".get_tag: \n"
55 " ldr ip, [r0] \n"
56 " cmp ip, #0 \n"
57 " add r0, r0, ip, lsl #2 \n"
58 " add r4, r4, ip \n"
59 " bne .tag_compare \n"
60 " \n"
61 " cmp sp, #0 \n"
62 " beq .fancy_error_loop \n"
63 " \n"
64 " sub sp, sp, r4, lsl #2 \n" /* "Push" ATAGs in the stack */
65 " mov r0, sp \n"
66 ".atag_copy: \n"
67 " ldr r3, [r2], #4 \n"
68 " str r3, [r0], #4 \n"
69 " subs r4, r4, #1 \n"
70 " bne .atag_copy \n"
71 " \n"
72 " mov r2, sp \n"
73 " mov r0, #0 \n"
74 " b boot \n"
75 " \n"
76 ".fancy_error_loop: \n"
77 " b . \n");
79 void setup_mmu(uint32_t kernel_phys, uint32_t kernel_virt, uint32_t mem_lower, uint32_t mem_upper) {
81 uint32_t i;
83 kprintf("[BOOT] MMU kernel_phys %08x\n", kernel_phys);
84 kprintf("[BOOT] MMU kernel_virt %08x\n", kernel_virt);
85 kprintf("[BOOT] MMU mem_lower %08x\n", mem_lower);
86 kprintf("[BOOT] MMU mem_upper %08x\n", mem_upper-1);
88 /* We know the virtual address but not the physical */
89 pde_t *page_dir = 0xfffec000-(kernel_virt-kernel_phys);
90 kprintf("[BOOT] First level MMU page at %08x\n", page_dir);
92 /* Clear page dir */
93 for (i=0; i < 4096; i++) {
94 page_dir[i].raw = 0;
97 // 1:1 memory mapping
98 for (i=(mem_lower >> 20); i < (mem_upper >> 20); i++) {
99 //kprintf("[BOOT] Memory mapping page %d\n", i);
100 //page_dir[i].raw = 0;
101 page_dir[i].section.type = PDE_TYPE_SECTION;
102 page_dir[i].section.b = 0;
103 page_dir[i].section.c = 1; // Cacheable
104 page_dir[i].section.ap = 3; // All can read&write
105 page_dir[i].section.base_address = i;
108 // v:p memory mapping
109 for (i=(kernel_virt >> 20); i <= (0xffffffff >> 20); i++) {
110 kprintf("[BOOT] Kernel mapping page %d phys %08x -> virt %08x\n", i, (kernel_phys)+((i << 20)-(kernel_virt)), i << 20);
111 //page_dir[i].raw = 0;
112 page_dir[i].section.type = PDE_TYPE_SECTION;
113 page_dir[i].section.b = 0;
114 page_dir[i].section.c = 1; // Cacheable
115 page_dir[i].section.ap = 3; // All can read&write
116 page_dir[i].section.base_address = (kernel_phys >> 20)+(i-(kernel_virt >> 20));
119 /* Write page_dir address to ttbr0 */
120 asm volatile ("mcr p15, 0, %0, c2, c0, 0"::"r"(page_dir));
121 /* Write ttbr control N = 0 (use only ttbr0) */
122 asm volatile ("mcr p15, 0, %0, c2, c0, 2"::"r"(0));
126 void boot(uintptr_t dummy, uintptr_t arch, struct tag *atags) {
128 struct tag *t = NULL;
129 struct TagItem tags[128];
130 struct TagItem *tag = &tags[0];
132 uint32_t mem_upper = 0;
133 uint32_t mem_lower = 0;
134 uint32_t kernel_phys = 0;
135 uint32_t kernel_virt = 0;
137 void *pkg_image;
138 uint32_t pkg_size;
140 uint32_t tmp;
142 /* Disable MMU, level one data cache and strict alignment fault checking */
143 CP15_C1CR_Clear(C1CRF_C|C1CRF_A|C1CRF_M);
145 /* High exception vectors selected, address range = 0xFFFF0000-0xFFFF001C */
146 CP15_C1CR_Set(C1CRF_V);
148 /* Set cp10 and cp11 for Privileged and User mode access */
149 CP15_C1CACR_All(C1CACRV_CPAP(10)|C1CACRV_CPAP(11));
151 /* Enable VFP (NEON in our case) */
152 fmxr(cr8, fmrx(cr8) | 1 << 30);
154 void (*entry)(struct TagItem *tags) = NULL;
156 kprintf("[BOOT] AROS for sun4i (" SUN4I_PLATFORM_NAME ") bootstrap\n");
157 asm volatile ("mov %0, sp":"=r"(tmp));
158 kprintf("[BOOT] Stack @ %08x\n", tmp);
160 tag->ti_Tag = KRN_BootLoader;
161 tag->ti_Data = (IPTR)"Bootstrap/sun4i (" SUN4I_PLATFORM_NAME ") ARM";
162 tag++;
164 kprintf("[BOOT] Parsing ATAGS %x\n", tags);
166 for_each_tag(t, atags) {
167 kprintf("[BOOT] (%x-%x) tag %08x (%d): ", t, (uint32_t)t+(t->hdr.size<<2)-1, t->hdr.tag, t->hdr.size);
169 switch (t->hdr.tag) {
171 case ATAG_MEM: {
172 mem_lower = t->u.mem.start;
173 mem_upper = t->u.mem.start+t->u.mem.size;
174 kprintf("Memory (%08x-%08x)\n", mem_lower, mem_upper-1);
176 break;
178 case ATAG_CMDLINE: {
179 kprintf("CMDLine: \"%s\"\n", t->u.cmdline.cmdline);
180 tag->ti_Tag = KRN_CmdLine;
181 tag->ti_Data = (intptr_t)t->u.cmdline.cmdline;
182 tag++;
184 break;
186 case ATAG_INITRD2: {
187 kprintf("RAMDISK: (%08x-%08x)\n", t->u.initrd.start, t->u.initrd.size + t->u.initrd.start - 1);
188 pkg_image = (void *)t->u.initrd.start;
189 pkg_size = t->u.initrd.size;
191 break;
193 default: {
194 kprintf("IGN...\n");
196 break;
201 if(t->hdr.size == 0) {
202 kprintf("[BOOT] (%x-%x) tag %08x (%d): ATAG_NONE\n", t, (uint32_t)t+(2<<2)-1, t->hdr.tag, 2);
205 kprintf("[BOOT] Bootstrap @ %08x-%08x\n", &__bootstrap_start, &__bootstrap_end);
207 if (mem_upper) {
209 mem_upper -= MEM_OFFSET_VECTOR; /* Preserve DRAM for vectors (virtual 0xffff 0000 - 0xffff 003f) */
210 kprintf("[BOOT] Vectors @%p\n", mem_upper);
212 mem_upper -= MEM_OFFSET_MMU1; /* Preserve DRAM for top level mmu table (MMU1) 16kb boundary and size */
213 kprintf("[BOOT] MMU1 @%p\n", mem_upper);
215 kernel_phys = mem_upper;
216 kernel_virt = kernel_phys;
218 uint32_t total_size_ro;
219 uint32_t total_size_rw;
220 uint32_t size_ro;
221 uint32_t size_rw;
223 /* Calculate total size of kernel and modules */
225 getElfSize(&_binary_kernel_bin_start, &size_rw, &size_ro);
227 total_size_ro = size_ro = (size_ro + 4095) & ~4095;
228 total_size_rw = size_rw = (size_rw + 4095) & ~4095;
230 if (pkg_image && pkg_size) {
231 uint8_t *base = pkg_image;
233 if (base[0] == 0x7f && base[1] == 'E' && base[2] == 'L' && base[3] == 'F') {
234 kprintf("[BOOT] Kernel image is ELF file\n");
236 getElfSize(base, &size_rw, &size_ro);
238 total_size_ro += (size_ro + 4095) & ~4095;
239 total_size_rw += (size_rw + 4095) & ~4095;
240 } else if (base[0] == 'P' && base[1] == 'K' && base[2] == 'G' && base[3] == 0x01) {
241 kprintf("[BOOT] Kernel image is a package:\n");
243 uint8_t *file = base+4;
244 uint32_t total_length = AROS_BE2LONG(*(uint32_t*)file); /* Total length of the module */
245 const uint8_t *file_end = base+total_length;
246 uint32_t len;
248 kprintf("[BOOT] Package size: %dKB\n", total_length >> 10);
250 file = base + 8;
252 while(file < file_end) {
253 const char *filename = remove_path(file+4);
255 /* get text length */
256 len = AROS_BE2LONG(*(uint32_t*)file);
257 /* display the file name */
258 kprintf("[BOOT] %s \n", filename);
260 file += len + 5;
262 len = AROS_BE2LONG(*(uint32_t *)file);
263 file += 4;
265 /* load it */
266 getElfSize(file, &size_rw, &size_ro);
268 total_size_ro += (size_ro + 4095) & ~4095;
269 total_size_rw += (size_rw + 4095) & ~4095;
271 /* go to the next file */
272 file += len;
278 On asm bootstrap we aligned top of memory to 1Mb and set the stack pointer there and "pushed" ATAGS in stack
279 We then substracted vector space and mmu1
281 ffff ffff (Serial debug port base,) ATAGS and stack
283 ffff 003c routine address FIQ
284 ffff 0038 routine address IRQ
285 ffff 0034 routine address Reserved
286 ffff 0030 routine address Data Abort
287 ffff 002c routine address Prefetch Abort
288 ffff 0028 routine address Software interrupt
289 ffff 0024 routine address Undefined instruction
290 ffff 0020 routine address Reset
291 ffff 001c FIQ
292 ffff 0018 IRQ
293 ffff 0014 Reserved
294 ffff 0010 Data Abort
295 ffff 000c Prefetch Abort
296 ffff 0008 Software interrupt
297 ffff 0004 Undefined instruction
298 ffff 0000 Reset
299 fffe c000 MMU1
300 fffa ffff End of kernel
302 xxx0 0000 RAM
306 kernel_phys = mem_upper - total_size_ro - total_size_rw;
307 kernel_virt = (kernel_phys | 0xfff00000);
309 /* Adjust top of memory to last mebibyte (or megabyte...)*/
310 mem_upper = AROS_ROUNDDOWN2(kernel_phys, 1024*1024-1);
312 tag->ti_Tag = KRN_MEMLower;
313 tag->ti_Data = mem_lower;
314 tag++;
316 tag->ti_Tag = KRN_MEMUpper;
317 tag->ti_Data = mem_upper;
318 tag++;
320 tag->ti_Tag = KRN_KernelLowest;
321 tag->ti_Data = kernel_virt;
322 tag++;
324 tag->ti_Tag = KRN_KernelHighest;
325 tag->ti_Data = kernel_virt + ((total_size_ro + 4095) & ~4095) + ((total_size_rw + 4095) & ~4095); // 0xfffe c000
326 tag++;
328 kprintf("[BOOT] Physical address of kernel: %p\n", kernel_phys);
329 kprintf("[BOOT] Virtual address of kernel: %p\n", kernel_virt);
331 entry = (void (*)(struct TagItem *))kernel_virt;
333 initAllocator(kernel_phys, kernel_phys + total_size_ro, kernel_virt - kernel_phys);
335 loadElf(&_binary_kernel_bin_start);
337 if (pkg_image && pkg_size) {
338 uint8_t *base = pkg_image;
340 if (base[0] == 0x7f && base[1] == 'E' && base[2] == 'L' && base[3] == 'F') {
341 kprintf("[BOOT] Kernel image is ELF file\n");
343 /* load it */
344 loadElf(base);
345 } else if (base[0] == 'P' && base[1] == 'K' && base[2] == 'G' && base[3] == 0x01) {
346 kprintf("[BOOT] Kernel image is a package:\n");
348 uint8_t *file = base+4;
349 uint32_t total_length = AROS_BE2LONG(*(uint32_t*)file); /* Total length of the module */
350 const uint8_t *file_end = base+total_length;
351 uint32_t len;
353 kprintf("[BOOT] Package size: %dKB\n", total_length >> 10);
355 file = base + 8;
357 while(file < file_end) {
358 const char *filename = remove_path(file+4);
360 /* get text length */
361 len = AROS_BE2LONG(*(uint32_t*)file);
362 /* display the file name */
363 kprintf("[BOOT] %s ", filename);
365 file += len + 5;
367 len = AROS_BE2LONG(*(uint32_t *)file);
368 file += 4;
370 /* load it */
371 loadElf(file);
373 /* go to the next file */
374 file += len;
379 arm_flush_cache(kernel_phys, total_size_ro + total_size_rw);
381 tag->ti_Tag = KRN_KernelBss;
382 tag->ti_Data = (IPTR)tracker;
383 tag++;
385 setup_mmu(kernel_phys, kernel_virt, mem_lower, mem_upper);
388 tag->ti_Tag = TAG_DONE;
389 tag->ti_Data = 0;
391 kprintf("[BOOT] Kernel taglist contains %d entries\n", ((intptr_t)tag - (intptr_t)tags)/sizeof(struct TagItem));
392 kprintf("[BOOT] mem_upper: %p\n", mem_upper);
394 if (entry) {
395 /* Set domains - Dom0 is usable, rest is disabled */
396 asm volatile ("mrc p15, 0, %0, c3, c0, 0":"=r"(tmp));
397 kprintf("[BOOT] Domain access control register: %08x\n", tmp);
398 asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(0x00000001));
400 /* Enable MMU */
401 CP15_C1CR_Set(C1CRF_M);
403 kprintf("[BOOT] Heading over to AROS kernel @ %08x\n", entry);
405 entry(tags);
407 kprintf("[BOOT] Back? Something wrong happened...\n");
408 } else {
409 kprintf("[BOOT] kernel entry pointer not set?\n");
412 while(1);