]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/MEMM/MEMM/A20TRAP.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / MEMM / MEMM / A20TRAP.ASM
1
2
3 page 58,132
4 ;******************************************************************************
5 title A20TRAP.ASM - I/O trap handlers for watching the A20 line.
6 ;******************************************************************************
7 ;
8 ; (C) Copyright MICROSOFT Corp. 1986
9 ;
10 ; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
11 ;
12 ; Module: A20TRAP.ASM - I/O trap handlers for watching the A20 line.
13 ;
14 ; Version: 0.03
15 ;
16 ; Date: June 1, 1986
17 ;
18 ; Author:
19 ;
20 ;******************************************************************************
21 ;
22 ; Change log:
23 ;
24 ; DATE REVISION DESCRIPTION
25 ; -------- -------- -------------------------------------------------------
26 ; 07/03/86 0.03 From ChkDisA20 routine in VMINST.
27 ;
28 ;******************************************************************************
29 ;
30 ; Functional Description:
31 ; This module contains the I/O trap handlers for the A20 line watching
32 ; logic.
33 ;
34 ;
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
38 ; state. (ISP)
39 ;******************************************************************************
40 .lfcond ; list false conditionals
41 .386p
42 page
43 ;******************************************************************************
44 ; P U B L I C D E C L A R A T I O N S
45 ;******************************************************************************
46 ;
47 public A20_Handler
48 public A20_Trap_Init
49 public EnableA20
50 public DisableA20
51 public togl_A20
52 public get_a20_state
53 public estb_a20_state
54 public get_init_a20_state
55
56
57 ;
58 ;******************************************************************************
59 ; E X T E R N A L R E F E R E N C E S
60 ;******************************************************************************
61 include VDMseg.inc
62 include VDMsel.inc
63 ;
64 _DATA segment
65 ; (none)
66 _DATA ends
67
68 _TEXT segment
69
70 extrn PortTrap:near
71
72 _TEXT ends
73 page
74 ;******************************************************************************
75 ; L O C A L C O N S T A N T S
76 ;******************************************************************************
77 ;
78 FALSE equ 0
79 TRUE equ not FALSE
80
81 YesLLdone equ 1
82 KbdDataEnb equ 2
83
84 A20CmdBit equ 02h ; high is enabled
85 A20DsbCmd equ 0DDh
86 A20EnbCmd equ 0DFh
87
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
93
94 ; equates for the state_a20 flag
95
96 A20_ON equ A20CmdBit ;
97 A20_OFF equ 0 ;
98 ;
99 ; equate for the bit which will toggle the state of
100 ;
101 WRAP_BIT equ 00100000h ; page table entry bit
102 ;
103 ;******************************************************************************
104 ; S E G M E N T D E F I N I T I O N
105 ;******************************************************************************
106 ;
107
108 ;
109 ; _DATA segment
110 ;
111 _DATA segment
112
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
115
116 _DATA ends
117
118 ;
119 page
120 ;------------------------------------------------------------------------------
121 _TEXT segment
122 assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP
123 ;
124 ;******************************************************************************
125 ; L O C A L D A T A A R E A
126 ;******************************************************************************
127 ;
128
129 ;******************************************************************************
130 ; A20_Handler - I/O trap handler for Address line 20 modification
131 ;
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
137 ; DS = DGROUP
138 ; SS:BP = points to stack frame on entry to GP fault handler
139 ;
140 ; EXIT:
141 ; CLC => I/O emulated.
142 ; STC => I/O NOT emulated.
143 ;
144 ; USED: BX,Flags
145 ; STACK:
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
151 ret
152 A20_Write:
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
156
157 ; keyboard data write
158 Kbd_D_Dwrite:
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
163 ret
164 ;
165 ; here if Output Port write
166 ;
167 Kbd_D_out:
168 push ax ; Set A20 cmd bit
169 call check_a20_togl ; do we need to toggle the
170 ; the a20 state
171 jz skip_togl ; N: Skip routine to toggle
172 call togl_a20
173 skip_togl:
174 or al, A20CmdBit ; to leave A20 enabled
175 out KbdDataPort,al ; "emulate" it
176 pop ax ; restore client's byte
177 clc ; emulated
178 ret
179
180 ;Output to Keyboard command port
181 Kbd_C_Handler:
182 ;
183 mov [KbdComd],al ; Y: save new port 64 byte
184 stc ; don't bother to emulate it
185 ret
186 ;
187 A20_Handler endp
188
189
190 ;******************************************************************************
191 ; A20_Trap_Init - turn on I/O bit map trapping for A20 line watching
192 ;
193 ; ENTRY: DS -> DGROUP - real,virtual, or protected mode
194 ; ES -> TSS segment
195 ; IOTrap_Tab already has address of A20_Handler for KbdDataPort and
196 ; KbdCmdPort
197 ;
198 ; EXIT: IO_BitMap Updated to trap ports used to change A20 line
199 ;
200 ; USED: AX,Flags
201 ; STACK:
202 ;------------------------------------------------------------------------------
203 A20_Trap_Init proc near
204 ;
205 ; reset flag
206 ;
207 mov [KbdComd],0
208 ;
209 ; Set IOBM traps to look for client's disabling of the A20 line
210 ;
211 mov bh, 80h ; set every 1k
212 mov ax, KbdDataPort
213 call PortTrap ; set traps on keyboard ports
214 mov ax, KbdCmdPort ; in case client
215 call PortTrap ; tries to disable A20
216 ret
217 ;
218 A20_Trap_Init endp
219 ;
220 ;*****************************************************************************;
221 ;*** EnableA20 - switch 20th address line ;
222 ; ;
223 ; This routine is used to enable the 20th address line in ;
224 ; the system. ;
225 ; ;
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 ;
231 ; the A20 line. ;
232 ; ;
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. ;
238 ; ;
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. ;
241 ; ;
242 ; ENTRY none ;ds = DGROUP ;
243 ; EXIT A20 line enabled ;
244 ; USES ax, flags modified ;
245 ; ;
246 ; WARNING: ;
247 ; ;
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. ;
252 ; ;
253 ; TO BE ADDED: ;
254 ; ;
255 ; 8042 error handling ;
256 ;*****************************************************************************;
257 EnableA20 proc near
258 mov ah,0dfh ; code for enable
259 jmp a20common ; jump to common code
260
261 EnableA20 endp
262
263 ;*****************************************************************************;
264 ;*** DisableA20 - switch 20th address line ;
265 ; ;
266 ; This routine is used to disable the 20th address line in ;
267 ; the system. ;
268 ; ;
269 ; ENTRY none ;ds = DATA ;
270 ; EXIT A20 line disabled ;
271 ; [state_a20] = 0 ;
272 ; USES ax, flags modified ;
273 ;*****************************************************************************;
274
275 DisableA20 proc near
276 mov ah,0ddh ; code for disable
277 jmp a20common ; jump to common code
278
279 DisableA20 endp
280
281
282 a20common proc near
283
284 ; This is entered via a jmp from one of the two procedural
285 ; entry points above.
286
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
295 call empty_8042
296 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
297 ;
298 ; AST P/386 needs the delay for their
299 ; A20 switch settle. If not, it won't work !
300 ; PC (10/03/88)
301 ;
302 push cx
303 mov cx, 0100h
304 ASTloop:
305 loop ASTloop
306 pop cx
307 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
308
309 com1:
310 ret
311 a20common endp
312
313 ;*****************************************************************************;
314 ;*** empty_8042 - wait for 8042 input buffer to drain ;
315 ; ;
316 ; ENTRY none ;
317 ; EXIT al=0, z=0 => 8042 input buffer empty ;
318 ; al=2, z=1 => timeout, input buffer full ;
319 ; USES none ;
320 ;*****************************************************************************;
321 empty_8042 proc near
322 push cx ; save it
323 sub cx,cx ; cx = 0, timeout loop counter
324 emp1:
325 in al,KbdStatusPort ; read 8042 status port
326 and al,KbdBufFull ; test buffer full bit
327 loopnz emp1
328 pop cx
329 ret
330 empty_8042 endp
331
332 ;*****************************************************************************;
333 ;*** check_a20_togl - check if a20 state emulated needs to be toggled ;
334 ; ;
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 ;
339 ; USES Flags ;
340 ; ;
341 ;*****************************************************************************;
342 check_a20_togl proc near
343 ;
344 push ax
345 and al,A20CmdBit ; make all other bits 0
346 xor al,[state_a20] ; does the state of the a20 bit match
347 ; Y: then Z is set
348 ; N: then Z is not set
349 pop ax
350 ret
351 ;
352 check_a20_togl endp
353
354
355 ;*****************************************************************************;
356 ;*** get_a20_state - see if virtualised a20 is enabled or not ;
357 ; ;
358 ; ENTRY [state_a20] = A20 emulated state ;
359 ; ;
360 ; EXIT ZF set if A20 disabled ;
361 ; ZF not set if A20 enabled ;
362 ; ;
363 ; USES Flags ;
364 ;*****************************************************************************;
365
366 get_a20_state proc near
367 ;
368 test [state_a20], A20_ON
369 ret
370 get_a20_state endp
371
372
373 ;*****************************************************************************;
374 ;*** togl_A20 - toggle emulated A20 state. ;
375 ; ;
376 ; ENTRY [state_a20] = A20 emulated state ;
377 ; PROTECTED MODE ONLY ;
378 ; DS:DGROUP ;
379 ; ;
380 ; EXIT [state_a20] toggled ;
381 ; page table entries for the 1M --> 1M + 64k area toggled ;
382 ; ;
383 ; USES Flags ;
384 ; ;
385 ; ;
386 ;*****************************************************************************;
387 togl_A20 proc near
388 ;
389 push es
390 push di
391 push cx
392 push eax
393 ;
394 ; get addressability to page table
395 ;
396 push PAGET_GSEL
397 pop es
398 ;
399 ; and offset into entries for the 64k block at 1M
400 ;
401 mov di,100h*4 ; 1024k/4k = 256 entries, each 4 bytes long
402 mov cx,10h ; 64k/4k = 16 entries
403 cld
404 ;
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.
408 ;
409 w64_loop:
410 xor dword ptr es:[di], WRAP_BIT
411 add di,4
412 loop w64_loop
413 ;
414 ; flush the tlb
415 ;
416 mov eax,cr3
417 mov cr3,eax
418 ;
419 ; toggle a20 state
420 ;
421 xor [state_a20],A20_ON
422 ;
423 ; restore the registers
424 ;
425 pop eax
426 pop cx
427 pop di
428 pop es
429 ret
430 ;
431 togl_A20 endp
432
433
434
435 _TEXT ends ; end of segment
436
437 LAST segment
438
439 assume cs:LAST, ds:DGROUP, es:DGROUP, ss:DGROUP
440
441
442 ;******************************************************************************
443 ;***estb_a20_state ;
444 ; ;
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. ;
449 ; ;
450 ; INPUTS: ;
451 ; ;
452 ; OUTPUTS: [state_a20] .. A20_ON if a20 is on currently ;
453 ; .. A20_OFF if a20 is off currently ;
454 ; ;
455 ; USES: flags ;
456 ; ;
457 ; AUTHOR: ISP. Shifted in from smartdrv sources. 8/29/88. ;
458 ; ;
459 ;*****************************************************************************;
460 ; A20 address line state determination addresses
461 ;
462 low_mem label dword
463 dw 20h*4
464 dw 0
465
466 high_mem label dword
467 dw 20h*4 + 10h
468 dw 0ffffh
469
470 estb_a20_state proc near
471 push cx
472 push ds
473 push es
474 push si
475 push di
476 ;
477 ; initialise a20 to off
478 ;
479 mov [state_a20],A20_OFF
480 ;
481 ; compare 3 dwords at 0:80h and 1M:80h. if these are equal then
482 ; we can assume that a20 is off
483 ;
484 lds si,cs:low_mem
485 ASSUME DS:NOTHING
486 les di,cs:high_mem
487 ASSUME ES:NOTHING
488 mov cx,3
489 cld
490 repe cmpsd
491 pop di
492 pop si
493 pop es
494 pop ds
495 ASSUME DS:DGROUP,ES:DGROUP
496 jcxz not_enabled
497 ;
498 ; a20 is on
499 ;
500 mov [state_a20],A20_ON
501 not_enabled:
502 pop cx
503 ret
504 estb_a20_state endp
505
506 ;*****************************************************************************;
507 ;*** get_init_a20_state - see if virtualised a20 is enabled or not ;
508 ; ;
509 ; ENTRY [state_a20] = A20 state at startup ;
510 ; ;
511 ; EXIT ZF set if A20 disabled ;
512 ; ZF not set if A20 enabled ;
513 ; ;
514 ; USES Flags ;
515 ;*****************************************************************************;
516
517 ASSUME DS:DGROUP,ES:NOTHING
518
519 get_init_a20_state proc near
520 ;
521 test [state_a20], A20_ON
522 ret
523 get_init_a20_state endp
524
525 LAST ends
526
527 end ; end of module
528 \1a