From b6ea8c8a8bc482ea2fadd1826f25e62cabb81e57 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 4 Sep 2009 15:09:50 -0700 Subject: [PATCH] pxelinux: workaround for EFI CSM bug - BEV stack overwrite on localboot On at least some machines with an EFI-based BIOS, the Compatibility Service Module (CSM) puts the BEV stack at an address where the boot loader is likely to overwrite it. Implement a workaround which forces INT 18h instead if an EFI signature is detected in memory. Signed-off-by: H. Peter Anvin --- core/pxelinux.asm | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/core/pxelinux.asm b/core/pxelinux.asm index 190f4c6..b274514 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -268,6 +268,81 @@ _start1: call writestr_early ; +; Look to see if we are on an EFI CSM system. Some EFI +; CSM systems put the BEV stack in low memory, which means +; a return to the PXE stack will crash the system. However, +; INT 18h works reliably, so in that case hack the stack and +; point the "return address" to an INT 18h instruction. +; +; Hack the stack instead of the much simpler "just invoke INT 18h +; if we want to reset", so that chainloading other NBPs will work. +; +efi_csm_workaround: + les bp,[InitStack] ; GS:SP -> original stack + les bx,[es:bp+44] ; Return address + cmp word [es:bx],18CDh ; Already pointing to INT 18h? + je .skip + + ; Search memory from E0000 to FFFFF for a $EFI structure + mov bx,0E000h +.scan_mem: + mov es,bx + cmp dword [es:0],'IFE$' ; $EFI is byte-reversed... + jne .not_here + ; + ; Verify the table. We don't check the checksum because + ; it seems some CSMs leave it at zero. + ; + movzx cx,byte [es:5] ; Table length + cmp cx,83 ; 83 bytes is the current length... + jae .found_it + +.not_here: + inc bx + jnz .scan_mem + jmp .skip ; No $EFI structure found + + ; + ; Found a $EFI structure. Move down the original stack + ; and put an INT 18h instruction there instead. + ; +.found_it: +%if USE_PXE_PROVIDED_STACK + mov cx,efi_csm_hack_size + mov si,sp + sub sp,cx + mov di,sp + mov ax,ss + mov es,ax + sub [InitStack],cx + sub [BaseStack],cx +%else + les si,[InitStack] + lea di,[si-efi_csm_hack_size] + mov [InitStack],di +%endif + lea cx,[bp+52] ; End of the stack we care about + sub cx,si + es rep movsb + mov [es:di-8],di ; Clobber the return address + mov [es:di-6],es + mov si,efi_csm_hack + mov cx,efi_csm_hack_size + rep movsb + +.skip: + + section .data + alignz 4 +efi_csm_hack: + int 18h + jmp 0F000h:0FFF0h + hlt +efi_csm_hack_size equ $-efi_csm_hack + + section .text + +; ; Assume API version 2.1, in case we find the !PXE structure without ; finding the PXENV+ structure. This should really look at the Base ; Code ROM ID structure in have_pxe, but this is adequate for now -- -- 2.7.4