aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <kwojtus@protonmail.com>2019-12-28 18:09:09 +0100
committerWojtek Kosior <kwojtus@protonmail.com>2019-12-28 18:09:09 +0100
commitf7ddd1a356f58298d703b11e862d3d6127e67080 (patch)
tree92f681646a569dfbcdc8a4df277ee48da4e46868
parent6321cd922cb665ca5bfb9bc2025701b07c076894 (diff)
downloadrpi-MMU-example-f7ddd1a356f58298d703b11e862d3d6127e67080.tar.gz
rpi-MMU-example-f7ddd1a356f58298d703b11e862d3d6127e67080.zip
rewrite the stage 1 of bootloader in a more compact and (mostly) load-addr-independent way
-rw-r--r--Makefile12
-rw-r--r--loader_linker.ld72
-rw-r--r--loader_stage1.S55
-rw-r--r--loader_stage1.c26
-rw-r--r--loader_stage1_linker.ld16
-rw-r--r--loader_stage2.c3
-rw-r--r--loader_stage2_linker.ld16
7 files changed, 97 insertions, 103 deletions
diff --git a/Makefile b/Makefile
index 92d200f..29efa86 100644
--- a/Makefile
+++ b/Makefile
@@ -25,8 +25,14 @@ PL_0_test.elf : PL0_test.o uart.o
kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o
arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^
-loader.elf : boot.o loader_stage1.o loader_stage2.o uart.o
- arm-none-eabi-gcc -T loader_linker.ld -o $@ $(ELFFLAGS) $^
+loader_stage2.elf : loader_stage2.o uart.o
+ arm-none-eabi-gcc -T loader_stage2_linker.ld -o $@ $(ELFFLAGS) $^
+
+loader_stage1.o : loader_stage1.S loader_stage2.img
+ arm-none-eabi-as -mcpu=cortex-a7 $< -o $@
+
+loader.elf : loader_stage1.o
+ arm-none-eabi-gcc -T loader_stage1_linker.ld -o $@ $(ELFFLAGS) $^
loader.img : loader.elf
arm-none-eabi-objcopy $^ -O binary $@
@@ -36,7 +42,7 @@ loader.img : loader.elf
qemu-elf : kernel.elf
qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $^
-qemu-bin : loader.elf kernel.img pipe_image
+qemu-bin : loader.img kernel.img pipe_image
./pipe_image --stdout | qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $<
run-on-rpi : kernel.img pipe_image
diff --git a/loader_linker.ld b/loader_linker.ld
deleted file mode 100644
index 45c88ff..0000000
--- a/loader_linker.ld
+++ /dev/null
@@ -1,72 +0,0 @@
-ENTRY(_boot)
-
-SECTIONS
-{
- /* Starts at LOADER_ADDR. */
- /* Warning! Internet says RPis in 32-bit mode load binary at 0x8000! */
- /* My experiments do, however, show, that qemu emulating RPi2 */
- /* loads it at 0x10000! (took some pain to find out) */
-
- /* . = 0x10000; */
-
- /* rpi-open-firmware, on the other hand, loads it at 0x2000000 */
- /* (and this should be not-so-hard to change by modifying the */
- /* firmware) */
-
- . = 0x2000000;
-
- /* For AArch64, use . = 0x80000; Unless this too is wrong */
-
- __start = .;
- __text_stage1_start = .;
- .text_stage1 :
- {
- KEEP(*(.text.boot))
- *(.text.boot)
- *(.text.stage1main)
- }
- . = ALIGN(4096); /* align to page size */
- __text_stage1_end = .;
-
- __stage2_start = .;
- __text_start = .;
- .text :
- {
- KEEP(*(.text.stage2main))
- *(.text.boot)
- }
- . = ALIGN(4096); /* align to page size */
- __text_end = .;
-
- __rodata_start = .;
- .rodata :
- {
- *(.rodata)
- }
- . = ALIGN(4096); /* align to page size */
- __rodata_end = .;
-
- __data_start = .;
- .data :
- {
- *(.data)
- }
- . = ALIGN(4096); /* align to page size */
- __data_end = .;
-
- __bss_start = .;
- .bss :
- {
- bss = .;
- *(.bss)
- }
- . = ALIGN(4096); /* align to page size */
- __bss_end = .;
- __bss_size = __bss_end - __bss_start;
-
- __stage2_end = .;
- __stage2_size = __stage2_end - __stage2_start;
- __end = .;
-
- _stack_top = 0x4000;
-}
diff --git a/loader_stage1.S b/loader_stage1.S
new file mode 100644
index 0000000..adf2e12
--- /dev/null
+++ b/loader_stage1.S
@@ -0,0 +1,55 @@
+// armv7 mode
+
+// Entry point for the kernel.
+// r15 -> should begin execution at 0x8000.
+// r0 -> 0x00000000
+// r1 -> 0x00000C42
+// r2 -> 0x00000100 - start of ATAGS
+// preserve these registers as argument for kernel
+
+.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/loader_stage1.c b/loader_stage1.c
deleted file mode 100644
index aca439c..0000000
--- a/loader_stage1.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <stddef.h>
-#include <stdint.h>
-#include <global.h>
-
-#define STAGE2_ADDR ((volatile char*) 0x4000)
-
-// There's one tricky thing about managing executable's own code.
-// Mainly, symbols are visible to c code as extern chars, but the actual
-// values are their adresses... see the code below
-extern char
- __stage2_start,
- __stage2_end,
- __stage2_size;
-
-__attribute__((section(".text.stage1main")))
-void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags)
-{
- // stage2 of the bootloader is part of executable;
- // copy it over to it's destination place
- // TODO implement a memcpy() somewhere and use it instead of loops
- for (size_t i = 0; i < (size_t) &__stage2_size; i++)
- STAGE2_ADDR[i] = (&__stage2_start)[i];
-
- // jump to stage2
- ((void(*)(uint32_t, uint32_t, uint32_t))STAGE2_ADDR)(r0, r1, atags);
-}
diff --git a/loader_stage1_linker.ld b/loader_stage1_linker.ld
new file mode 100644
index 0000000..711fcbf
--- /dev/null
+++ b/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/loader_stage2.c b/loader_stage2.c
index 7b5087a..65dda0a 100644
--- a/loader_stage2.c
+++ b/loader_stage2.c
@@ -5,8 +5,7 @@
void *const kernel_load_addr = ((void*) 0x8000);
-void __attribute__((section(".text.stage2main")))
-stage2(uint32_t r0, uint32_t r1, uint32_t atags)
+void _stage2_main(uint32_t r0, uint32_t r1, uint32_t atags)
{
// Declare as unused
(void) r0;
diff --git a/loader_stage2_linker.ld b/loader_stage2_linker.ld
new file mode 100644
index 0000000..33e79e9
--- /dev/null
+++ b/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 = .;
+}