windows-nt/Source/XPSP1/NT/base/boot/startup/i386/a20.asm

280 lines
9.2 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
; NOTICE
; This was taken from the os2 bios sources and was slightly modified to
; enable the a20 line. There's still some work to do and much clean-up to
; bring the file upto coding standards. I'll do this when time permits.
; TomP
;* _EnableA20
;* Description: *
;* This routine enables and disables the A20 address line, depending on *
;* the value in ax *
;* *
;* In general when in real mode we want the A20 line disabled, *
;* when in protected mode enabled. However if there is no high *
;* memory installed we can optimise out unnecessary switching *
;* of the A20 line. Unfortunately the PC/AT ROM does not allow *
;* us to completely decouple mode switching the 286 from gating *
;* the A20 line. *
;* *
;* In real mode we would want A20 enabled if we need to access *
;* high memory, for example in a device driver. We want it *
;* disabled while running arbitrary applications because they *
;* may rely on the 1 meg address wrap feature which having the *
;* A20 line off provides. *
;* *
;* This code is largely duplicated from the PC/AT ROM BIOS. *
;* See Module "BIOS1" on page 5-155 of the PC/AT tech ref. *
;* *
;* WARNING: *
;* *
;* The performance characteristics of these routines *
;* are not well understood. There may be worst case *
;* scenarios where the routine could take a relatively *
;* long time to complete. *
;* *
;* Linkage: *
;* far call *
;* *
;* Input: *
;* *
;* Exit: *
;* A20 line enabled/disabled *
;* *
;* Uses: *
;* ax *
;* *
;* Internal References: *
;* empty_8042 -- waits for 8042 input buffer to drain *
.386p
include su.inc
IODelay macro
jmp $+2
endm
extrn _puts:near
extrn _Empty_8042Failed:near
; Equates for cmos
CMOS_DATA equ 71h ; I/O word for cmos chip
SHUT_ADDR equ 8fh ; shutdown byte address in cmos
SHUT_CODE equ 9 ; block copy return code we use
; equates for 8042
STATUS_PORT equ 64h ; 8042 com port
PORT_A equ 60h ; 8042 data port
BUF_FULL equ 2 ; 8042 busy bit
SHUT_CMD equ 0feh ; RESET 286 command
MSW_VIRTUAL equ 1 ; protected mode bit of MSW
MASTER_IMR equ 21h ; mask port for master 8259
;CONST SEGMENT WORD USE16 PUBLIC 'CONST'
;CONST ENDS
;_BSS SEGMENT WORD USE16 PUBLIC 'BSS'
;_BSS ENDS
;DGROUP GROUP CONST, _BSS, _DATA
; ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
_TEXT segment para use16 public 'CODE'
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
;++
;
;VOID
;EnableA20(
; VOID
; )
;
;Routine Description:
;
; Enables the A20 line for any machine.
;
;Arguments:
;
; None
;
;Return Value:
;
; None.
;
; The A20 line is enabled.
;
;--
public _EnableA20
_EnableA20 proc near
; Check if empty_8042 has failed before
; If so, skip this function. This would occur
; on legacy free systems.
mov di,offset DGROUP:_Empty_8042Failed
cmp byte ptr [di],1
jz EA2
; cmp byte ptr [di],0
call empty_8042 ; ensure 8042 input buffer empty
jnz EA2 ; 8042 error return
; Enable or disable the A20 line
mov al,0d1h ; 8042 cmd to write output port
out STATUS_PORT,al ; send cmd to 8042
call empty_8042 ; wait for 8042 to accept cmd
jnz EA2 ; 8042 error return
mov al,0dfh ; 8042 port data
out PORT_A,al ; output port data to 8042
call empty_8042
; We must wait for the a20 line to settle down, which (on an AT)
; may not happen until up to 20 usec after the 8042 has accepted
; the command. We make use of the fact that the 8042 will not
; accept another command until it is finished with the last one.
; The 0FFh command does a NULL 'Pulse Output Port'. Total execution
; time is on the order of 30 usec, easily satisfying the IBM 8042
; settling requirement. (Thanks, CW!)
mov al,0FFh ;* Pulse Output Port (pulse no lines)
out STATUS_PORT,al ;* send cmd to 8042
call empty_8042 ;* wait for 8042 to accept cmd
EA2:
ret
_EnableA20 endp
;++
;
;VOID
;DisableA20(
; VOID
; )
;
;Routine Description:
;
; Disables the A20 line for any machine.
;
;Arguments:
;
; None
;
;Return Value:
;
; None.
;
; The A20 line is disabled.
;
;--
public _DisableA20
_DisableA20 proc near
; Check if empty_8042 has failed before
; If so, skip this function. This would occur
; on legacy free systems.
mov di,offset DGROUP:_Empty_8042Failed
cmp byte ptr [di],1
jz EA2
cmp byte ptr [di],0
DA1:
call empty_8042 ; ensure 8042 input buffer empty
jnz DA2 ; 8042 error return
; Disable the A20 line
mov al,0d1h ; 8042 cmd to write output port
out STATUS_PORT,al ; send cmd to 8042
call empty_8042 ; wait for 8042 to accept cmd
jnz DA2 ; 8042 error return
mov al,0ddh ; 8042 port data
out PORT_A,al ; output port data to 8042
call empty_8042
; We must wait for the a20 line to settle down, which (on an AT)
; may not happen until up to 20 usec after the 8042 has accepted
; the command. We make use of the fact that the 8042 will not
; accept another command until it is finished with the last one.
; The 0FFh command does a NULL 'Pulse Output Port'. Total execution
; time is on the order of 30 usec, easily satisfying the IBM 8042
; settling requirement. (Thanks, CW!)
mov al,0FFh ;* Pulse Output Port (pulse no lines)
out STATUS_PORT,al ;* send cmd to 8042
call empty_8042 ;* wait for 8042 to accept cmd
DA2:
ret
_DisableA20 endp
;**
; empty_8042 -- wait for 8042 input buffer to drain
;
; Input:
; interrupts disabled
;
; Exit:
; al=0, z=0 => 8042 input buffer empty
;
; Uses:
; ax, flags
public Empty8042
Empty8042 proc near
empty_8042:
sub cx,cx ; cx = 0, timeout loop counter
emp1: in al,STATUS_PORT ; read 8042 status port
IODelay
IODelay
IODelay
IODelay
and al,BUF_FULL ; test buffer full bit
loopnz emp1
cmp cx,0 ; see if buffer is full
jnz emp2
; if we reached this point this indicates an error
mov di,offset DGROUP:_Empty_8042Failed
mov byte ptr [di],1
; mov [_Empty_8042Failed],1 ; set Empty_8042Failed global to "TRUE"
; mov _Empty_8042Failed,1 ; set Empty_8042Failed global to "TRUE"
; mov cx, offset _Empty_8042Failed
; mov [cx],ah
emp2:
and al,BUF_FULL ; reset the Z flag
ret
Empty8042 endp
_TEXT ends
end