4 ;******************************************************************************
5 title A20TRAP
.ASM
- I
/O trap handlers for watching the A20 line
.
6 ;******************************************************************************
8 ; (C) Copyright MICROSOFT Corp. 1986
10 ; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
12 ; Module: A20TRAP.ASM - I/O trap handlers for watching the A20 line.
20 ;******************************************************************************
24 ; DATE REVISION DESCRIPTION
25 ; -------- -------- -------------------------------------------------------
26 ; 07/03/86 0.03 From ChkDisA20 routine in VMINST.
28 ;******************************************************************************
30 ; Functional Description:
31 ; This module contains the I/O trap handlers for the A20 line watching
35 ; COMMENTS: This module displays weaknesses due to carryover from previous
36 ; sources. A lot of the code here can be shifted to the LAST
37 ; segment. There is a duplication of routines for getting the a20
39 ;******************************************************************************
40 .lfcond
; list false conditionals
43 ;******************************************************************************
44 ; P U B L I C D E C L A R A T I O N S
45 ;******************************************************************************
54 public get_init_a20_state
58 ;******************************************************************************
59 ; E X T E R N A L R E F E R E N C E S
60 ;******************************************************************************
74 ;******************************************************************************
75 ; L O C A L C O N S T A N T S
76 ;******************************************************************************
84 A20CmdBit equ
02h ; high is enabled
88 KbdCmdPort equ 64h
; 8042 cmd port
89 KbdWrtData equ
0D1h ; Enable write to data port
90 KbdDataPort equ 60h
; 8042 data port
91 KbdStatusPort equ 64h
; 8042 cmd port
92 KbdBufFull equ
2 ; Buffer bull(data not received) status
94 ; equates for the state_a20 flag
96 A20_ON equ A20CmdBit
;
99 ; equate for the bit which will toggle the state of
101 WRAP_BIT equ
00100000h ; page table entry bit
103 ;******************************************************************************
104 ; S E G M E N T D E F I N I T I O N
105 ;******************************************************************************
113 KbdComd db 0 ; last CMD written to port 64h
114 state_a20 db 0 ; A20 line state: A20_ON is on, A20_OFF is off
120 ;------------------------------------------------------------------------------
122 assume
cs:_TEXT
, ds:DGROUP
, es:DGROUP
, ss:DGROUP
124 ;******************************************************************************
125 ; L O C A L D A T A A R E A
126 ;******************************************************************************
129 ;******************************************************************************
130 ; A20_Handler - I/O trap handler for Address line 20 modification
132 ; ENTRY: Protected Mode Ring 0
133 ; AL = byte to output to port.
134 ; BX == 2 * port address(either KbdDataPort or KbdCmdPort)
135 ; DX == 0 => Emulate input
136 ; <> 0 => Emulate output
138 ; SS:BP = points to stack frame on entry to GP fault handler
141 ; CLC => I/O emulated.
142 ; STC => I/O NOT emulated.
146 ;------------------------------------------------------------------------------
147 A20_Handler proc
near
148 or dx,dx ;Q: Output ?
149 jnz A20_Write
; Y: check for write to output port
150 stc ; N: don't bother to emulate it
153 cmp bx,KbdDataPort
*2 ;Q: Keyboard data port?
154 jne Kbd_C_Handler
; N: Go handle Kybd Command output
155 ; Y: Go handle Kybd Data output
157 ; keyboard data write
159 cmp [KbdComd
],KbdWrtData
;Q: write to output port?
160 mov [KbdComd
],0 ; data port write => no CMD
161 je Kbd_D_out
; Y: filter client's data
162 stc ; N: don't bother to emulate it
165 ; here if Output Port write
168 push ax ; Set A20 cmd bit
169 call check_a20_togl
; do we need to toggle the
171 jz skip_togl
; N: Skip routine to toggle
174 or al, A20CmdBit
; to leave A20 enabled
175 out KbdDataPort
,al ; "emulate" it
176 pop ax ; restore client's byte
180 ;Output to Keyboard command port
183 mov [KbdComd
],al ; Y: save new port 64 byte
184 stc ; don't bother to emulate it
190 ;******************************************************************************
191 ; A20_Trap_Init - turn on I/O bit map trapping for A20 line watching
193 ; ENTRY: DS -> DGROUP - real,virtual, or protected mode
195 ; IOTrap_Tab already has address of A20_Handler for KbdDataPort and
198 ; EXIT: IO_BitMap Updated to trap ports used to change A20 line
202 ;------------------------------------------------------------------------------
203 A20_Trap_Init proc
near
209 ; Set IOBM traps to look for client's disabling of the A20 line
211 mov bh, 80h
; set every 1k
213 call PortTrap
; set traps on keyboard ports
214 mov ax, KbdCmdPort
; in case client
215 call PortTrap
; tries to disable A20
220 ;*****************************************************************************;
221 ;*** EnableA20 - switch 20th address line ;
223 ; This routine is used to enable the 20th address line in ;
226 ; In general when in real mode we want the A20 line disabled, ;
227 ; when in protected mode enabled. However if there is no high ;
228 ; memory installed we can optimise out unnecessary switching ;
229 ; of the A20 line. Unfortunately the PC/AT ROM does not allow ;
230 ; us to completely decouple mode switching the 286 from gating ;
233 ; In real mode we would want A20 enabled if we need to access ;
234 ; high memory, for example in a device driver. We want it ;
235 ; disabled while running arbitrary applications because they ;
236 ; may rely on the 1 meg address wrap feature which having the ;
237 ; A20 line off provides. ;
239 ; This code is largely duplicated from the PC/AT ROM BIOS. ;
240 ; See Module "BIOS1" on page 5-155 of the PC/AT tech ref. ;
242 ; ENTRY none ;ds = DGROUP ;
243 ; EXIT A20 line enabled ;
244 ; USES ax, flags modified ;
248 ; The performance characteristics of these routines ;
249 ; are not well understood. There may be worst case ;
250 ; scenarios where the routine could take a relatively ;
251 ; long time to complete. ;
255 ; 8042 error handling ;
256 ;*****************************************************************************;
258 mov ah,0dfh ; code for enable
259 jmp a20common
; jump to common code
263 ;*****************************************************************************;
264 ;*** DisableA20 - switch 20th address line ;
266 ; This routine is used to disable the 20th address line in ;
269 ; ENTRY none ;ds = DATA ;
270 ; EXIT A20 line disabled ;
272 ; USES ax, flags modified ;
273 ;*****************************************************************************;
276 mov ah,0ddh ; code for disable
277 jmp a20common
; jump to common code
284 ; This is entered via a jmp from one of the two procedural
285 ; entry points above.
287 call empty_8042
; ensure 8042 input buffer empty
288 jnz com1
; 8042 error return
289 mov al,0d1h ; 8042 cmd to write output port
290 out KbdCmdPort
,al ; send cmd to 8042
291 call empty_8042
; wait for 8042 to accept cmd
292 jnz com1
; 8042 error return
293 mov al,ah ; 8042 port data
294 out KbdDataPort
,al ; output port data to 8042
296 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
298 ; AST P/386 needs the delay for their
299 ; A20 switch settle. If not, it won't work !
307 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
313 ;*****************************************************************************;
314 ;*** empty_8042 - wait for 8042 input buffer to drain ;
317 ; EXIT al=0, z=0 => 8042 input buffer empty ;
318 ; al=2, z=1 => timeout, input buffer full ;
320 ;*****************************************************************************;
323 sub cx,cx ; cx = 0, timeout loop counter
325 in al,KbdStatusPort
; read 8042 status port
326 and al,KbdBufFull
; test buffer full bit
332 ;*****************************************************************************;
333 ;*** check_a20_togl - check if a20 state emulated needs to be toggled ;
335 ; ENTRY [state_a20] = A20 emulated state ;
336 ; al = byte to output to kbd data port ;
337 ; EXIT Z set if A20 not to be toggled ;
338 ; clear if A20 to be toggled ;
341 ;*****************************************************************************;
342 check_a20_togl proc
near
345 and al,A20CmdBit
; make all other bits 0
346 xor al,[state_a20
] ; does the state of the a20 bit match
348 ; N: then Z is not set
355 ;*****************************************************************************;
356 ;*** get_a20_state - see if virtualised a20 is enabled or not ;
358 ; ENTRY [state_a20] = A20 emulated state ;
360 ; EXIT ZF set if A20 disabled ;
361 ; ZF not set if A20 enabled ;
364 ;*****************************************************************************;
366 get_a20_state proc
near
368 test [state_a20
], A20_ON
373 ;*****************************************************************************;
374 ;*** togl_A20 - toggle emulated A20 state. ;
376 ; ENTRY [state_a20] = A20 emulated state ;
377 ; PROTECTED MODE ONLY ;
380 ; EXIT [state_a20] toggled ;
381 ; page table entries for the 1M --> 1M + 64k area toggled ;
386 ;*****************************************************************************;
394 ; get addressability to page table
399 ; and offset into entries for the 64k block at 1M
401 mov di,100h
*4 ; 1024k/4k = 256 entries, each 4 bytes long
402 mov cx,10h
; 64k/4k = 16 entries
405 ; for all the entries flip the bit which will make the entries either wrap
406 ; around for 1M-1M+64k to either 1M-1M+64k or 0-64k. This bit is the 1M bit
407 ; in the base address.
410 xor dword ptr es:[di], WRAP_BIT
421 xor [state_a20
],A20_ON
423 ; restore the registers
435 _TEXT ends
; end of segment
439 assume
cs:LAST
, ds:DGROUP
, es:DGROUP
, ss:DGROUP
442 ;******************************************************************************
445 ; since we are fixing the a20 state to be always enabled we need to implement ;
446 ; a logical a20 state independent of the physical one. this routine inits ;
447 ; this state. we do this comparing 3 double words at 0:80 and 1M:80. if these;
448 ; compare the a20 is disabled thus causing a wraparound. ;
452 ; OUTPUTS: [state_a20] .. A20_ON if a20 is on currently ;
453 ; .. A20_OFF if a20 is off currently ;
457 ; AUTHOR: ISP. Shifted in from smartdrv sources. 8/29/88. ;
459 ;*****************************************************************************;
460 ; A20 address line state determination addresses
470 estb_a20_state proc
near
477 ; initialise a20 to off
479 mov [state_a20
],A20_OFF
481 ; compare 3 dwords at 0:80h and 1M:80h. if these are equal then
482 ; we can assume that a20 is off
495 ASSUME
DS:DGROUP
,ES:DGROUP
500 mov [state_a20
],A20_ON
506 ;*****************************************************************************;
507 ;*** get_init_a20_state - see if virtualised a20 is enabled or not ;
509 ; ENTRY [state_a20] = A20 state at startup ;
511 ; EXIT ZF set if A20 disabled ;
512 ; ZF not set if A20 enabled ;
515 ;*****************************************************************************;
517 ASSUME
DS:DGROUP
,ES:NOTHING
519 get_init_a20_state proc
near
521 test [state_a20
], A20_ON
523 get_init_a20_state endp