diff options
Diffstat (limited to 'grub-core/kern/arm/startup.S')
-rw-r--r-- | grub-core/kern/arm/startup.S | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S new file mode 100644 index 0000000..3946fe8 --- /dev/null +++ b/grub-core/kern/arm/startup.S @@ -0,0 +1,177 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/offsets.h> +#include <grub/symbol.h> +#include <grub/machine/kernel.h> + +/* + * GRUB is called from U-Boot as a Linux Kernel type image, which + * means among other things that it always enters in ARM state. + * + * coreboot starts in ARM mode as well. + * + * Overview of GRUB image layout: + * + * _start: + * Entry point (1 ARM branch instruction, to "codestart") + * grub_total_module_size: + * Data field: Size of included module blob + * (when generated by grub-mkimage) + * codestart: + * Remainder of statically-linked executable code and data. + * __bss_start: + * Start of included module blob. + * Also where global/static variables are located. + * _end: + * End of bss region (but not necessarily module blob). + * <stack>: + * <modules>: + * Loadable modules, post relocation. + * <heap>: + */ + + .text + .arm +FUNCTION(_start) + b codestart + + @ Size of final image integrated module blob - set by grub-mkimage + .org _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE +VARIABLE(grub_total_module_size) + .long 0 + +VARIABLE(grub_modbase) + .long 0 +bss_start_ptr: + .long EXT_C(__bss_start) +end_ptr: + .long EXT_C(_end) + + @ Memory map at start: + @ * text+data + @ * list relocations + @ * modules + @ Before we enter C, we need to apply the relocations + @ and get following map: + @ * text+data + @ * BSS (cleared) + @ * stack + @ * modules + @ + @ To make things easier we ensure + @ that BSS+stack is larger than list of relocations + @ by increasing stack if necessarry. + @ This allows us to always unconditionally copy backwards + @ Currently list of relocations is ~5K and stack is set + @ to be at least 256K + +FUNCTION(codestart) + @ Store context: Machine ID, atags/dtb, ... + @ U-Boot API signature is stored on the U-Boot heap + @ Stack pointer used as start address for signature probing + mov r12, sp + adr sp, entry_state + push {r0-r12,lr} @ store U-Boot context (sp in r12) + + adr r1, _start + ldr r0, bss_start_ptr @ src + add r0, r0, r1 + + add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) + mvn r2, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) + and r0, r0, r2 +1: + ldr r3, [r0], #4 @load next offset + @ both -2 and -1 are treated the same as we have only one type of relocs + @ -2 means "end of this type of relocs" and -1 means "end of all relocs" + add r2, r3, #2 + cmp r2, #1 + bls reloc_done + @ Adjust next offset + ldr r2, [r3, r1] + add r2, r2, r1 + str r2, [r3, r1] + b 1b + +reloc_done: + + @ Modules have been stored as a blob + @ they need to be manually relocated to _end + add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) + mvn r1, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) + and r0, r0, r1 @ src = aligned end of relocations + + ldr r1, end_ptr @ dst = End of BSS + ldr r2, grub_total_module_size @ blob size + + add r1, r1, #GRUB_KERNEL_MACHINE_STACK_SIZE + and r1, r1, #~0x7 @ Ensure 8-byte alignment + + sub sp, r1, #8 + add r1, r1, #1024 + + str r1, EXT_C(grub_modbase) + + /* Coreboot already places modules at right place. */ +#ifndef GRUB_MACHINE_COREBOOT + add r1, r1, r2 + add r0, r0, r2 + sub r1, r1, #4 + sub r0, r0, #4 + +1: ldr r3, [r0], #-4 @ r3 = *src-- + str r3, [r1], #-4 @ *dst-- = r3 + subs r2, #4 @ remaining -= 4 + bne 1b @ while remaining != 0 +#endif + + @ Since we _are_ the C run-time, we need to manually zero the BSS + @ region before continuing + ldr r0, bss_start_ptr @ zero from here + @ If unaligned, bytewise zero until base address aligned. + mov r2, #0 +1: tst r0, #3 + beq 2f + strb r2, [r0], #1 + b 1b +2: ldr r1, end_ptr @ to here +1: str r2, [r0], #4 + cmp r0, r1 + bne 1b + + b EXT_C(grub_main) + + .align 3 +@ U-boot/coreboot context stack space +VARIABLE(grub_arm_saved_registers) + .long 0 @ r0 + .long 0 @ r1 + .long 0 @ r2 + .long 0 @ r3 + .long 0 @ r4 + .long 0 @ r5 + .long 0 @ r6 + .long 0 @ r7 + .long 0 @ r8 + .long 0 @ r9 + .long 0 @ r10 + .long 0 @ r11 + .long 0 @ sp + .long 0 @ lr +entry_state: |