windows-nt/Source/XPSP1/NT/base/boot/startrom/i386/a20.asm
2020-09-26 16:20:57 +08:00

280 lines
9.2 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; 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