summaryrefslogtreecommitdiffstats
path: root/grub-core/kern/arm/startup.S
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/kern/arm/startup.S')
-rw-r--r--grub-core/kern/arm/startup.S177
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: