Recent versions of the Linux kernel provide an EFI boot stub of their own, for interrogating the runtime services and building up the bootparams. Where possible, we should use this instead of doing it for ourself. (Theoretically, at least.)
Tested in 32-bit and 64-bit mode, with a corresponding kernel. The whole thing is somewhat shafted for 32-bit EFI booting a 64-bit kernel, and vice versa — the EFI stub only works in one of the other, so the bootloader would have to look at the PE header to work out whether it's a 32-bit or 64-bit executable. It's necessary to check for the existence of the PE header *anyway*, since current kernels will point the handover_offset field in the bootparams to the location at which the boot stub *would* have been, even when it isn't actually compiled in! However, we probably don't want to use the EFI handover protocol for current kernels anyway. There's no benefit in the qemu context (it's only really for device ROMs which are only accessible via EFI, such as on Apple laptops). And the kernel's boot stub was broken for the case of a single GOP device which implements the ConOut protocol — it wouldn't detect the framebuffer. Oh, and the 32-bit entry is completely broken. It messes up the stack on the way in so gets all its arguments off-by-one, and if you fix that, it would corrupt memory by passing wild pointers to runtime calls due to further unrelated confusion about function arguments. I'm working on a patch series for the kernel¹ which will fix this all a little more sanely, adding bit flags for a 32-bit and 64-bit-capable EFI handover entry point. Once that's merged upstream, the final version of this patch can make OVMF use the EFI handover *only* for new kernels with one of those bits set. But any feedback would be appreciated in the meantime. Note that OVMF is already broken for the case of booting a 32-bit kernel from 64-bit firmware, even for the legacy handover case which *ought* to work. We need to switch back into 32-bit mode before jumping to the 32-bit entry point. Rather than just jumping to the non-existent 64-bit entry point in a 32-bit kernel. I haven't addressed that here. diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.S b/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.S index b8cd4ca..0064dff 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.S +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.S @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ ASM_GLOBAL ASM_PFX(JumpToKernel) +ASM_GLOBAL ASM_PFX(JumpToKernelEFI) #------------------------------------------------------------------------------ # VOID @@ -27,3 +28,19 @@ ASM_PFX(JumpToKernel): calll 0x4(%esp) ret +#------------------------------------------------------------------------------ +# VOID +# EFIAPI +# JumpToKernelEFI ( +# EFI_HANDLE ImageHandle, +# EFI_SYSTEM_TABLE *SystemTable, +# VOID *KernelBootParams, +# VOID *KernelStart +# ); +#------------------------------------------------------------------------------ +ASM_PFX(JumpToKernelEFI): + movl 0xc(%esp), %eax + movl 0x264(%eax), %eax + addl 0x10(%esp), %eax + jmp %eax + diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.asm b/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.asm index a8f3965..dc61dd1 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.asm +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.asm @@ -32,4 +32,23 @@ JumpToKernel PROC JumpToKernel ENDP +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; JumpToKernelEFI ( +; EFI_HANDLE ImageHandle, +; EFI_SYSTEM_TABLE *SystemTable, +; VOID *KernelBootParams, +; VOID *KernelStart +; ); +;------------------------------------------------------------------------------ +JumpToKernelEFI PROC + + mov eax, [esp + 12] + mov eax, [eax + 264h] + add eax, [esp + 16] + jmp eax + +JumpToKernelEFI ENDP + END diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/Linux.c b/edk2/OvmfPkg/Library/LoadLinuxLib/Linux.c index 96c985b..674dc52 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/Linux.c +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/Linux.c @@ -575,14 +575,11 @@ SetupGraphics ( STATIC EFI_STATUS SetupLinuxBootParams ( - IN VOID *Kernel, IN OUT struct boot_params *Bp ) { SetupGraphics (Bp); - Bp->hdr.code32_start = (UINT32)(UINTN) Kernel; - SetupLinuxMemmap (Bp); return EFI_SUCCESS; @@ -615,7 +612,18 @@ LoadLinux ( InitLinuxDescriptorTables (); - SetupLinuxBootParams (Kernel, (struct boot_params*) KernelSetup); + Bp->hdr.code32_start = (UINT32)(UINTN) Kernel; + + if (Bp->hdr.version >= 0x20b && Bp->hdr.handover_offset) { + DEBUG ((EFI_D_INFO, "Jumping to kernel EFI handover point at ofs %x\n", Bp->hdr.handover_offset)); + + DisableInterrupts (); + JumpToKernelEFI ((VOID*) gImageHandle, (VOID*) gST, KernelSetup, Kernel); + } + // + // Old kernels without EFI handover protocol + // + SetupLinuxBootParams ((struct boot_params*) KernelSetup); DEBUG ((EFI_D_INFO, "Jumping to kernel\n")); DisableInterrupts (); diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.h b/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.h index f869797..3cc4da5 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.h +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.h @@ -37,6 +37,15 @@ JumpToKernel ( ); VOID +EFIAPI +JumpToKernelEFI ( + EFI_HANDLE ImageHandle, + EFI_SYSTEM_TABLE *SystemTable, + VOID *KernelBootParams, + VOID *KernelStart + ); + +VOID InitLinuxDescriptorTables ( VOID ); diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.S b/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.S index 9ae755b..2ac5885 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.S +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.S @@ -13,6 +13,7 @@ #------------------------------------------------------------------------------ ASM_GLOBAL ASM_PFX(JumpToKernel) +ASM_GLOBAL ASM_PFX(JumpToKernelEFI) #------------------------------------------------------------------------------ # VOID @@ -28,3 +29,23 @@ ASM_PFX(JumpToKernel): callq %rcx ret +#------------------------------------------------------------------------------ +# VOID +# EFIAPI +# JumpToKernelEFI ( +# EFI_HANDLE ImageHandle, // %rcx +# EFI_SYSTEM_TABLE *SystemTable, // %rdx +# VOID *KernelBootParams, // %r8 +# VOID *KernelStart // %r9 +# ); +#------------------------------------------------------------------------------ +ASM_PFX(JumpToKernelEFI): + movq %rcx, %rdi + movq %rdx, %rsi + movq %r8, %rdx + xor %rax, %rax + movl 0x264(%r8), %eax + addq %rax, %r9 + addq $0x200, %r9 + callq %r9 + ret diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.asm b/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.asm index ed53321..ac30d87 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.asm +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.asm @@ -31,4 +31,27 @@ JumpToKernel PROC JumpToKernel ENDP +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; JumpToKernelEFI ( +; EFI_HANDLE ImageHandle, // rcx +; EFI_SYSTEM_TABLE *SystemTable, // rdx +; VOID *KernelBootParams // r8 +; VOID *KernelStart, // r9 +; ); +;------------------------------------------------------------------------------ +JumpToKerneEFI PROC + mov rdi, rcx + mov rsi, rdx + mov rdx, r8 + xor rax, rax + mov eax, [r8 + 264h] + add r9, rax + add r9, 200h + call r9 + ret + +JumpToKernelEFI ENDP + END -- dwmw2 ¹ http://git.infradead.org/users/dwmw2/efi.git/
smime.p7s
Description: S/MIME cryptographic signature
------------------------------------------------------------------------------ Master SQL Server Development, Administration, T-SQL, SSAS, SSIS, SSRS and more. Get SQL Server skills now (including 2012) with LearnDevNow - 200+ hours of step-by-step video tutorials by Microsoft MVPs and experts. SALE $99.99 this month only - learn more at: http://p.sf.net/sfu/learnmore_122512
_______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel