diff options
Diffstat (limited to 'src/arm/PL1/loader')
-rw-r--r-- | src/arm/PL1/loader/loader_stage1.S | 55 | ||||
-rw-r--r-- | src/arm/PL1/loader/loader_stage1_linker.ld | 16 | ||||
-rw-r--r-- | src/arm/PL1/loader/loader_stage2.c | 33 | ||||
-rw-r--r-- | src/arm/PL1/loader/loader_stage2_linker.ld | 16 |
4 files changed, 120 insertions, 0 deletions
diff --git a/src/arm/PL1/loader/loader_stage1.S b/src/arm/PL1/loader/loader_stage1.S new file mode 100644 index 0000000..69d78c5 --- /dev/null +++ b/src/arm/PL1/loader/loader_stage1.S @@ -0,0 +1,55 @@ +/* arm mode, cortex-a7 compatibility + * + * _boot is entry point for the loader. + * + * Loader copies it's embedded stage 2 to address 0x4000 + * and jumps to it. Registers r0 - r2 are arguments for the kernel + * and should be left intact. + */ + +.global _boot +_boot: + // Only let the first core execute + mrc p15, 0, r3, c0, c0, 5 + and r3, r3, #3 + cmp r3, #0 + beq proceed + // this is a kind of blef - races can theoretically still occur + // when the main core overwrites this part of memory + wfe + +proceed: + // copy stage2 of the loader to address 0x4000 + + // first, load address of stage2_start to r3 (a PIC way) + adr r3, stage2_start + + // load destination address for stage2 code to r4 + mov r4, #0x4000 + + // load blob size to r5 + mov r5, #(stage2_end - stage2_start) + + // r6 is the counter - counts the bytes copied + mov r6, #0 + + // each word of the blob is loaded to r7 and stored + // from r7 to it's destination in a loop +loop: + ldr r7, [r3, r6] + str r7, [r4, r6] + add r6, r6, #4 + cmp r6, r5 + blo loop + + // Initialize the stack + // _stack_top is defined in loader_stage1_linker.ld + ldr sp, =_stack_top + + // Call stage2 of the loader (branch to 0x4000) + bx r4 + +.align 4 +stage2_start: + .incbin "loader_stage2.img" +stage2_end: diff --git a/src/arm/PL1/loader/loader_stage1_linker.ld b/src/arm/PL1/loader/loader_stage1_linker.ld new file mode 100644 index 0000000..711fcbf --- /dev/null +++ b/src/arm/PL1/loader/loader_stage1_linker.ld @@ -0,0 +1,16 @@ +ENTRY(_boot) + +SECTIONS +{ + /* see linker.ld for details */ + . = 0x2000000; + + __start = .; + loader_stage1 : + { + KEEP(loader_stage1.o) + } + __end = .; + + _stack_top = 0x8000; +} diff --git a/src/arm/PL1/loader/loader_stage2.c b/src/arm/PL1/loader/loader_stage2.c new file mode 100644 index 0000000..fc3ae1c --- /dev/null +++ b/src/arm/PL1/loader/loader_stage2.c @@ -0,0 +1,33 @@ +#include <stddef.h> +#include <stdint.h> +#include "uart.h" +#include "io.h" +#include "global.h" + +void *const kernel_load_addr = ((void*) 0x8000); + +void _stage2_main(uint32_t r0, uint32_t r1, uint32_t atags) +{ + uart_init(); + + // get kernel size via uart (little endian) + uint32_t b0, b1, b2, b3; + + b0 = getchar(); + b1 = getchar(); + b2 = getchar(); + b3 = getchar(); + + uint32_t kernel_size = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); + + // load kernel at kernel_load_addr + char *dst = kernel_load_addr, *end = dst + kernel_size; + + while (dst < end) + *(dst++) = getchar(); + + // jump to kernel + ((void(*)(uint32_t, uint32_t, uint32_t)) kernel_load_addr) + (r0, r1, atags); +} + diff --git a/src/arm/PL1/loader/loader_stage2_linker.ld b/src/arm/PL1/loader/loader_stage2_linker.ld new file mode 100644 index 0000000..33e79e9 --- /dev/null +++ b/src/arm/PL1/loader/loader_stage2_linker.ld @@ -0,0 +1,16 @@ +ENTRY(_stage2_main) + +SECTIONS +{ + /* see loader_stage1.S for details */ + . = 0x4000; + + __start = .; + loader_stage2 : + { + KEEP(loader_stage2.o(.text)) + loader_stage2.o + uart.o + } + __end = .; +} |