From: David Woodhouse <David.Woodhouse@xxxxxxxxx> As it is, the bootloader has no idea whether the kernel's EFI boot stub is 32-bit or 64-bit. If it gets it wrong, we'll get bizarre crashes; it won't even get the *entry* point right because of the weird implicit added 0x200 for the 64-bit entry points. This patch adds flags to indicate support for 32-bit vs. 64-bit mode. In future, it would be possible to support both in the same kernel. We can't make EFI runtime calls to 32-bit EFI from a 64-bit kernel, or vice versa, but with the old entry point it used to at least *boot*, and the EFI handover protocol ought to retain that functionality. As an added bonus, stop setting handover_offset when CONFIG_EFI_STUB isn't even set, and asking the bootloader to jump to where we *would* have placed the entry point. Signed-off-by: David Woodhouse <David.Woodhouse@xxxxxxxxx> --- Documentation/x86/boot.txt | 45 ++++++++++++++++++++++++++++++++++++++------- arch/x86/boot/header.S | 6 ++++-- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index 406d82d..0841b21 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -401,6 +401,14 @@ Protocol: 2.00+ - If 0, the protected-mode code is loaded at 0x10000. - If 1, the protected-mode code is loaded at 0x100000. + Bit 1 (read): EFI_STUB_32 + - If 0, the EFI handover protocol is not supported in 32-bit mode. + - If 1, the EFI handover protocol is supported in 32-bit mode. + + Bit 2 (read): EFI_STUB_64 + - If 0, the EFI handover protocol is not supported in 64-bit mode. + - If 1, the EFI handover protocol is supported in 64-bit mode. + Bit 5 (write): QUIET_FLAG - If 0, print early messages. - If 1, suppress early messages. @@ -702,12 +710,15 @@ Field name: handover_offset Type: read Offset/size: 0x264/4 - This field is the offset from the beginning of the kernel image to - the EFI handover protocol entry point. Boot loaders using the EFI - handover protocol to boot the kernel should jump to this offset. - - See EFI HANDOVER PROTOCOL below for more details. + This field indicates the location of the EFI handover protocol entry + point. See EFI HANDOVER PROTOCOL below for more details. + NOTE: For 32-bit support, this field contains the offset from the + beginning of the kernel image as one might expect. For 64-bit support, + for historical reasons 0x200 must be added to the value of this field. + For example, if the value of the handover_offset field is 0x30, the + 64-bit EFI entry point is actually 0x230 bytes into the kernel code. + Do not ask why. **** THE IMAGE CHECKSUM @@ -1034,8 +1045,23 @@ address of the struct boot_params; %ebp, %edi and %ebx must be zero. This protocol allows boot loaders to defer initialisation to the EFI boot stub. The boot loader is required to load the kernel/initrd(s) from the boot media and jump to the EFI handover protocol entry point -which is hdr->handover_offset bytes from the beginning of -startup_{32,64}. +which is indicated by the hdr->handover_offset field. + +The appropriate (32-bit or 64-bit) EFI boot stub must be called according +to the version of EFI running on the system. A kernel may support either, +both, or neither entry point. The bootloader should check the EFI_STUB_32 +or EFI_STUB_64 flag in the load_flags field as appropriate. If the entry +point appropriate for the system's implementation of EFI is not supported +by the kernel, then the bootloader should invoke the 'legacy' entry point +as normal. + +If invoking the 32-bit entry point, it is found at the offset indicated +by the handover_offset field of the setup header, and obviously must be +invoked with the CPU in 32-bit mode. + +If invoking the 64-bit entry point, it is found at an offset 0x200 greater +than the value of the handover_offset field, and the CPU must be in 64-bit +mode. The function prototype for the handover entry point looks like this, @@ -1055,3 +1081,8 @@ The boot loader *must* fill out the following fields in bp, o hdr.ramdisk_size (if applicable) All other fields should be zero. + +Note that the efi_main() entry point uses Linux/ELF calling conventions, +not EFI calling conventions. So for x86_64, 'handle' is in %rdi, 'table' +in %rsi and 'bp' in %rdx. For i386, the ABI is the same: the arguments +(and return address) are on the stack. diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 8c132a6..318264e 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -303,7 +303,8 @@ CAN_USE_HEAP = 0x80 # If set, the loader also has set # space behind setup.S can be used for # heap purposes. # Only the loader knows what is free - .byte LOADED_HIGH +EFIFLAGS = IS_ENABLED(CONFIG_EFI_STUB) << (1 + IS_ENABLED(CONFIG_X86_64)) + .byte LOADED_HIGH + EFIFLAGS setup_move_size: .word 0x8000 # size to move, when setup is not # loaded at 0x90000. We will move setup @@ -397,7 +398,8 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr #define INIT_SIZE VO_INIT_SIZE #endif init_size: .long INIT_SIZE # kernel initialization size -handover_offset: .long 0x30 # offset to the handover +handover_offset: .long 0x30 * IS_ENABLED(CONFIG_EFI_STUB) + # offset to the handover # protocol entry point # End of setup header ##################################################### -- 1.8.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html