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

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / MEMM / MEMM / ELIMTRAP.ASM
1
2
3 ;******************************************************************************
4 title DMATRAP.ASM - Trap handlers for DMA ports
5 ;******************************************************************************
6 ;
7 ; (C) Copyright MICROSOFT Corp. 1986
8 ;
9 ; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
10 ;
11 ; Module: DMATRAP.ASM - Trap Handlers for DMA ports
12 ;
13 ; Version: 0.04
14 ;
15 ; Date: April 9, 1986
16 ;
17 ; Author:
18 ;
19 ;******************************************************************************
20 ;
21 ; Change log:
22 ;
23 ; DATE REVISION DESCRIPTION
24 ; -------- -------- -------------------------------------------------------
25 ; 04/09/86 Original
26 ; 06/18/86 0.01 Modified LIM_Map to handle all 4 boards and call
27 ; page mapping routine in EMMLIB.LIB
28 ; 06/27/86 0.02 Made _page_frame_address indexing dword (was word)
29 ;
30 ; 06/28/86 0.02 Name change from MEMM386 to MEMM
31 ; 07/01/86 0.03 Added DMA support routines
32 ; 07/02/86 0.03 Fixed CNT size vs. length problem
33 ; 07/06/86 0.04 Made _pft386 a ptr to _pft386 array
34 ; 07/06/86 0.04 now sets _window array also
35 ; 08/11/86 0.05 moved IO_Trap code for LIM DMA trapping here
36 ; 06/09/88 remove IOT_LIM, LIMMap, and InitELIM since we don't
37 ; have any EMM hardware to trap and emulate now (Paulch)
38 ; 07/26/88 reintroduced initelim removing iab port trap (ISP)
39 ;
40 ; 07/27/88 Started rewriting the DMA port trap handlers - similar to the
41 ; code in VDMAD.ASM in Win/386 V2.03
42 ; - Jaywant H Bharadwaj
43 ;
44 ;*****************************************************************************
45
46
47 ;******************************************************************************
48 ;
49 ; Functional Description:
50 ;
51 ; Monitors writes/reads to the DMA ports.
52 ; Reads are simple - return the value saved in DMARegSav structure.
53 ; On a write to Page/Base/count Reg port -
54 ; user specifies a linear address. DMAs can handle only physical addresses.
55 ; Therefore, the actual physical address has to be written into the Page and
56 ; base Address Reg. Also the DMA transfer area may not be physically contiguous.
57 ; If it isn't we should remap the linear address so that it is physically
58 ; contiguous.
59 ;
60 ; We never know when a DMA is started. Hence on every access to the Page/Base
61 ; or count Register we make sure that the linear address specified by the user
62 ; maps to a physical address which is contiguous over the DMA transfer area.
63 ; This has to be done even if the count register is altered since the user
64 ; might be relying on the previous contents of Page/Addr Regs which may not be
65 ; contiguous anymore.
66 ;
67 ; All routines except InitDMA are entered through protected mode only.
68 ;
69 ;******************************************************************************
70
71 .lfcond ; list false conditionals
72 .386p
73
74 page
75 ;******************************************************************************
76 ; P U B L I C D E C L A R A T I O N S
77 ;******************************************************************************
78
79 ;
80 ; routines called from C
81 ;
82 public _GetPte
83 public _SetPte
84 public _GetCRSEntry
85 public _GetDMALinAdr
86 public _Exchange16K
87 public _FatalError
88
89 public InitELIM ; initialization routine for LIMulator
90 public InitDMA ; init DMA register save area
91 public DMARegSav
92 public _DMA_Pages
93 public DMA_Pages
94 public _DMA_PAGE_COUNT
95 public DMA_PAGE_COUNT
96
97
98
99 public DMA_DMAFixup
100 public DMABase0
101 public DMABase1
102 public DMABase2
103 public DMABase3
104 public DMABase5
105 public DMABase6
106 public DMABase7
107
108 public DMACnt0
109 public DMACnt1
110 public DMACnt2
111 public DMACnt3
112 public DMACnt5
113 public DMACnt6
114 public DMACnt7
115 public DMAPg0
116 public DMAPg1
117 public DMAPg2
118 public DMAPg3
119 public DMAPg5
120 public DMAPg6
121 public DMAPg7
122 public DMAClrFF1
123 public DMAClrFF2
124 public DMAMode1
125 public DMAMode2
126
127
128 page
129 ;******************************************************************************
130 ; L O C A L C O N S T A N T S
131 ;******************************************************************************
132 ;
133 include VDMseg.inc
134 include VDMsel.inc
135 include desc.inc
136 include elim.inc
137 include mach_id.inc
138 include page.inc
139 include oemdep.inc
140 include instr386.inc
141 include vm386.inc
142 include emmdef.inc
143
144 ;******************************************************************************
145 ;
146 ; Get_FRS_window - get pointer to Fast Register Set window
147 ;
148 ; ENTRY: Reg - points to an FRS_struc
149 ;
150 ; EXIT: Reg - points to FRS_window entry in the structure
151 ;
152 ; USES: Reg
153 ;
154 ;******************************************************************************
155 Get_FRS_window MACRO Reg
156
157 mov Reg, word ptr [CurRegSet] ; just offset (assume dgroup)
158 add Reg, FRS_window ; points to FRS window entries
159 ENDM
160
161 ;****************************************************************************
162 ;
163 ; InitDMARegSav - MACRO for initialising save area for channels
164 ;
165 ; ENTRY: chan_num = channel number (1,2,3,5,6,7)
166 ; ES -> DGROUP
167 ;
168 ;-----------------------------------------------------------------------------
169
170 InitDMARegSav MACRO chan_num
171
172 lea di,[DMARegSav.Chnl&chan_num] ; pt to channel's save area
173
174 xor eax, eax
175 in al,DMA_P&chan_num ; page register for channel
176 jmp $+2
177 jmp $+2 ; timing
178 shl eax,16 ; high EAX = high word of linear addr
179
180 ; flip-flop already reset by the caller
181
182 in al,DMA_B&chan_num ; get low byte of base
183 jmp $+2
184 jmp $+2 ; timing
185 mov ah,al
186 in al,DMA_B&chan_num ; get high byte of base
187 xchg ah,al
188 ; EAX = LINEAR BASE address
189
190 stosd ; store LINEAR BASE address
191
192 stosd ; store PHYSICAL BASE address
193
194 xor eax, eax ; clear EAX
195 jmp $+2
196 jmp $+2 ; timing
197 in al,DMA_C&chan_num ; get low byte of count
198 jmp $+2
199 jmp $+2 ; timing
200 mov ah,al
201 in al,DMA_C&chan_num ; get high byte of count
202 xchg ah,al
203 ; EAX = count
204
205 stosd ; store count
206
207 add di, 4 ; skip 4 bytes - 3 ports+mode byte
208
209 ENDM
210
211
212 ;******************************************************************************
213 ; DMA_WADDR_TO_BADDR - convert internal DMA word address to a byte address
214 ;
215 ; ENTRY: 386 PROTECTED MODE
216 ; DS -> DGROUP
217 ; ES -> DGROUP
218 ; EAX - Word Address
219 ;
220 ; EXIT: EAX - Byte address
221 ;
222 ; USED:
223 ;------------------------------------------------------------------------------
224 DMA_WADDR_TO_BADDR MACRO
225 LOCAL Not_AT
226
227 cmp [ROM_BIOS_Machine_ID], RBMI_Sys80
228 jbe short Not_AT ; If running on EBIOS machine
229
230 ror eax,16 ; AX = high word
231 shr al,1 ; adjust for D0 null in page reg
232 rol eax,17 ; EAX = address w/ adjust for
233 ; 'A0' offset
234 Not_At:
235 shl ecx, 1 ; Adjust for word units
236 ENDM
237
238
239 ;******************************************************************************
240 ; DMA_BADDR_TO_WADDR - convert internal DMA byte address to a word address
241 ;
242 ; ENTRY: 386 PROTECTED MODE
243 ; DS -> DGROUP
244 ; ES -> DGROUP
245 ; EAX - Word Address
246 ;
247 ; EXIT: EAX - Byte address
248 ;
249 ; USED:
250 ;------------------------------------------------------------------------------
251 DMA_BADDR_TO_WADDR MACRO
252 LOCAL Not_AT
253
254 cmp [ROM_BIOS_Machine_ID], RBMI_Sys80
255 jbe short Not_AT ; If running on EBIOS machine
256
257 shr eax, 1 ; Adjust for implied 'A0'
258 push ax ; Save A16-A1
259 xor ax, ax
260 shl eax, 1 ; Adjust for unused Pg Reg D0
261 pop ax ; Restore A16-A1
262 Not_At:
263 ENDM
264
265 ;******************************************************************************
266 ; E X T E R N A L R E F E R E N C E S
267 ;******************************************************************************
268
269 _DATA segment
270 extrn ROM_BIOS_Machine_ID:byte
271 extrn _page_frame_base:word
272 extrn CurRegSet:word
273 extrn Page_Dir:word
274 SaveAL db ?
275 _DATA ends
276
277 _TEXT segment
278
279 extrn PortTrap:near ; set port bit in I/O bit Map
280 extrn MapLinear:near
281 extrn ErrHndlr:near
282 ;
283 ; Swap pages so that DMA Xfer area is physically contiguous.
284 ; defined in mapdma.c
285 ;
286 extrn _SwapDMAPages:near
287
288 _TEXT ends
289
290 ;******************************************************************************
291 ; S E G M E N T D E F I N I T I O N
292 ;******************************************************************************
293
294 _DATA segment
295
296 DMARegSav DMARegBuf <> ; DMA Register buffer
297
298 DMAP_Page label word
299 ; dw DMA_P0 ; DMA page registers
300 dw DMA_P1
301 dw DMA_P2
302 dw DMA_P3
303 dw DMA_P5
304 dw DMA_P6
305 dw DMA_P7
306 ; dw DMA_P4
307 ; dw DMA_P0+10h ; page regs mapped to here also
308 dw DMA_P1+10h
309 dw DMA_P2+10h
310 dw DMA_P3+10h
311 dw DMA_P5+10h
312 dw DMA_P6+10h
313 dw DMA_P7+10h
314 ; dw DMA_P4+10h
315 DMAP_Addr label word
316 ; dw DMA_B0 ; DMA base registers
317 dw DMA_B1
318 dw DMA_B2
319 dw DMA_B3
320 dw DMA_B5
321 dw DMA_B6
322 dw DMA_B7
323 DMAP_Count label word
324 ; dw DMA_C0 ; DMA count registers
325 dw DMA_C1
326 dw DMA_C2
327 dw DMA_C3
328 dw DMA_C5
329 dw DMA_C6
330 dw DMA_C7
331 dw DMA1_CLR_FF ; reset flip-flop commands
332 dw DMA2_CLR_FF
333 DMAP_Mode label word
334 dw DMA1_MODE
335 dw DMA2_MODE
336
337 LIMDMAP_CNT = ($ - DMAP_Page) / 2
338 ;
339 ; DMA_Pages - EMM Pages for DMA relocation. Each is an index into pft386.
340 ; To access actual entry in pft386 you need to multiply index by 4.
341 ; If eight contingous 16k EMM pages are not available - the unavailable
342 ; entries are left at NULL_PAGE.
343 ; This array should be initialized at boot time.
344 ;
345 _DMA_Pages LABEL WORD
346 DMA_Pages dw 8 dup (NULL_PAGE) ; null for start
347 _DMA_PAGE_COUNT LABEL WORD
348 DMA_PAGE_COUNT dw 0 ; number of above initialised
349
350
351 _DATA ends
352
353 page
354
355 ;------------------------------------------------------------------------------
356
357 _TEXT segment
358 assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP
359
360 ;******************************************************************************
361 ;
362 ; InitDMA - initialize internal values for DMA registers of each channel
363 ;
364 ; ENTRY: Real Mode
365 ; DS = DGROUP
366 ;
367 ; EXIT: Real Mode
368 ; DGROUP:[DMARegSav] = DMA register save area initialized
369 ;
370 ;------------------------------------------------------------------------------
371
372 InitDMA proc near
373
374 push eax
375 push di
376 push es
377
378 pushf
379 cli
380 cld
381
382 push ds
383 pop es ; ES = DGROUP
384
385 xor al,al
386 out DMA1_CLR_FF, al ; clear FF on first controller
387 mov [DMARegSav.DMAFF1], al ; reset S/W FF
388 jmp $+2
389 jmp $+2 ; timing
390 ;
391 ; initialize regs for channels 1,2,3
392 ;
393 InitDMARegSav 1
394 InitDMARegSav 2
395 InitDMARegSav 3
396
397 xor al,al
398 out DMA2_CLR_FF, al ; clear FF on second controller
399 mov [DMARegSav.DMAFF2], al ; reset S/W FF
400 jmp $+2
401 jmp $+2 ; timing
402 ;
403 ; initialize regs for channels 5,6,7
404 ;
405 InitDMARegSav 5
406 InitDMARegSav 6
407 InitDMARegSav 7
408
409 popf
410 pop es
411 pop di
412 pop eax
413 ret
414
415 InitDMA endp
416
417 ;******************************************************************************
418 ;
419 ; DMABase(0-7) - Write/Read DMA Channel N Base Register
420 ;
421 ; ENTRY:
422 ; AL = byte to output to port
423 ; BX = port * 2
424 ; DH = 0 => Emulate Input
425 ; <>0 => Emulate Output
426 ;
427 ; EXIT:
428 ; AL = emulated input/output value from port.
429 ; CLC => I/O emulated or performed
430 ;
431 ;------------------------------------------------------------------------------
432 DMABase0to7 proc near
433
434 DMABase4: ; I/O port C0h
435 DMABase5: ; I/O port C4h
436 DMABase6: ; I/O port C8h
437 DMABase7: ; I/O port CCh
438 push ax
439 push bx
440 push cx
441 push dx
442 push si
443 ;
444 ; Now, BX = port * 2 and DX = IO code
445 ; Code ported from Win/386 expects DX = port and BH = IO code
446 ;
447 xchg dx, bx
448 shr dx, 1
449 xchg bh,bl ; move IO code to bh
450
451 mov si, dx
452 sub si, 0B0h ; SI = Channel * 4
453 shl si, 2 ; SI = Channel * 16
454 mov bl, [DMARegSav.DMAFF2] ; get flip-flop
455 xor [DMARegSav.DMAFF2], 1 ; and toggle it
456 jmp short DMABaseN ;
457
458 DMABase0: ; I/O port 00h
459 DMABase1: ; I/O port 02h
460 DMABase2: ; I/O port 04h
461 DMABase3: ; I/O port 06h
462 push ax
463 push bx
464 push cx
465 push dx
466 push si
467 ;
468 ; Now, BX = port * 2 and DX = IO code
469 ; Code ported from Win/386 expects DX = port and BH = IO code
470 ;
471 xchg dx, bx
472 shr dx, 1
473 xchg bh,bl ; move IO code to bh
474
475 mov si, dx ; SI = Channel * 2
476 shl si, 3 ; SI = Channel * 16
477 mov bl, [DMARegSav.DMAFF1] ; get flip-flop
478 xor [DMARegSav.DMAFF1], 1 ; and toggle it
479
480 ;
481 ; FALL THROUGH!!!
482 ;
483
484 ;******************************************************************************
485 ;
486 ; DMABaseN - Write/Read DMA Channel N Base Register
487 ;
488 ; ENTRY: As above plus
489 ; SI = 16 * channel #
490 ;
491 ;------------------------------------------------------------------------------
492 DMABaseN:
493 and bl, 1 ; Look at bit0 only - safety
494
495 or bh,bh ;Q: Input ?
496 jz short Base_rd_port ; Y: do Read operation
497 ; N: save value "written"
498 mov [SaveAL], al ; save AL in Save area.
499 xor bh, bh ; Make BX = Flip Flop state
500 mov byte ptr DMARegSav.DMALinAdr[bx][si], al
501
502 in al, dx ; Just a Dummy I/O to
503 ; toggle the real flip-flop
504 ; to match DMAFF above
505 jmp $+2
506 jmp $+2
507 xor bl,1 ; and the s/w one
508
509 call DMA_DMAFixup ; Translate Lin to Phys
510 ; & Update DMARegSav
511 call DMA_WrtAdrReg ; emulate the write
512 jmp short DBExit
513
514 Base_rd_port:
515 in al, dx ; Toggle the real flop-flip
516 ;
517 ; bh is already zero, therefore BX = flip flop state
518 ;
519 mov al,byte ptr DMARegSav.DMALinAdr[bx][si]
520 mov [SaveAL], al
521 DBExit:
522 pop si
523 pop dx
524 pop cx
525 pop bx
526 pop ax
527 mov al, [SaveAL]
528 clc
529 ret
530
531 DMABase0to7 endp
532
533 page
534
535 ;******************************************************************************
536 ;
537 ; DMACnt(0-7) - Write/Read DMA Channel N Count Register
538 ;
539 ;ENTRY:
540 ; AL = byte to output to port.
541 ; BX = port * 2
542 ; DH = 0 => Emulate Input.
543 ; <>0 => Emulate Output.
544 ;
545 ;EXIT:
546 ; AL = emulated input/output value from port.
547 ; CLC => I/O emulated or performed
548 ;
549 ;------------------------------------------------------------------------------
550
551 DMACnt0to7 proc near
552
553 DMACnt4: ; I/O port C2h
554 DMACnt5: ; I/O port C6h
555 DMACnt6: ; I/O port CAh
556 DMACnt7: ; I/O port CEh
557 push ax
558 push bx
559 push cx
560 push dx
561 push si
562 ;
563 ; Now, BX = port * 2 and DX = IO code
564 ; Code ported from Win/386 expects DX = port and BH = IO code
565 ;
566 xchg dx, bx
567 shr dx, 1
568 xchg bh,bl ; move IO code to bh
569
570 mov si, dx
571 sub si, 0B2h ; SI = 4 * channel #
572 shl si, 2 ; si = 16 * channel #
573 mov bl, [DMARegSav.DMAFF2] ; get flip-flop
574 xor [DMARegSav.DMAFF2], 1 ; toggle our flip-flop
575 jmp short DMACntN
576
577 DMACnt0: ; I/O port 01h
578 DMACnt1: ; I/O port 03h
579 DMACnt2: ; I/O port 05h
580 DMACnt3: ; I/O port 07h
581 push ax
582 push bx
583 push cx
584 push dx
585 push si
586 ;
587 ; Now, BX = port * 2 and DX = IO code
588 ; Code ported from Win/386 expects DX = port and BH = IO code
589 ;
590 xchg dx, bx
591 shr dx, 1
592 xchg bh,bl ; move IO code to bh
593
594 mov si, dx
595 dec si
596 shl si, 3 ; si = 16 * channel #
597 mov bl, [DMARegSav.DMAFF1] ; get flip-flop
598 xor [DMARegSav.DMAFF1], 1 ; toggle our flip-flop
599 ;
600 ; FALL THROUGH!!!
601 ;
602
603 ;******************************************************************************
604 ;
605 ; DMACntN - Write/Read DMA Channel N Count Register
606 ;
607 ; ENTRY: As DMACnt1to7 plus
608 ; si = 16 * channel #
609 ;
610 ;------------------------------------------------------------------------------
611 DMACntN:
612 and bl, 1 ; Look at bit0 only - Safety
613
614 or bh,bh ;Q: Input ?
615 jz short DMA_CntN_rd ; Y: do Read operation
616 ; N: save value "written"
617 mov [SaveAL], al ; save AL in Save area.
618 xor bh, bh ; make BX = Flip Flop state
619 mov byte ptr DMARegSav.DMACount[bx][si], al ; save cnt
620 out dx, al ; do the I/O
621
622 xor bl,1 ; Toggle flip-flop for Wrt
623 call DMA_DMAFixup ; Translate Lin to Phys
624 ; & Update DMARegSav
625 call DMA_WrtAdrReg ; emulate the write
626 call DMALoadCount
627
628 jmp short DCExit
629 DMA_CntN_rd:
630 xor bh,bh ; make BX = Flip Flop state
631 in al, dx ; Toggle the real flip-flop
632 ; to match bx above
633 mov [SaveAL], al
634
635 jmp $+2
636 jmp $+2
637 xor bl,1 ; and the s/w one
638 ;
639 ; get current count values from cntlr
640 ;
641 in al, dx ; get 2nd byte of Count reg
642 jmp $+2 ; timing ...
643 jmp $+2 ; timing ...
644 mov byte ptr DMARegSav.DMACount[bx][si], al ; save it
645 xor bl, 1 ; flip to other byte
646 in al, dx ; get 1st byte of Count reg
647 mov byte ptr DMARegSav.DMACount[bx][si], al ; save it
648 DCExit:
649 pop si
650 pop dx
651 pop cx
652 pop bx
653 pop ax
654 mov al, [SaveAL]
655
656 clc ; I/O emulated, return
657 ret
658
659 DMACnt0to7 endp
660
661 page
662 ;******************************************************************************
663 ;
664 ; DMAPgN - Write/Read DMA Channel N Page Register
665 ;
666 ; ENTRY:
667 ; AL = byte to output to port
668 ; BX = port * 2
669 ; DX = 0 => Emulate Input
670 ; <>0 => Emulate Output
671 ; si = 2 * Channel #
672 ;
673 ; EXIT:
674 ; AL = emulated input/output value from port.
675 ; CLC => I/O emulated or performed
676 ;
677 ; USED: EBX,Flags
678 ; STACK:
679 ;
680 ; NOTES: For channels 0-4, DMACount is in Bytes, and
681 ; DMALinAdr holds the address as:
682 ;
683 ; +-----------+-----------+----------------------+
684 ; | 31-24 | 23-16 | 15-0 |
685 ; +-----------+-----------+----------------------+
686 ; | 0000 0000 | A23-A16 | A15-A0 |
687 ; +-----------+-----------+----------------------+
688 ;
689 ; For channels 5-7, DMACount is in Words, and
690 ; DMALinAdr holds the address as:
691 ;
692 ; +-----------+-----------+----------------------+
693 ; | 31-24 |23-17 | 16 | 15-0 |
694 ; +-----------+-----------+----------------------+
695 ; | 0000 0000 |A23-A17 |0 | A16-A1 |
696 ; +-----------+-----------+----------------------+
697 ;
698 ;
699 ;------------------------------------------------------------------------------
700 DMAPg0to7 proc near
701
702 DMAPg0:
703 push si
704 mov si,0*16 ; si = 16 * channel #
705 jmp short DMAPgN
706 DMAPg1:
707 push si
708 mov si,1*16 ; si = 16 * channel #
709 jmp short DMAPgN
710 DMAPg2:
711 push si
712 mov si,2*16 ; si = 16 * channel #
713 jmp short DMAPgN
714 DMAPg3:
715 push si
716 mov si,3*16 ; si = 16 * channel #
717 jmp short DMAPgN
718 DMAPg5:
719 push si
720 mov si,5*16 ; si = 16 * channel #
721 jmp short DMAPgN
722 DMAPg6:
723 push si
724 mov si,6*16 ; si = 16 * channel #
725 jmp short DMAPgN
726 DMAPg7:
727 push si
728 mov si,7*16 ; si = 16 * channel #
729 ; FALL THROUGH
730
731 ;----------------------------------------------------------------------
732 ; DMAPgN - Common Page Code
733 ;
734 ; ENTRY: As above plus
735 ; si = 16 * Channel #
736 ;
737 ;----------------------------------------------------------------------
738
739 DMAPgN:
740 push ax
741 push bx
742 push cx
743 push dx
744 ;
745 ; Now, BX = port * 2 and DX = IO code
746 ; Code ported from Win/386 expects DX = port and BH = IO code
747 ;
748 xchg dx, bx
749 shr dx, 1
750 xchg bh,bl ; move IO code to bh
751
752 or bh,bh ;Q: Input ?
753 jz short Pg_rd_port ; Y: do Read operation
754
755 mov [SaveAL], al ; save AL in Save area.
756 ;
757 ; Get s/w FF for WrtAdrReg
758 ;
759 mov bl, [DMARegSav.DMAFF1] ; Assume Chan 1 FF
760 cmp si, 4*16 ; Q: Addr for 2nd controller
761 jb short PgN_FF ; A: No, FF is correct
762 mov bl, [DMARegSav.DMAFF2] ; Chan 2 FF
763 PgN_FF:
764 xor bh, bh ; make BX = flip-flop state
765
766 mov byte ptr DMARegSav.DMALinAdr.HighWord[si], al ; save value
767 call DMA_DMAFixup ; Translate Lin to Phys
768 ; & Update DMARegSav
769 call DMA_WrtAdrReg ; emulate the write
770 jmp short DPExit
771 Pg_rd_port:
772 mov al, byte ptr DMARegSav.DMALinAdr.HighWord[si]
773 mov [SaveAL], al
774 DPExit:
775 pop dx
776 pop cx
777 pop bx
778 pop ax
779 pop si
780 mov al, [SaveAL]
781 clc
782 ret
783
784 DMAPg0to7 endp
785
786 page
787
788 ;******************************************************************************
789 ;
790 ; DMAClrFF1 - Reset Controller 1's FlipFlop
791 ; DMAClrFF2 - Reset Controller 2's FlipFlop
792 ;
793 ; ENTRY:
794 ; AL = byte to output to port.
795 ; BX = port * 2
796 ; DH = 0 => Emulate Input.
797 ; <>0 => Emulate Output.
798 ;
799 ; EXIT:
800 ; AL = emulated input/output value from port.
801 ; CLC => I/O emulated or performed
802 ;
803 ;------------------------------------------------------------------------------
804
805 DMAClrFF1 proc near
806 push ax
807 push bx
808 push cx
809 push dx
810 ;
811 ; Now, BX = port * 2 and DX = IO code
812 ; Code ported from Win/386 expects DX = port and BH = IO code
813 ;
814 xchg bx, dx
815 shr dx, 1
816 xchg bh,bl ; move IO code to bh
817
818 or bh,bh ;Q: Input ?
819 jz short DMA_CLF_RdEm ; Y: Let it go
820 out dx, al ; N: do it
821 mov [DMARegSav.DMAFF1], 0
822 jmp short DMACFFexit
823 DMA_CLF_RdEm:
824 in al,dx ; do the read
825 DMACFFexit:
826 pop dx
827 pop cx
828 pop bx
829 pop ax
830 clc
831 ret
832
833 DMAClrFF1 endp
834
835 DMAClrFF2 proc near
836
837 push ax
838 push bx
839 push cx
840 push dx
841 ;
842 ; Now, BX = port * 2 and DX = IO code
843 ; Code ported from Win/386 expects DX = port and BH = IO code
844 ;
845 xchg bx, dx
846 shr dx, 1
847 xchg bh,bl ; move IO code to bh
848
849 or bh,bh ;Q: Input ?
850 jz DMA_CLF_RdEm ; Y: Let it go
851 out dx, al ; N: do it
852 mov [DMARegSav.DMAFF2], 0
853 jmp DMACFFexit
854
855 DMAClrFF2 endp
856
857 page
858 ;******************************************************************************
859 ;
860 ; DMAMode1 - Track Controller 1's Mode Register
861 ; DMAMode2 - Track Controller 2's Mode Register
862 ;
863 ; ENTRY:
864 ; AL = byte to output to port.
865 ; BX = port * 2
866 ; DX = 0 => Emulate Input.
867 ; <>0 => Emulate Output.
868 ;
869 ; EXIT:
870 ; AL = emulated input/output value from port.
871 ; CLC => I/O emulated or performed
872 ;
873 ;------------------------------------------------------------------------------
874
875 DMAMode1 proc near
876 push ax
877 push bx
878 push cx
879 push dx
880 push si
881 ;
882 ; Now, BX = port * 2 and DX = IO code
883 ; Code ported from Win/386 expects DX = port and BH = IO code
884 ;
885 xchg bx, dx
886 shr dx, 1
887 xchg bh,bl ; move IO code to bh
888
889 or bh,bh ;Q: Input ?
890 jz short DMA_Mread ; Y: Let it go
891
892 mov [SaveAL], al ; save AL in Save area.
893 xor ah, ah
894 mov si, ax
895 and si, DMA_M_CHANNEL
896 mov bl, al
897 and bl, NOT DMA_M_16BIT ; 8 bit xfers for controller 1
898 DMA_Mboth:
899 shl si, 4 ; Channel * 16
900 mov [DMARegSav.DMAMode][si], bl
901 out dx, al ; N: do it
902 jmp short DMExit
903
904 DMA_Mread:
905 in al, dx ; do the read
906 mov [SaveAL], al
907 DMExit:
908 pop si
909 pop dx
910 pop cx
911 pop bx
912 pop ax
913 mov al, [SaveAL]
914 clc
915 ret
916 DMAMode1 endp
917
918 DMAMode2 proc near
919
920 push ax
921 push bx
922 push cx
923 push dx
924 push si
925 ;
926 ; Now, BX = port * 2 and DX = IO code
927 ; Code ported from Win/386 expects DX = port and BH = IO code
928 ;
929 xchg bx, dx
930 shr dx, 1
931 xchg bh,bl ; move IO code to bh
932
933 or bh,bh ;Q: Input ?
934 jz DMA_Mread ; Y: Let it go
935
936 mov [SaveAL], al ; save AL in Save area.
937 xor ah, ah
938 mov si, ax
939 and si, DMA_M_CHANNEL
940 add si, 4 ; Channel 4 to 7
941 mov bl, al
942 or bl, DMA_M_16BIT ; 16 bit for controller 2
943 jmp DMA_Mboth
944
945 DMAMode2 endp
946
947 ; INCLUDE VDMAD2.ASM
948
949 page
950 ;******************************************************************************
951 ;DMA_GetLinAdr - return Linear Address, count and mode from DMARegSave area
952 ;
953 ; ENTRY:
954 ; si = channel # * 16
955 ; DS assume DGROUP
956 ;
957 ; EXIT:
958 ; EAX = linear Base Address
959 ; ECX = SIZE of transfer (bytes)
960 ; DL = Mode register
961 ;
962 ; USED: Flags
963 ; STACK:
964 ;------------------------------------------------------------------------------
965 DMA_GetLinAdr proc near
966
967 mov eax, dword ptr DMARegSav.DMALinAdr[si]
968 mov ecx, dword ptr DMARegSav.DMACount[si]
969 mov dl, byte ptr DMARegSav.DMAMode[si]
970 inc ecx ; ECX = SIZE of transfer
971 test dl, DMA_M_16BIT ; Word transfer?
972 jz short GLexit ; N: no special treatment
973
974 DMA_WADDR_TO_BADDR ; Y: fixup values from regs
975 GLexit:
976 ret
977
978 DMA_GetLinAdr endp
979
980 page
981 ;******************************************************************************
982 ; DMA_SetPhyAdr - Load the Page and Base DMA registers with the input
983 ; Physical Address and save this addr as current phy addr.
984 ;
985 ; ENTRY:
986 ; EAX = physical address
987 ; SI = DMA channel # * 16
988 ; DS -> DGROUP
989 ;
990 ; USED: Flags
991 ;------------------------------------------------------------------------------
992 DMA_SetPhyAdr proc near
993 ;
994 push eax
995 push bx
996 push dx
997
998 xor bh, bh
999 mov bl, [DMARegSav.DMAFF1]
1000 cmp si,4*16 ; 2nd cntlr?
1001 jb short DMA_SPA1
1002 mov bl, [DMARegSav.DMAFF2] ; yes, other flip-flop
1003 DMA_SPA1:
1004 test [DMARegSav.DMAMode][si], DMA_M_16BIT ; word transfer?
1005 jz short SaveIt ; no, no translation
1006 DMA_BADDR_TO_WADDR
1007 SaveIt:
1008 mov dword ptr DMARegSav.DMAPhyAdr[si], eax
1009
1010 ; set page register
1011 xor dh, dh
1012 mov dl, byte ptr DMARegSav.DMAPagePort[si]
1013 mov al, byte ptr DMARegSav.DMAPhyAdr.HighWord[si]
1014 out dx, al
1015
1016 ; set base address register
1017 mov dl, byte ptr DMARegSav.DMABasePort[si]
1018 mov al, byte ptr DMARegSav.DMAPhyAdr[si][bx]
1019 out dx,al ; send out 1st byte
1020 xor bl,1 ; toggle FF
1021 jmp $+2
1022 jmp $+2
1023 mov al, byte ptr DMARegSav.DMAPhyAdr[si][bx]
1024 out dx,al ; send out other byte
1025 xor bl,1 ; toggle FF to original state
1026
1027 pop dx
1028 pop bx
1029 pop eax
1030 ret
1031 ;
1032 DMA_SetPhyAdr endp
1033
1034 page
1035 ;******************************************************************************
1036 ; DMALoadCount - Load the Count DMA register with the input
1037 ;
1038 ; ENTRY:
1039 ; si = DMA channel # * 16
1040 ;
1041 ;------------------------------------------------------------------------------
1042 DMALoadCount proc near
1043 push bx
1044 push ax
1045 push dx
1046
1047 xor bh, bh
1048 mov bl, byte ptr [DMARegSav.DMAFF1]
1049 cmp si,4*16 ;Q: Adrs from 2nd cntlr
1050 jb short DMA_SC1 ; N: save it as is
1051 mov bl, byte ptr [DMARegSav.DMAFF2]
1052
1053 DMA_SC1:
1054 mov dl, byte ptr DMARegSav.DMACntPort[si]
1055 xor dh, dh
1056 mov al, byte ptr DMARegSav.DMACount[bx][si]
1057 out dx, al
1058 jmp $+2
1059 jmp $+2
1060 xor bl, 1
1061 mov al, byte ptr DMARegSav.DMACount[bx][si]
1062 out dx, al
1063
1064 pop dx
1065 pop ax
1066 pop bx
1067 ret
1068
1069 DMALoadCount endp
1070
1071 page
1072 ;******************************************************************************
1073 ; DMA_DMAFixup - Fixup Linear to Physical mapping for DMA
1074 ;
1075 ; ENTRY:
1076 ; SI = 16 * channel #
1077 ; DS assume DGROUP
1078 ;
1079 ; EXIT:
1080 ; DMARegSav is updated
1081 ;
1082 ; USED: flags, registers (calls a C program, so most registers are trashed)
1083 ;
1084 ; Check to see if DMA Page fixup is needed.
1085 ; We test for the following cases for optimization:
1086 ; Lin Base Add == Lin Page Reg == 0, assume that transfer addr
1087 ; is not yet valid
1088 ;
1089 ;------------------------------------------------------------------------------
1090 DMA_DMAFixup proc near
1091 ;Q: LinAddr = 0?
1092
1093 mov eax, dword ptr DMARegSav.DMALinAdr[si]
1094 or eax,eax
1095 jz short DMA_nofixup ; Y:DMA not programmed yet
1096 ;Do the fixup.....
1097 pushfd ; ENABLE INTERRUPTS!
1098 push bx ; C code trashes these regs
1099 push es
1100 ;
1101 ; long SwapDMAPages(LinAdr, Len, XferSize);
1102 ; long LinAdr, Len;
1103 ; unsigned XferSize; 0/1 Byte/word Xfer
1104 ;
1105 movzx eax, [DMARegSav.DMAMode][si]
1106 and al, DMA_M_16BIT ; Non-zero for 16bit transfer
1107 push ax ; push XferSize
1108
1109 call DMA_GetLinAdr
1110 push ecx ; push count
1111 push eax ; push LinAdr
1112 ;
1113 ; C code saves di si bp ds ss sp
1114
1115 call _SwapDMAPages ; C program to do the dirty work
1116
1117 xchg ax, dx
1118 shl eax, 16
1119 mov ax, dx ; eax = returned value
1120
1121 add sp, 10 ; clean up stack
1122
1123 pop es
1124 pop bx
1125 popfd ; Restore original FLAGS state
1126
1127 test [DMARegSav.DMAMode][si], DMA_M_16BIT ; word transfer?
1128 jz short SavIt ; no, no translation
1129 DMA_BADDR_TO_WADDR ; Y: Put in special format
1130 SavIt:
1131 mov dword ptr DMARegSav.DMAPhyAdr[si], eax
1132 clc ; Done fixup
1133 ret
1134 DMA_nofixup:
1135 stc
1136 ret
1137
1138 DMA_DMAFixup endp
1139
1140 page
1141 ;******************************************************************************
1142 ; DMA_WrtAdrReg - Write registers associated with DMA address
1143 ;
1144 ; ENTRY:
1145 ; BX = Flip Flop State, 0 or 1
1146 ; SI = channel # * 16
1147 ; DS assume DGROUP
1148 ; Uses Values in DMARegSav
1149 ;
1150 ; EXIT:
1151 ;
1152 ; USED: Flags, EAX
1153 ; STACK:
1154 ;------------------------------------------------------------------------------
1155 DMA_WrtAdrReg proc near
1156
1157 ; Must Update Page and Base registers simultaneously when remapping occurs...
1158 push bx
1159 push dx
1160
1161 and bx, 1 ; Lose extra bit just in case...
1162 ; Base Register...
1163 xor dh, dh ; clear high byte
1164
1165 ; NOTE: Internal flip-
1166 ; flop flag not updated,
1167 ; since we write twice....
1168 ; BX = flip flop state
1169
1170 mov dl, byte ptr DMARegSav.DMABasePort[si]
1171 mov al, byte ptr DMARegSav.DMAPhyAdr[bx][si]
1172 out dx, al ; output the byte
1173 jmp $+2 ; timing
1174 jmp $+2 ; timing
1175 xor bx, 1 ; toggle flip-flop
1176
1177 mov al, byte ptr DMARegSav.DMAPhyAdr[bx][si]
1178 out dx, al ; output the byte
1179 jmp $+2 ; timing
1180 jmp $+2 ; timing
1181 xor bx, 1 ; toggle flip-flop
1182
1183 ; Page Register...
1184 mov al, byte ptr DMARegSav.DMAPhyAdr.HighWord[si] ; fetch value
1185 mov dl, byte ptr DMARegSav.DMAPagePort[si]
1186 out dx,al ; output the byte
1187
1188 pop dx
1189 pop bx
1190 ret
1191
1192 DMA_WrtAdrReg endp
1193
1194 page
1195 ;******************************************************************************
1196 ; InitELIM - initialize LIM h/w trapping data structures and
1197 ; I/O bit map for this ports.
1198 ;
1199 ; NOTE: this is a FAR routine
1200 ;
1201 ; ENTRY: Real Mode
1202 ;
1203 ; EXIT: Real Mode
1204 ; TSS:[IOBitMap] - LIM addresses entered in I/O bit map
1205 ;
1206 ; USED: Flags
1207 ; STACK:
1208 ;------------------------------------------------------------------------------
1209 InitELIM proc far
1210
1211 push ax
1212 push bx
1213 push cx
1214 push si
1215 push di
1216 push ds
1217 push es
1218
1219 cld
1220
1221 mov ax,seg DGROUP
1222 mov ds,ax
1223 ;
1224 ; now set entries in I/O Bit Map
1225 ;
1226 mov ax,TSS
1227 mov es,ax ; ES -> TSS
1228 ;
1229 ; now set DMA ports in I/O Bit Map
1230 ;
1231 mov cx,LIMDMAP_CNT
1232 mov si,offset DGROUP:DMAP_Page ; DS:SI -> DMA ports
1233 mov bx,8000h ; trap it every 1k
1234 IE_maploop:
1235 lodsw ; AX = port to trap
1236 call PortTrap ; set bit(s) for this port
1237 loop IE_maploop ;if more ...
1238
1239 pop es
1240 pop ds
1241 pop di
1242 pop si
1243 pop cx
1244 pop bx
1245 pop ax
1246 ret
1247
1248 InitELIM endp
1249
1250
1251 ;
1252 ; C callable routines for manipulating page table entries.
1253 ; and Current FRS - CurRegSet
1254
1255
1256 ;
1257 ; Equates for picking up arguments passed in from C code.
1258 ; Arg1 - word Arg,
1259 ; Arg2 - word or dword Arg
1260 ;
1261
1262 Arg1 equ [BP+4]
1263 Arg2 equ [BP+6]
1264
1265
1266 ;*****************************************************************************
1267 ;
1268 ; _GetPte - called from C code
1269 ;
1270 ; return pte in dx:ax
1271 ;
1272 ; long GetPte(PTIndex)
1273 ; unsigned PTIndex;
1274 ;
1275 ; Written: JHB Aug 10,1988
1276 ; Modif: ISP Aug 12,1988 parameter should be returned in dx:ax not eax
1277 ; removed some of pushes and pops
1278 ; added cld before load just to be safe
1279 ; offset specified in DGROUP
1280 ;
1281 ; JHB Aug 21 88 changed input param to PTIndex
1282 ;
1283 ;*****************************************************************************
1284
1285 _GetPte proc near
1286
1287 push bp
1288 mov bp, sp
1289 push si
1290 push ds
1291
1292 mov ax, PAGET_GSEL
1293 mov ds, ax
1294
1295 mov si, WORD PTR Arg1
1296 shl si, 2 ; dword entries in the PT
1297
1298 cld
1299 lodsw ; get low word
1300 mov dx, ax ; into dx
1301 lodsw ; get hiword
1302 xchg dx, ax ; dx:ax = long return value
1303
1304 pop ds
1305 pop si
1306 pop bp
1307 ret
1308 _GetPte endp
1309
1310 ;*****************************************************************************
1311 ;
1312 ; _SetPte - called from C code
1313 ;
1314 ; Locate the PT entry for given EmmPhyPage and set it to pte.
1315 ;
1316 ; SetPte(PTIndex, pte)
1317 ; unsigned PTIndex;
1318 ; long pte;
1319 ;
1320 ; WRITTEN: JHB Aug 10,1988
1321 ; MODIF: ISP Aug 12,1988 pushes and pops removed
1322 ; cld added for safety
1323 ; offset specified in DGROUP
1324 ; pushed poped eax (check on this)
1325 ;
1326 ; JHB Aug 21, 1988 changed first input param to PTIndex
1327 ;
1328 ;*****************************************************************************
1329
1330
1331 _SetPte proc near
1332
1333 push bp
1334 mov bp, sp
1335 push di
1336 push es
1337
1338 mov ax, PAGET_GSEL
1339 mov es, ax
1340 mov di, WORD PTR Arg1
1341 shl di, 2
1342
1343 mov eax, DWORD PTR Arg2
1344 and ax, 0F000H ; clear low 12 bits
1345 or ax, P_AVAIL ; page control bits - user, present, write
1346
1347 cld
1348 stosd
1349 ;
1350 ; reload CR3 to flush TLB
1351 ;
1352 mov eax, CR3
1353 mov CR3, eax
1354
1355 ; mov eax,dword ptr [Page_Dir] ; mov EAX,dword ptr [Page_Dir]
1356 ; db 0Fh,22h,18h ; mov CR3,EAX
1357
1358 pop es
1359 pop di
1360 pop bp
1361 ret
1362 _SetPte endp
1363
1364 ;*****************************************************************************
1365 ;
1366 ; _GetCRSEntry - called from C code
1367 ;
1368 ; return the Emm page mapped to the EmmPhyPage by looking up CurRegSet.
1369 ;
1370 ; unsigned GetCRSEntry(EmmPhyPage)
1371 ; unsigned EmmPhyPage
1372 ;
1373 ; WRITTEN: JHB Aug 10,1988
1374 ; MODIF: ISP Aug 12,1988 pushes and pops removed
1375 ; Offset specified in DGROUP
1376 ; cld added for safety
1377 ;*****************************************************************************
1378
1379 _GetCRSEntry proc near
1380
1381 push bp
1382 mov bp, sp
1383 push di
1384
1385 mov bx, WORD PTR Arg1
1386 shl bx, 1 ; each FRS entry is a word
1387 Get_FRS_Window DI ; di = address of Current FRS
1388 add di, bx
1389 mov ax, word ptr [di] ; load FRS entry
1390
1391 pop di
1392 pop bp
1393 ret
1394 _GetCRSEntry endp
1395
1396 ;
1397 ; Equates for picking up long Arguments from C code
1398 ; LArg1 - long Arg
1399 ; Larg2 - long Arg when the first Arg is also long
1400 ;
1401
1402 LArg1 equ [BP+4]
1403 LArg2 equ [BP+8]
1404
1405 ;*****************************************************************************
1406 ;
1407 ; _GetDMALinAdr - called from C code
1408 ;
1409 ; returns the Lin Adr for the DMA buffer whose physical adr is given
1410 ;
1411 ; long GetDMALinAdr(DMAPhyAdr)
1412 ; long DMAPhyAdr;
1413 ;
1414 ; Get the Linear address for DMAPhyAdr. There is a pte which always
1415 ; maps to this always. MapLinear translates DMAPhyAdr to a linear adr.
1416 ;
1417 ;
1418 ; 8/12/88 JHB removed _Copy16K, changed it to this routine.
1419 ;
1420 ;*****************************************************************************
1421
1422 _GetDMALinAdr proc near
1423
1424 push bp
1425 mov bp, sp
1426 push si
1427 push di
1428 push ds
1429 ;
1430 ; convert the DMAPhyAdr into a linear address.
1431 ;
1432 mov eax, dword ptr LArg1
1433 call MapLinear
1434 ;
1435 ; eax = 32 bit linear adr for the DMA Xfer area.
1436 ;
1437 ror eax, 16
1438 mov dx, ax
1439 ror eax, 16 ; dx:ax 32 bit linear adr to be returned
1440
1441 pop ds
1442 pop di
1443 pop si
1444 pop bp
1445 ret
1446 _GetDMALinAdr endp
1447
1448 ;******************************************************************************
1449 ;
1450 ; set_selector - set up a selector address/attrib
1451 ;
1452 ; ENTRY: EAX = address for GDT selector - a linear address
1453 ; DI = GDT selector
1454 ; EXIT: selector in DI is writeable data segment,128k long and points
1455 ; to desired address.
1456 ;
1457 ;******************************************************************************
1458
1459 set_selector proc near
1460
1461 push eax
1462 push di
1463 push es
1464
1465 and di,NOT 07h ; just in case... GDT entry
1466 push GDTD_GSEL
1467 pop es ; ES:DI -> selector entry
1468
1469 mov es:[di+2],ax ; low word of base address
1470
1471 shr eax,16 ; AX = high word of address
1472 mov es:[di+4],al ; low byte of high word of address
1473 xor al,al ; clear limit/G bit
1474 or al, 1 ; set LSB0 i.e. Limit16 bit for 128K Xfer
1475 mov es:[di+6],ax ; set high byte of high word of addr
1476 ; and high nibble of limit/G bit
1477 ; and Limit Bit 16 for 128K transfer
1478 mov ax,0FFFFh
1479 mov es:[di],ax ; set limit bits 0-15
1480
1481 mov al,D_DATA0 ; writeable DATA seg / ring 0
1482 mov es:[di+5],al
1483
1484 pop es
1485 pop di
1486 pop eax
1487
1488 ret
1489
1490 set_selector endp
1491
1492 ;****************************************************************************
1493 ; _Exchange16K - called from C
1494 ;
1495 ; Exchange contents of the pages at LinAdr1 and LinAdr2
1496 ;
1497 ; Exchange16K(LinAdr1, LinAdr2)
1498 ; long LinAdr1, LinAdr2;
1499 ;
1500 ; Written: JHB Aug 11, 1988
1501 ; ISP Aug 12, 1988 Added cld.
1502 ; DWORD PTR mentioned explicitly
1503 ;*****************************************************************************
1504
1505 _Exchange16K proc near
1506
1507 push bp
1508 mov bp, sp
1509 push si
1510 push di
1511 push ds
1512
1513 mov di,MBSRC_GSEL ; source selector
1514 mov eax,dword ptr LArg1 ; load linear adr
1515 call set_selector ; set up a selector in GDT
1516 mov es,di
1517
1518 mov di,MBTAR_GSEL ; destination selector
1519 mov eax,dword ptr LArg2
1520 call set_selector ; set up selector
1521 mov ds,di
1522 mov cx,1000h ; 16k bytes (4 at a time)
1523 xor di,di ; initialize index
1524 cld
1525 sloop:
1526 mov eax,dword ptr es:[di] ; pick a dword at LArg1
1527 xchg eax,dword ptr ds:[di] ; swap with dword at LArg2
1528 stosd ; store new dword at LArg1
1529 loop sloop
1530
1531 pop ds
1532 pop di
1533 pop si
1534 pop bp
1535 ret
1536
1537 _Exchange16K endp
1538
1539 ;
1540 ; signals an exception error
1541 ;
1542 _FatalError proc near
1543
1544 push bp
1545 mov bp, sp
1546
1547 mov ax, 1
1548 mov bx, 3
1549 call ErrHndlr
1550
1551 pop bp
1552 ret
1553
1554 _FatalError endp
1555
1556 _TEXT ends ; end of segment
1557
1558 end ; end of module
1559
1560 \1a