|
|
; 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
|