| /* |
| * 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: |