; =============================================================================
;
; Litos - Initialize A20 address line, real mode
;
; =============================================================================
%ifdef DEBUG
;%define DEBUG_A20 ; uncomment this to display A20 info
%endif
CODE_SECTION 16
%define INITA20_LOOPS 250 ; number of tries to enable A20 gate
; -----------------------------------------------------------------------------
; Test A20 address line
; -----------------------------------------------------------------------------
; OUTPUT: ZY (ZF=1): A20 not enabled, NZ (ZF=0): A20 enabled
; DESTROYS: All registers except DS
; -----------------------------------------------------------------------------
; ------------- Push registers
TestA20: push ds ; push DS
; ------------- Prepare registers
xor ax,ax ; AX <- 0
mov ds,ax ; DS <- 0
dec ax ; AX <- 0ffffh
mov es,ax ; ES <- 0ffffh
mov ch,15 ; CH <- number of A20 test loops HIGH
mov si,4*80h ; SI <- A20 test address (= Int 80h)
; ------------- Push old value from the test address
mov ax,[si] ; AX <- olf value from the test address
push ax ; push old value
; ------------- Check A20
TestA202: inc ax ; AX <- changed value
mov [si],ax ; change value on the test address
call ShortDelay ; short delay
cmp ax,[es:si+10h] ; check alternative address
loope TestA202 ; address content is the same
; ------------- Pop old value to the test address
pop word [si] ; return old value
; ------------- Pop registers
pop ds ; pop DS
ret
; -----------------------------------------------------------------------------
; Empty 8042 keyboard controller
; -----------------------------------------------------------------------------
; DESTROYS: All registers except DS
; -----------------------------------------------------------------------------
; ------------- Prepare time-out counters (for first loop CX may be random)
Empty8042: mov ah,10 ; AH <- time out value HIGH
; ------------- Check if input buffer is empty
Empty80422: in al,64h ; AL <- 8042 status port
test al,B1 ; input buffer is full?
jnz Empty80426 ; input buffer is full
; ------------- Check if output buffer is empty
test al,B0 ; output buffer is full?
jz Empty80428 ; output buffer is empty, all OK
; ------------- Flush output buffer
call ShortDelay ; short delay
in al,60h ; flush output buffer
; ------------- Next wait loop
Empty80426: call ShortDelay ; short delay
loop Empty80422 ; wait for empty input buffer
dec ah ; counter HIGH
jnz Empty80422 ; continue
Empty80428: ret
; -----------------------------------------------------------------------------
; Enable A20 address line gate
; -----------------------------------------------------------------------------
; INPUT: DS = data segment
; DESTROYS: All registers except DS
; -----------------------------------------------------------------------------
; NOTES: If it cannot enable A20 address line, it halts the system.
; -----------------------------------------------------------------------------
; ------------- Check if A20 address line is already enabled
InitA20:
%ifdef DEBUG_A20
mov si,A20Msg ; SI <- debug message
call BIOSDispText ; display text
%endif
call TestA20 ; test A20 address line
%ifdef DEBUG_A20
mov si,A20Msg1 ; SI <- debug message
%endif
jnz InitA209 ; A20 is enabled
; ------------- Enable A20 with BIOS
InitA202: mov ax,2401h ; AX <- function code
int 15h ; enable A20 address line
cli ; disable interrupts again
; ------------- Check if A20 address line is already enabled
call TestA20 ; test A20 address line
%ifdef DEBUG_A20
mov si,A20Msg2 ; SI <- debug message
%endif
jnz InitA209 ; A20 is enabled
; ------------- Enable A20 with keyboard controller
call Empty8042 ; empty 8042 keyboard controller
mov al,0d1h ; AL <- index of write output port
out 64h,al ; set index of write output port
call Empty8042 ; empty 8042 keyboard controller
mov al,0dfh ; AL <- enable A20
out 60h,al ; enable A20 with write output port
call Empty8042 ; empty 8042 keyboard controller
; ------------- Check if A20 address line is already enabled
call TestA20 ; test A20 address line
%ifdef DEBUG_A20
mov si,A20Msg3 ; SI <- debug message
%endif
jnz InitA209 ; A20 is enabled
; ------------- Fast A20 gating (if "Fast A20" is enabled with a BIOS setting)
cmp byte [InitA20Loops],INITA20_LOOPS-6 ; skip some loops
jae InitA205 ; carefully with "Fast A20"
in al,92h ; AL <- system control port A
test al,B1 ; is this port valid?
jnz InitA204 ; no fast A20 supported
or al,B1 ; enable A20 gate
and al,~B0 ; don't do fast reset
out 92h,al ; enable A20 gate
; ------------- Check if A20 address line is already enabled
InitA204: call TestA20 ; test A20 address line
%ifdef DEBUG_A20
mov si,A20Msg4 ; SI <- debug message
%endif
jnz InitA209 ; A20 is enabled
; ------------- Next loop
InitA205: dec byte [InitA20Loops] ; A20 loop counter
jnz InitA202 ; next A20 test
; ------------- Error enabling A20 gate
mov si,A20ErrMessage ; error message
call BIOSDispText ; display error message
InitA206: hlt ; halt system
jmp short InitA206 ; halt system
InitA209:
; ------------- Debug display method
%ifdef DEBUG_A20
call BIOSDispText ; display text
%endif
ret
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
DATA_SECTION
InitA20Loops: db INITA20_LOOPS ; number of tries to enable A20 gate
A20ErrMessage: db 'Error: Cannot enable A20!',0
; ------------- Debug messages
%ifdef DEBUG_A20
A20Msg: db 13,10,'A20 method: ',0
A20Msg1: db 'Enabled',13,10,0
A20Msg2: db 'BIOS 2401h',13,10,0
A20Msg3: db 'Keyboard controller',13,10,0
A20Msg4: db 'Fast A20',13,10,0
%endif
|