summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--ldlinux.asm102
-rw-r--r--pxelinux.asm102
3 files changed, 143 insertions, 66 deletions
diff --git a/NEWS b/NEWS
index 951c8bf0..0a9e02ca 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,11 @@
Starting with 1.47, changes marked with SYSLINUX/PXELINUX apply to
that specific program only; other changes apply to both.
+Changes in 1.50:
+ * Yet another A20-code update. It seems some "legacy-free"
+ machines and embedded gear simply don't have a KBC to talk
+ to, and that waiting for one will wait forever. Sigh.
+
Changes in 1.49:
* SYSLINUX: Implement a hack for BIOS drivers which hog significant
chunks of low memory during boot. (Note: PXELINUX already
diff --git a/ldlinux.asm b/ldlinux.asm
index 88db90bd..3edb25bf 100644
--- a/ldlinux.asm
+++ b/ldlinux.asm
@@ -16,7 +16,7 @@
; then the first sector (cluster, really, but we can only assume 1 sector)
; of LDLINUX.SYS at 7E00h and finally the remainder of LDLINUX.SYS at 8000h.
;
-; Copyright (C) 1994-1999 H. Peter Anvin
+; Copyright (C) 1994-2000 H. Peter Anvin
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
@@ -373,6 +373,7 @@ RetryCount resb 1 ; Used for disk access retries
KbdFlags resb 1 ; Check for keyboard escapes
LoadFlags resb 1 ; Loadflags from kernel
A20Tries resb 1 ; Times until giving up on A20
+A20KBCflag resb 1 ; Did we use KBC to access A20?
FuncFlag resb 1 ; Escape sequences received from keyboard
MNameBuf resb 11 ; Generic mangled file name buffer
InitRD resb 11 ; initrd= mangled name
@@ -2490,18 +2491,16 @@ bcopy: push eax
slow_out: out dx, al ; Fall through
-_io_delay: push ax
- in ax,IO_DELAY_PORT
- in ax,IO_DELAY_PORT
- in ax,IO_DELAY_PORT
- in ax,IO_DELAY_PORT
- pop ax
+_io_delay: out IO_DELAY_PORT,al
+ out IO_DELAY_PORT,al
+ out IO_DELAY_PORT,al
+ out IO_DELAY_PORT,al
ret
enable_a20:
mov byte [ss:A20Tries],255 ; Times to try to make this work
-try_enable_a20:
+.try_enable_a20:
;
; Flush the caches
;
@@ -2510,44 +2509,46 @@ try_enable_a20:
;
; Enable the "fast A20 gate"
;
+ mov byte [ss:A20KBCflag], 0 ; Haven't used the KBC yet
in al, 092h
or al,02h
+ and al,~01h ; Don't accidentally reset the machine!
out 092h, al
;
; Enable the keyboard controller A20 gate
;
+ mov dl, 1 ; Allow early exit
call empty_8042
- mov al,0D1h ; Command write
+ jnz .a20_wait ; A20 live, no need to use KBC
+
+ mov byte [ss:A20KBCflag], 1 ; We touched the KBC
+ mov al,0D1h ; Command write
out 064h, al
- call empty_8042
+ call empty_8042_uncond
+
mov al,0DFh ; A20 on
out 060h, al
- call kbc_delay
+ call empty_8042_uncond
+
; Verify that A20 actually is enabled. Do that by
; observing a word in low memory and the same word in
; the HMA until they are no longer coherent. Note that
; we don't do the same check in the disable case, because
; we don't want to *require* A20 masking (SYSLINUX should
; work fine without it, if the BIOS does.)
- push es
- push cx
- mov cx,0FFFFh ; Times to try, also HMA
- mov es,cx ; HMA = segment 0FFFFh
-.a20_wait: inc word [ss:A20Test]
- call try_wbinvd
- mov ax,[es:A20Test+10h]
- cmp ax,[ss:A20Test]
- jne .a20_done
- loop .a20_wait
+.a20_wait: push cx
+ mov cx, 0FFFFh
+.a20_wait_loop:
+ call a20_test
+ jnz .a20_done
+ loop .a20_wait_loop
;
; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
; and report failure to the user.
;
pop cx
- pop es
-
dec byte [ss:A20Tries]
- jnz try_enable_a20
+ jnz .try_enable_a20
mov si, err_a20
jmp abort_load
@@ -2555,6 +2556,27 @@ try_enable_a20:
; A20 unmasked, proceed...
;
.a20_done: pop cx
+ ret
+
+;
+; This routine tests if A20 is enabled (ZF = 0). This routine
+; must not destroy any register contents.
+;
+a20_test:
+ push es
+ push cx
+ push ax
+ mov cx,0FFFFh ; HMA = segment 0FFFFh
+ mov es,ax
+ mov cx,0100h ; Loop count
+ mov ax,[ss:A20Test]
+.a20_wait: inc ax
+ mov [ss:A20Test],ax
+ call try_wbinvd
+ cmp ax,[es:A20Test+10h]
+ loopz .a20_wait
+.a20_done: pop ax
+ pop cx
pop es
ret
@@ -2567,29 +2589,43 @@ disable_a20:
; Disable the "fast A20 gate"
;
in al, 092h
- and al,~02h
+ and al,~03h
out 092h, al
;
; Disable the keyboard controller A20 gate
;
- call empty_8042
+ test [ss:A20KBCflag], byte 01h
+ jz .snooze ; Never messed with the KBC
+
+ ; We did mess with the KBC, so we have to do this..
+ call empty_8042_uncond
mov al,0D1h
out 064h, al ; Command write
- call empty_8042
+ call empty_8042_uncond
mov al,0DDh ; A20 off
out 060h, al
- ; Fall through/tailcall to kbc_delay
-
-kbc_delay: call empty_8042
- push cx
+ call empty_8042_uncond
+ ; Wait a bit for it to take effect
+.snooze: push cx
mov cx, delaytime
.delayloop: io_delay
loop .delayloop
pop cx
ret
+;
+; Routine to empty the 8042 KBC controller. If dl != 0
+; then we will test A20 in the loop and exit if A20 is
+; suddenly enabled.
+;
+empty_8042_uncond:
+ xor dl,dl
empty_8042:
- io_delay
+ call a20_test
+ jz .a20_on
+ and dl,dl
+ jnz .done
+.a20_on: io_delay
in al, 064h ; Status port
test al,1
jz .no_output
@@ -2600,7 +2636,7 @@ empty_8042:
test al,2
jnz empty_8042
io_delay
- ret
+.done: ret
;
; WBINVD instruction; gets auto-eliminated on 386 CPUs
diff --git a/pxelinux.asm b/pxelinux.asm
index 5734ea3a..39f5a93a 100644
--- a/pxelinux.asm
+++ b/pxelinux.asm
@@ -8,7 +8,7 @@
; network booting API. It is based on the SYSLINUX boot loader for
; MS-DOS floppies.
;
-; Copyright (C) 1994-1999 H. Peter Anvin
+; Copyright (C) 1994-2000 H. Peter Anvin
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
@@ -365,6 +365,7 @@ RetryCount resb 1 ; Used for disk access retries
KbdFlags resb 1 ; Check for keyboard escapes
LoadFlags resb 1 ; Loadflags from kernel
A20Tries resb 1 ; Times until giving up on A20
+A20KBCflag resb 1 ; Did we use KBC to access A20?
FuncFlag resb 1 ; == 1 if <Ctrl-F> pressed
alignb tftp_port_t_size
@@ -2043,18 +2044,16 @@ bcopy: push eax
slow_out: out dx, al ; Fall through
-_io_delay: push ax
- in ax,IO_DELAY_PORT
- in ax,IO_DELAY_PORT
- in ax,IO_DELAY_PORT
- in ax,IO_DELAY_PORT
- pop ax
+_io_delay: out IO_DELAY_PORT,al
+ out IO_DELAY_PORT,al
+ out IO_DELAY_PORT,al
+ out IO_DELAY_PORT,al
ret
enable_a20:
mov byte [ss:A20Tries],255 ; Times to try to make this work
-try_enable_a20:
+.try_enable_a20:
;
; Flush the caches
;
@@ -2063,44 +2062,46 @@ try_enable_a20:
;
; Enable the "fast A20 gate"
;
+ mov byte [ss:A20KBCflag], 0 ; Haven't used the KBC yet
in al, 092h
or al,02h
+ and al,~01h ; Don't accidentally reset the machine!
out 092h, al
;
; Enable the keyboard controller A20 gate
;
+ mov dl, 1 ; Allow early exit
call empty_8042
- mov al,0D1h ; Command write
+ jnz .a20_wait ; A20 live, no need to use KBC
+
+ mov byte [ss:A20KBCflag], 1 ; We touched the KBC
+ mov al,0D1h ; Command write
out 064h, al
- call empty_8042
+ call empty_8042_uncond
+
mov al,0DFh ; A20 on
out 060h, al
- call kbc_delay
+ call empty_8042_uncond
+
; Verify that A20 actually is enabled. Do that by
; observing a word in low memory and the same word in
; the HMA until they are no longer coherent. Note that
; we don't do the same check in the disable case, because
; we don't want to *require* A20 masking (SYSLINUX should
; work fine without it, if the BIOS does.)
- push es
- push cx
- mov cx,0FFFFh ; Times to try, also HMA
- mov es,cx ; HMA = segment 0FFFFh
-.a20_wait: inc word [ss:A20Test]
- call try_wbinvd
- mov ax,[es:A20Test+10h]
- cmp ax,[ss:A20Test]
- jne .a20_done
- loop .a20_wait
+.a20_wait: push cx
+ mov cx, 0FFFFh
+.a20_wait_loop:
+ call a20_test
+ jnz .a20_done
+ loop .a20_wait_loop
;
; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
; and report failure to the user.
;
pop cx
- pop es
-
dec byte [ss:A20Tries]
- jnz try_enable_a20
+ jnz .try_enable_a20
mov si, err_a20
jmp abort_load
@@ -2108,6 +2109,27 @@ try_enable_a20:
; A20 unmasked, proceed...
;
.a20_done: pop cx
+ ret
+
+;
+; This routine tests if A20 is enabled (ZF = 0). This routine
+; must not destroy any register contents.
+;
+a20_test:
+ push es
+ push cx
+ push ax
+ mov cx,0FFFFh ; HMA = segment 0FFFFh
+ mov es,ax
+ mov cx,0100h ; Loop count
+ mov ax,[ss:A20Test]
+.a20_wait: inc ax
+ mov [ss:A20Test],ax
+ call try_wbinvd
+ cmp ax,[es:A20Test+10h]
+ loopz .a20_wait
+.a20_done: pop ax
+ pop cx
pop es
ret
@@ -2120,29 +2142,43 @@ disable_a20:
; Disable the "fast A20 gate"
;
in al, 092h
- and al,~02h
+ and al,~03h
out 092h, al
;
; Disable the keyboard controller A20 gate
;
- call empty_8042
+ test [ss:A20KBCflag], byte 01h
+ jz .snooze ; Never messed with the KBC
+
+ ; We did mess with the KBC, so we have to do this..
+ call empty_8042_uncond
mov al,0D1h
out 064h, al ; Command write
- call empty_8042
+ call empty_8042_uncond
mov al,0DDh ; A20 off
out 060h, al
- ; Fall through/tailcall to kbc_delay
-
-kbc_delay: call empty_8042
- push cx
+ call empty_8042_uncond
+ ; Wait a bit for it to take effect
+.snooze: push cx
mov cx, delaytime
.delayloop: io_delay
loop .delayloop
pop cx
ret
+;
+; Routine to empty the 8042 KBC controller. If dl != 0
+; then we will test A20 in the loop and exit if A20 is
+; suddenly enabled.
+;
+empty_8042_uncond:
+ xor dl,dl
empty_8042:
- io_delay
+ call a20_test
+ jz .a20_on
+ and dl,dl
+ jnz .done
+.a20_on: io_delay
in al, 064h ; Status port
test al,1
jz .no_output
@@ -2153,7 +2189,7 @@ empty_8042:
test al,2
jnz empty_8042
io_delay
- ret
+.done: ret
;
; WBINVD instruction; gets auto-eliminated on 386 CPUs