/* * 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 . */ #include #include #include /* * GRUB is called from U-Boot as a Linux Kernel type image, which * means among other things that it always enters in ARM state. * * * 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). * : * Any part of the module blob that extends beyond _end. * : * Loadable modules, post relocation. * : * : */ .text .arm FUNCTION(_start) b codestart @ Size of final image integrated module blob - set by grub-mkimage . = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE VARIABLE(grub_total_module_size) .long 0 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 ldr sp, =entry_state push {r4-r12,lr} @ store U-Boot context (sp in r12) @ Put kernel parameters aside until we can store them (further down) mov r4, r1 @ machine type mov r5, r2 @ boot data @ Modules have been stored as a blob in BSS, @ they need to be manually relocated to _end or @ (__bss_start + grub_total_module_size), whichever greater. bl uboot_get_real_bss_start @ r0 = src ldr r1, =EXT_C(_end) @ dst = End of BSS ldr r2, grub_total_module_size @ blob size add r3, r0, r2 @ blob end cmp r1, r3 @ _end < blob end? movlt r1, r3 @ dst = blob end + blob size 1: ldr r3, [r0], #4 @ r3 = *src++ str r3, [r1], #4 @ *dst++ = r3 subs r2, #4 @ remaining -= 4 bne 1b @ while remaining != 0 @ Set up a new stack, beyond the end of copied modules. ldr r3, =GRUB_KERNEL_MACHINE_STACK_SIZE add r3, r1, r3 @ Place stack beyond end of modules and sp, r3, #~0x7 @ Ensure 8-byte alignment @ Since we _are_ the C run-time, we need to manually zero the BSS @ region before continuing bl uboot_get_real_bss_start @ zero from here ldr r1, =EXT_C(_end) @ to here mov r2, #0 1: str r2, [r0], #4 cmp r0, r1 bne 1b @ Global variables now accessible - store kernel parameters in memory ldr r12, =EXT_C(uboot_machine_type) str r4, [r12] ldr r12, =EXT_C(uboot_boot_data) str r5, [r12] b EXT_C(grub_main) /* * __bss_start does not actually point to the start of the runtime * BSS, but rather to the next byte following the preceding data. */ FUNCTION (uboot_get_real_bss_start) ldr r0, =EXT_C(__bss_start) @ src tst r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) beq 1f mvn r1, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) and r0, r0, r1 add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN) 1: bx lr /* * 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(uboot_syscall) ldr ip, =transition_space stm ip, {r8, lr} ldr ip, =gd_backup ldr r8, [ip] ldr ip, =uboot_syscall_ptr mov lr, pc ldr pc, [ip] ldr ip, =gd_backup str r8, [ip] ldr ip, =transition_space ldm ip, {r8, lr} bx lr FUNCTION(uboot_return) ldr sp, =entry_state_end pop {r4-r12, lr} mov sp, r12 bx lr .data .align 3 @ 8-byte alignment for stack @ U-boot context stack space entry_state_end: .long 0 @ r4 .long 0 @ r5 .long 0 @ r6 .long 0 @ r7 gd_backup: .long 0 @ r8 - U-Boot global data pointer .long 0 @ r9 .long 0 @ r10 .long 0 @ r11 VARIABLE(uboot_search_hint)@ U-Boot stack pointer - .long 0 @ also API signature address hint. .long 0 @ lr entry_state: @ backup for U-Boot context @ GRUB context stack space transition_space: .long 0 @ r8 .long 0 @ lr VARIABLE(uboot_syscall_ptr) .long 0 @ .end