From 2d91eebbf1fc9335269207602b360ec485aaf7bb Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 17 Dec 2019 17:39:03 +0100 Subject: don't embed stage2 of bootloader as binary blob - use smart section naming --- loader_stage1.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'loader_stage1.c') diff --git a/loader_stage1.c b/loader_stage1.c index d209c15..aca439c 100644 --- a/loader_stage1.c +++ b/loader_stage1.c @@ -2,24 +2,25 @@ #include #include -char *const stage2_addr = ((void*) 0x4000); +#define STAGE2_ADDR ((volatile char*) 0x4000) -// there's one tricky thing about embedding file in executable; -// mainly, symbols are visible to c code as extern chars, but the actual +// 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 - _binary_loader_stage2_img_start, - _binary_loader_stage2_img_end, - _binary_loader_stage2_img_size; + __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 a blob embedded in executable; + // 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) &_binary_loader_stage2_img_size; i++) - stage2_addr[i] = (&_binary_loader_stage2_img_start)[i]; + 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); + ((void(*)(uint32_t, uint32_t, uint32_t))STAGE2_ADDR)(r0, r1, atags); } -- cgit v1.2.3 From f7ddd1a356f58298d703b11e862d3d6127e67080 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 18:09:09 +0100 Subject: rewrite the stage 1 of bootloader in a more compact and (mostly) load-addr-independent way --- Makefile | 12 ++++++--- loader_linker.ld | 72 ------------------------------------------------- loader_stage1.S | 55 +++++++++++++++++++++++++++++++++++++ loader_stage1.c | 26 ------------------ loader_stage1_linker.ld | 16 +++++++++++ loader_stage2.c | 3 +-- loader_stage2_linker.ld | 16 +++++++++++ 7 files changed, 97 insertions(+), 103 deletions(-) delete mode 100644 loader_linker.ld create mode 100644 loader_stage1.S delete mode 100644 loader_stage1.c create mode 100644 loader_stage1_linker.ld create mode 100644 loader_stage2_linker.ld (limited to 'loader_stage1.c') 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 -#include -#include - -#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 = .; +} -- cgit v1.2.3