summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-05-21 10:25:43 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-05-21 10:25:43 -0700
commit652070309f5d283efacaa8c5102368da20a92c4a (patch)
treefbd14207e9c3c4b92c19a177a9f52993a60c5603 /core
parent55092109e53ae43ceefb5f7c6314aff103931c9a (diff)
downloadsyslinux-652070309f5d283efacaa8c5102368da20a92c4a.tar.gz
idle: handle PXE stacks which improperly disable interruptssyslinux-3.81-pre9
At least Etherboot (and all-but-super-recent versions of gPXE) PXE ROMs improperly disable interrupts when calling an intercepted version of INT 15h and 1Ah; this is due to the old trick of using "ret 2" to return... this avoids resetting the flags for status, but it also doesn't restore the value of the interrupt flag. Needless to say, this causes serious issues. Work around it by adding explicit pushf/popf or STI in places known to have issues, but also add an STI in reset_idle, and add an error alert in do_idle if we ever get called with interrupts disabled. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'core')
-rw-r--r--core/conio.inc2
-rw-r--r--core/highmem.inc2
-rw-r--r--core/idle.inc30
-rw-r--r--core/pxelinux.asm3
-rw-r--r--core/ui.inc1
5 files changed, 34 insertions, 4 deletions
diff --git a/core/conio.inc b/core/conio.inc
index 2d8c61ad..4488c94a 100644
--- a/core/conio.inc
+++ b/core/conio.inc
@@ -286,8 +286,8 @@ write_serial_str:
; pollchar: check if we have an input character pending (ZF = 0)
;
pollchar:
- pushad
call do_idle
+ pushad
mov ah,11h ; Poll keyboard
int 16h
jnz .done ; Keyboard response
diff --git a/core/highmem.inc b/core/highmem.inc
index 5ae3abea..c7e602f8 100644
--- a/core/highmem.inc
+++ b/core/highmem.inc
@@ -25,6 +25,7 @@
;
highmemsize:
push es
+ pushfd
pushad
push cs
@@ -152,6 +153,7 @@ got_highmem:
%endif
mov [HighMemSize],eax
popad
+ popfd
pop es
ret ; Done!
diff --git a/core/idle.inc b/core/idle.inc
index c2ce1348..67a5c3ed 100644
--- a/core/idle.inc
+++ b/core/idle.inc
@@ -19,6 +19,7 @@ reset_idle:
mov ax,[cs:BIOS_timer]
mov [cs:IdleTimer],ax
pop ax
+ sti ; Guard against BIOS/PXE brokenness...
ret
do_idle:
@@ -28,6 +29,31 @@ do_idle:
mov ax,cs
mov ds,ax
mov es,ax
+ pushf
+ pop ax
+ test ah,2
+ jnz .ok
+ push si
+ push cx
+ mov si,hlt_err
+ call writestr
+ mov si,sp
+ add si,10
+ mov cx,16
+.errloop:
+ ss lodsw
+ call writehex4
+ dec cx
+ jz .endloop
+ mov al,' '
+ call writechr
+ jmp .errloop
+.endloop:
+ call crlf
+ pop cx
+ pop si
+ sti
+.ok:
mov ax,[BIOS_timer]
sub ax,[IdleTimer]
cmp ax,TICKS_TO_IDLE
@@ -43,8 +69,10 @@ do_idle:
.ret: ret
section .data
-NoHalt dw 0
IdleHook dw do_idle.ret
+NoHalt dw 1
+
+hlt_err db 'ERROR: idle with IF=0', CR, LF, 0
section .bss
IdleTimer resw 1
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index ad1686c1..9d9d5b4d 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -308,10 +308,11 @@ _start1:
%if USE_PXE_PROVIDED_STACK == 0
lss sp,[InitStack]
%endif
- int 1Ah ; May trash regs
+ int 1Ah ; May trash regs
%if USE_PXE_PROVIDED_STACK == 0
lss esp,[BaseStack]
%endif
+ sti ; Work around Etherboot bug
jc no_int1a
cmp ax,564Eh
diff --git a/core/ui.inc b/core/ui.inc
index a12233c2..1b40717a 100644
--- a/core/ui.inc
+++ b/core/ui.inc
@@ -532,7 +532,6 @@ getchar_timeout:
pop ax
cmp ax,[BIOS_timer] ; Has the timer advanced?
je .loop
- call do_idle
dec dword [ThisKbdTo]
jz .timeout