diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-09-04 15:09:50 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-09-04 15:09:50 -0700 |
commit | b6ea8c8a8bc482ea2fadd1826f25e62cabb81e57 (patch) | |
tree | e6f6a65d5ca8e21dd4d84dafd470981daefd1bb8 /core | |
parent | 788da3035b2cf325658d6123b1bef73c67290f68 (diff) | |
download | syslinux-b6ea8c8a8bc482ea2fadd1826f25e62cabb81e57.tar.gz |
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 <hpa@zytor.com>
Diffstat (limited to 'core')
-rw-r--r-- | core/pxelinux.asm | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/core/pxelinux.asm b/core/pxelinux.asm index 190f4c66..b2745146 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 -- |