summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-09-04 15:09:50 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-09-04 15:09:50 -0700
commitb6ea8c8a8bc482ea2fadd1826f25e62cabb81e57 (patch)
treee6f6a65d5ca8e21dd4d84dafd470981daefd1bb8 /core
parent788da3035b2cf325658d6123b1bef73c67290f68 (diff)
downloadsyslinux-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.asm75
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 --