/* * 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). * : * : * 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) ldr r12, =EXT_C(grub_uboot_machine_type) str r1, [r12] ldr r12, =EXT_C(grub_uboot_boot_data) str r2, [r12] @ Modules have been stored as a blob in BSS, @ they need to be manually relocated to _end ldr r0, =EXT_C(__bss_start) @ src add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) mvn r1, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) and r0, r0, r1 ldr r1, =EXT_C(_end) @ 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 ldr r12, =EXT_C(grub_modbase) str r1, [r12] 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, =EXT_C(__bss_start) @ 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, =EXT_C(_end) @ to here 1: str r2, [r0], #4 cmp r0, r1 bne 1b b EXT_C(grub_main) /* * 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) ldr ip, =transition_space stm ip, {r8, lr} ldr ip, =gd_backup ldr r8, [ip] ldr ip, =grub_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(grub_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(grub_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(grub_uboot_syscall_ptr) .long 0 @ .end