/* * 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 .org _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE VARIABLE(grub_total_module_size) .long 0 VARIABLE(grub_uboot_machine_type) .long 0 VARIABLE(grub_uboot_boot_data) .long 0 VARIABLE(grub_modbase) .long 0 bss_start_ptr: .long EXT_C(__bss_start) end_ptr: .long EXT_C(_end) 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 {r4-r12,lr} @ store U-Boot context (sp in r12) str r1, EXT_C(grub_uboot_machine_type) str r2, EXT_C(grub_uboot_boot_data) @ Modules have been stored as a blob in BSS, @ they need to be manually relocated to _end ldr r0, bss_start_ptr @ src add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) mvn r1, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) and r0, r0, r1 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) 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) /* * 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 str sp, transition_space + 12 sub sp, sp, #0x20 lsr sp, sp, #3 lsl sp, sp, #3 ldr r8, gd_backup ldr r9, gd_backup + 4 mov lr, pc ldr pc, grub_uboot_syscall_ptr str r8, gd_backup ldr r8, transition_space ldr lr, transition_space + 4 ldr r9, transition_space + 8 ldr sp, transition_space + 12 bx lr FUNCTION(grub_uboot_return) adr sp, entry_state_end pop {r4-r12, lr} mov sp, r12 bx lr .align 3 @ 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 .long 0 @ r9 .long 0 @ sp VARIABLE(grub_uboot_syscall_ptr) .long 0 @ END