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/

Attachment: 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

Reply via email to