We currently just jump to offset 0x200 in the kernel image, in 64-bit mode. This is completely broken. If it's a 32-bit kernel, we'll be jumping into the compressed data payload.
If it's a 64-bit kernel, it'll work... but the 0x200 offset is explicitly marked as 'may change in the future', has already changed from 0x100 to 0x200 in the past with no fanfare, and bootloaders are instructed that they should look at the ELF header to find the offset. So although it does actually work today, it's still broken in the "someone needs to whipped for doing it this way" sense of the word. In fact, the same bug exists in other bootloaders so the 0x200 offset probably *is* now set in stone. But still it's only valid to use it if we *know* it's a 64-bit kernel. And we don't. There *is* no ELF header that we can look at when we're booting a bzImage, and we can't rely on it having a PE/COFF header either. The 32-bit entry point is always guaranteed to work, and we need to support it anyway. So let's just *always* use it, in 32-bit mode, and then we don't have to make up some horrible heuristics for detecting 32-bit vs. 64-bit kernels. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: David Woodhouse <david.woodho...@intel.com> --- v2: Updated the MASM assembler too. Mostly using byte opcodes because MASM sucks. In both versions I've adjusted the far-call mechanism for entering compatible mode, to match what we can actually get to work in MASM. I've found a copy of ml64.exe and confirmed the output looks identical to the gas version which I've tested for booting both 32-bit and 64-bit kernels. I think this is ready to apply now. diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/LinuxGdt.c b/edk2/OvmfPkg/Library/LoadLinuxLib/LinuxGdt.c index 4e20436..58c097c 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/LinuxGdt.c +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/LinuxGdt.c @@ -83,7 +83,11 @@ STATIC GDT_ENTRIES GdtTemplate = { 0x0, // base 0 0x0, 0x09A, // present, ring 0, data, expand-up, writable +#ifdef MDE_CPU_IA32 0x0CF, // page-granular, 32-bit +#else + 0x0AF, // compatibility mode +#endif 0x0, }, // diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.S b/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.S index 9ae755b..0eaebf9 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.S +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.S @@ -23,8 +23,46 @@ ASM_GLOBAL ASM_PFX(JumpToKernel) # ); #------------------------------------------------------------------------------ ASM_PFX(JumpToKernel): + + // Set up for executing kernel. BP in %esi, entry point on the stack + // (64-bit when the 'ret' will use it as 32-bit, but we're little-endian) movq %rdx, %rsi - addq $0x200, %rcx - callq %rcx + pushq %rcx + + // Jump into the compatibility mode CS + pushq $0x10 + pushq $1f + retfq + +1: // Now in compatibility mode +.code32 + movl $0x18, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + // Disable paging + movl %cr0, %eax + btcl $31, %eax + movl %eax, %cr0 + + // Disable long mode in EFER + movl $0x0c0000080, %ecx + rdmsr + btcl $8, %eax + wrmsr + + // Disable PAE + movl %cr4, %eax + btcl $5, %eax + movl %eax, %cr4 + + // Zero registers and 'return' to kernel + xorl %ebp, %ebp + xorl %edi, %edi + xorl %ebx, %ebx ret +.code64 diff --git a/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.asm b/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.asm index ed53321..1ba737c 100644 --- a/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.asm +++ b/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.asm @@ -24,10 +24,47 @@ ;------------------------------------------------------------------------------ JumpToKernel PROC - mov rsi, rdx - add rcx, 200h - call rcx - ret + ; Set up for executing kernel. BP in %esi, entry point on the stack + ; (64-bit when the 'ret' will use it as 32-bit, but we're little-endian) + mov rsi, rdx + push rcx + + ; Jump into the compatibility mode CS + push 10h + push @F + DB 048h, 0cbh ; retfq + +@@: + ; Now in compatibility mode. MASM doesn't support 32-bit code so + ; we have to do it this way... + + DB 0b8h, 018h, 000h, 000h, 000h ; movl $0x18, %eax + DB 08eh, 0d8h ; movl %eax, %ds + DB 08eh, 0c0h ; movl %eax, %es + DB 08eh, 0e0h ; movl %eax, %fs + DB 08eh, 0e8h ; movl %eax, %gs + DB 08eh, 0d0h ; movl %eax, %ss + + ; Disable paging + DB 00fh, 020h, 0c0h ; movl %cr0, %eax + DB 00fh, 0bah, 0f8h, 01fh ; btcl $31, %eax + DB 00fh, 022h, 0c0h ; movl %eax, %cr0 + + ; Disable long mode in EFER + DB 0b9h, 080h, 000h, 000h, 0c0h ; movl $0x0c0000080, %ecx + DB 00fh, 032h ; rdmsr + DB 00fh, 0bah, 0f8h, 008h ; btcl $8, %eax + DB 00fh, 030h ; wrmsr + + ; Disable PAE + DB 00fh, 020h, 0e0h ; movl %cr4, %eax + DB 00fh, 0bah, 0f8h, 005h ; btcl $5, %eax + DB 00fh, 022h, 0e0h ; movl %eax, %cr4 + + DB 031h, 0edh ; xor %ebp, %ebp + DB 031h, 0ffh ; xor %edi, %edi + DB 031h, 0dbh ; xor %ebx, %ebx + DB 0c3h ; ret JumpToKernel ENDP -- dwmw2
smime.p7s
Description: S/MIME cryptographic signature
------------------------------------------------------------------------------ Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery and much more. Keep your Java skills current with LearnJavaNow - 200+ hours of step-by-step video tutorials by Java experts. SALE $49.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122612
_______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel