]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
decouple
authorVladimir Serbinenko <phcoder@gmail.com>
Fri, 19 Feb 2016 03:31:59 +0000 (04:31 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Fri, 19 Feb 2016 03:31:59 +0000 (04:31 +0100)
grub-core/kern/arm/startup.S [new file with mode: 0644]
grub-core/kern/arm/uboot/init.c [new file with mode: 0644]
grub-core/kern/arm/uboot/uboot.S [new file with mode: 0644]
include/grub/arm/startup.h [new file with mode: 0644]

diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S
new file mode 100644 (file)
index 0000000..8e233d4
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  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
+
+       @ Do not put modules before the end of relocations.
+       @ Instead increase stack size
+       @ r1 = max (r1, r0)
+        cmp     r0, r1
+        movcs   r1, r0
+       
+       sub     sp, r1, #8
+       add     r1, r1, #1024
+
+       str     r1, EXT_C(grub_modbase)
+
+       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
+
+       @ 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:
diff --git a/grub-core/kern/arm/uboot/init.c b/grub-core/kern/arm/uboot/init.c
new file mode 100644 (file)
index 0000000..2a6aa3f
--- /dev/null
@@ -0,0 +1,70 @@
+/* init.c - generic U-Boot initialization and finalization */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2016  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/uboot/uboot.h>
+#include <grub/arm/startup.h>
+#include <grub/uboot/api_public.h>
+
+extern int (*grub_uboot_syscall_ptr) (int, int *, ...);
+
+grub_uint32_t
+grub_uboot_get_machine_type (void)
+{
+  return grub_arm_saved_registers.r[1];
+}
+
+grub_addr_t
+grub_uboot_get_boot_data (void)
+{
+  return grub_arm_saved_registers.r[2];
+}
+
+int
+grub_uboot_api_init (void)
+{
+  struct api_signature *start, *end;
+  struct api_signature *p;
+  grub_addr_t grub_uboot_search_hint = grub_arm_saved_registers.sp;
+  if (grub_uboot_search_hint)
+    {
+      /* Extended search range to work around Trim Slice U-Boot issue */
+      start = (struct api_signature *) ((grub_uboot_search_hint & ~0x000fffff)
+                                       - 0x00500000);
+      end =
+       (struct api_signature *) ((grub_addr_t) start + UBOOT_API_SEARCH_LEN -
+                                 API_SIG_MAGLEN + 0x00500000);
+    }
+  else
+    {
+      start = 0;
+      end = (struct api_signature *) (256 * 1024 * 1024);
+    }
+
+  /* Structure alignment is (at least) 8 bytes */
+  for (p = start; p < end; p = (void *) ((grub_addr_t) p + 8))
+    {
+      if (grub_memcmp (&(p->magic), API_SIG_MAGIC, API_SIG_MAGLEN) == 0)
+       {
+         grub_uboot_syscall_ptr = p->syscall;
+         return p->version;
+       }
+    }
+
+  return 0;
+}
diff --git a/grub-core/kern/arm/uboot/uboot.S b/grub-core/kern/arm/uboot/uboot.S
new file mode 100644 (file)
index 0000000..d128775
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  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>
+
+       /*
+        * uboot_syscall():
+        *   This function is effectively a veneer, so it cannot
+        *   modify the stack or corrupt any registers other than
+        *   r12 (ip). Furthermore it needs to restore r8 for
+        *   U-Boot (Global Data Pointer) and preserve it for Grub.
+        */
+FUNCTION(grub_uboot_syscall)
+       str     r8, transition_space
+       str     lr, transition_space + 4
+       str     r9, transition_space + 8
+
+       ldr     ip, saved_registers_ptr
+       ldr     r8, [ip, #4 * 8]
+       ldr     r9, [ip, #4 * 9]
+
+       bl      do_syscall
+
+       ldr     r8, transition_space
+       ldr     lr, transition_space + 4
+       ldr     r9, transition_space + 8
+
+       bx      lr
+do_syscall:
+
+       ldr     ip, grub_uboot_syscall_ptr
+       bx      ip
+       
+FUNCTION(grub_uboot_return)
+       ldr     ip, saved_registers_ptr
+       ldr     sp, [ip, #4 * 4]
+       pop     {r4-r12, lr}
+       mov     sp, r12
+       bx      lr
+
+       
+       .align  3
+
+@ GRUB context stack space
+transition_space:      
+       .long   0       @ r8
+       .long   0       @ lr
+       .long   0       @ r9
+
+saved_registers_ptr:
+       .long EXT_C(grub_arm_saved_registers)
+
+VARIABLE(grub_uboot_syscall_ptr)
+       .long   0       @
+
+       END
diff --git a/include/grub/arm/startup.h b/include/grub/arm/startup.h
new file mode 100644 (file)
index 0000000..9afb6c5
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef GRUB_STARTUP_CPU_HEADER
+#define GRUB_STARTUP_CPU_HEADER
+
+struct grub_arm_startup_registers
+{
+  /* registers 0-11 */
+  /* for U-boot r[1] is machine type */
+  /* for U-boot r[2] is boot data */
+  grub_uint32_t r[12];
+  grub_uint32_t sp;
+  grub_uint32_t lr;
+};
+
+extern struct grub_arm_startup_registers grub_arm_saved_registers;
+
+#endif