summaryrefslogtreecommitdiff
path: root/v4.0/src/MEMM/EMM/EMMP.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/MEMM/EMM/EMMP.ASM')
-rw-r--r--v4.0/src/MEMM/EMM/EMMP.ASM2978
1 files changed, 2978 insertions, 0 deletions
diff --git a/v4.0/src/MEMM/EMM/EMMP.ASM b/v4.0/src/MEMM/EMM/EMMP.ASM
new file mode 100644
index 0000000..a60b46e
--- /dev/null
+++ b/v4.0/src/MEMM/EMM/EMMP.ASM
@@ -0,0 +1,2978 @@
1page 58,132
2;******************************************************************************
3 title EMMP - EMM protected mode functions
4;******************************************************************************
5;
6; (C) Copyright MICROSOFT Corp. 1986, 1987
7;
8; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver
9; EMMLIB.LIB - Expanded Memory Manager Functions Library
10;
11; Module: EMMP - WIN386 EMM functions
12;
13; Version: 0.04
14;
15; Date: July 7,1986
16;
17;******************************************************************************
18;
19; Change log:
20;
21; DATE REVISION DESCRIPTION
22; -------- -------- -------------------------------------------------------
23; 07/07/86 0.04 Moved here from version 0.04 EMMSUP.ASM
24; 07/08/86 0.04 Added Get/Set Page Map (SBP).
25; 05/13/88 Change to LIM 4.0 functionality (PC)
26;
27;******************************************************************************
28;
29; Functional Description:
30; This file contains the EMM functions which require greatest efficiency.
31;
32;******************************************************************************
33.lfcond ; list false conditionals
34.386p
35
36; include protseg.inc
37 include vdmseg.inc
38 include page.inc
39; include vdmm.inc
40 include vm386.inc
41 include vdmsel.inc
42 include emmdef.inc
43 include desc.inc
44; include vmdm.inc
45; include vpicd.inc
46; include vdmmmac.inc
47
48;******************************************************************************
49; P U B L I C S
50;******************************************************************************
51_TEXT segment
52 public _MapHandlePage
53 public _SavePageMap
54 public _RestorePageMap
55 public _GetSetPageMap
56 public _GetSetPartial
57 public _MapHandleArray
58 public _AlterMapAndJump
59 public _AlterMapAndCall
60; public TS_VEMMD_MC_Ret
61 public _MoveExchangeMemory
62 public _AlternateMapRegisterSet
63; public VEMMD_Set_Map_Region
64; public VEMMD_Unset_Map_Region
65; public _VMpte_to_EMMpte
66; public _Remap_EMM
67 public _Get_Key_Val
68_TEXT ends
69
70 page
71;******************************************************************************
72; E X T E R N A L R E F E R E N C E S
73;******************************************************************************
74
75_TEXT segment
76
77extrn _source_addr:near
78extrn _dest_addr:near
79
80extrn SetDescInfoResident:near
81extrn SegOffTo24Resident:near
82
83extrn ErrHndlr:near
84
85_TEXT ends
86
87_DATA SEGMENT
88
89;extrn _regp:dword ; pointer to entry stack frame
90;extrn VEMMD_pt:dword
91;extrn Cur_VM_Handle:dword
92;extrn Cur_VMID:dword
93;extrn _VM_List:dword
94;extrn _MaxEMMSize:dword
95;extrn _VEMMD_PgFrame:word
96;extrn _VEMMD_Last_Offset:word
97extrn PF_Base:word
98extrn _OSEnabled:dword
99;extrn NullAvailPTE:dword
100;extrn NullUnavailPTE:dword
101
102extrn _total_pages:word ; total # of EMM pages in system
103
104;
105; table of offsets into in to the first page table
106; for user logical emm page map
107;
108extrn _page_frame_base:dword
109
110extrn _pft386:word
111
112extrn _mappable_pages:word ; table of mappable pages
113extrn _mappable_page_count:word ; how many in the table
114extrn _page_frame_pages:word ; how many in the page frame
115extrn _physical_page_count:word ; number of physical pages
116extrn _VM1_EMM_Pages:word ; pages not in the page frame
117;extrn _VM1_EMM_Offset:word ; offset of these in a context
118extrn _cntxt_pages:byte ; number of pages in a context
119extrn _cntxt_bytes:byte ; number of bytes in a context
120
121
122;
123; table of indexes into the above - maps segment to physical page
124;
125extrn EMM_MPindex:byte
126
127;
128; ptr to table of emm page # for each handle's logical pages.
129;
130extrn _emm_page:word
131
132;
133; handle data structure
134;
135extrn _handle_table:word
136extrn _handle_table_size:word
137
138;
139; save area for handles
140;
141extrn _save_map:byte
142
143;
144; Save area and misc variables for 4.0 function 27
145;
146extrn EMM_savES:word
147extrn EMM_savDI:word
148
149extrn CurRegSetn:byte
150extrn FRS_free:byte
151extrn CurRegSet:dword
152extrn FRS_array:word
153
154extrn _regp:word
155_DATA ENDS
156
157 page
158;******************************************************************************
159; C O D E
160;******************************************************************************
161_TEXT SEGMENT
162assume cs:_TEXT, ds:DGROUP, ss:DGROUP
163
164 page
165;***********************************************
166;
167; normalize
168;
169; ENTRY: Sel,Off - Selector:offset to be normalize
170; protected mode only
171;
172; EXIT: Sel:Off normalized
173;
174; USES: Sel,Off
175; NOTE: Sel and Off should not be BX,DX,AX
176;
177;***********************************************
178normalize MACRO Sel,Off
179
180 push dx
181 push ax
182 push bx
183 push es
184
185 push Sel ; save for later reload
186 mov bx, Sel ; get Selector into BX
187
188 push GDTD_GSEL ; ES -> GDT
189 pop es
190
191 and bl,SEL_LOW_MASK ; mask off mode bits
192 mov dx,es:[bx+2] ; AL:DX <-- base address
193 mov al,es:[bx+4]
194 add dx,Off ; adjust base address
195 adc al,0
196 mov es:[bx+2],dx ; store it back
197 mov es:[bx+4],al
198 xor Off, Off ; new Offset
199
200 pop Sel ; reload Selector (flush cache)
201
202 pop es
203 pop bx
204 pop ax
205 pop dx
206
207 ENDM
208
209;***********************************************
210;
211; get_space_from_stack
212;
213; ENTRY: Len - amount of space requested
214;
215; EXIT: Len space allocated on ES:DI (client's stack)
216; ES:DI - points to First element on top of stack
217;
218; USES: DI
219;
220;***********************************************
221Get_space_from_stack MACRO Len
222
223 sub di, Len
224 ENDM
225
226;***********************************************
227;
228; release_space_to_stack
229;
230; ENTRY: Len - amount of space to be release
231;
232; EXIT: Len space released from client's stack (DS:SI)
233;
234; USES: SI
235;
236;***********************************************
237release_space_to_stack MACRO Len
238
239 add si, Len
240 ENDM
241
242;***********************************************
243;
244; Set_EMM_GDT - set GDT entry of selector with some fix infos
245; like access and limit
246;
247; ENTRY: Handle - selector of GDT to modify
248;
249; EXIT: GDT entry set
250; bx - selector
251;
252; USES: ax,bx,cx,dx,es
253;
254;***********************************************
255Set_EMM_GDT MACRO handle
256
257 mov bx, handle ; GDT selector
258 call SegOffTo24Resident ; AL:DX <-- 24 bit base address
259 mov cx, 0ffffh ; Limit
260 mov ah, D_DATA0 ; Acess right
261 push GDTD_GSEL
262 pop es ; ES:0 <-- GDT
263 call SetDescInfoResident ; set GDT entry
264 ENDM
265
266;***********************************************
267;
268; Set_Byte_Gran - set granularity of GDT entry to byte
269;
270; ENTRY: Handle - selector of GDT to modify
271;
272; EXIT: Granularity bit clear in GDT
273; bx - Selector
274;
275; USES: bx,es
276;
277;***********************************************
278Set_Byte_Gran MACRO handle
279
280 mov bx, handle ; GDT selector
281 push GDTD_GSEL
282 pop es ; ES:0 <-- GDT
283 and byte ptr es:[bx+6],NOT R_GRAN ; clear gran bit
284 ENDM
285
286;***********************************************
287;
288; Set_Page_Gran - set granularity of GDT entry to page
289;
290; ENTRY: Handle - selector of GDT to modify
291;
292; EXIT: Granularity bit set in GDT
293; bx - Selector
294;
295; USES: bx,es
296;
297;***********************************************
298Set_Page_Gran MACRO handle
299
300 mov bx, handle ; GDT selector
301 push GDTD_GSEL
302 pop es ; ES:0 <-- GDT
303 or byte ptr es:[bx+6], R_GRAN ; set gran bit
304 ENDM
305
306;***********************************************
307;
308; Get_FRS_window - get pointer to Fast Register Set window
309;
310; ENTRY: Reg - points to an FRS_struc
311;
312; EXIT: Reg - points to FRS_window entry in the structure
313;
314; USES: Reg
315;
316;***********************************************
317Get_FRS_window MACRO Reg
318
319 mov Reg, word ptr [CurRegSet] ; just offset (assume dgroup)
320 add Reg, FRS_window ; points to FRS window entries
321 ENDM
322
323 page
324;**********************************************************************
325;
326; map_EMM_page - set page table entries for a page frame
327;
328; ENTRY: AX - physical page number to be mapped
329; BX - EMM page number to map
330; EXIT: page table set up for EMM page # in this page frame
331; DESTROY:EAX,BX
332;
333;***********************************************
334map_EMM_page proc near
335 cmp ax,[_physical_page_count] ;Q: valid physical page# ?
336 jae short mEp_inv_page ; N: invalid page number
337 ; Y: continue with it
338 cmp bx,[_total_pages] ;Q: valid EMM page# ?
339 jae short mEp_inv_page ; N: invalid page number
340 ; Y: continue with it
341 push es ; preserve es
342 push cx ; preserve cx
343 push di ; preserve di
344 push ax ; save ax (phys page#)
345
346 ;
347 ; construct pointer to physical address of the first
348 ; 386 page and move it into eax
349 ;
350 mov cx,bx ; emm page# in cx to save in FRS later
351 shl bx,2 ; bx <-- pft index * 4
352
353 ;
354 ; continue calulation of pte
355 ;
356 add bx,[_pft386] ; BX = points into _pft386
357 mov eax,[bx] ; EAX = physical address of EMM page #
358 and ax,0F000H ; clear the low 12 bits
359 or ax,P_AVAIL ; page ctl bits <-- user,present,write
360
361 pop bx ; bx <-- physical page index
362
363 ;
364 ; save mapping (offset into _pft386 struct) into
365 ; current FRS's physical page entry
366 ;
367
368 Get_FRS_Window DI ; di <-- address of current FRS
369 add di,bx ; di <-- address of physical page
370 add di,bx ; entry in FRS
371 mov [di],cx ; save mapping (emm page#) into FRS
372 ;
373 ; construct pointer to physical address of
374 ; page frame
375 ;
376
377 shl bx,2 ; bx <-- index * 4
378 add bx,offset DGROUP:_page_frame_base ; bx = offset for entry in _page_frame_base
379 les di,[bx] ; es:di <-- page frame address
380
381 ;
382 ; now,
383 ; es:di points to the 1st entry in the page table
384 ; for this page frame
385 ; eax contains the new value of the PTE
386 ; set up 4 entries
387 ;
388
389 pushf ; preserve direction flag
390 cld ; forward
391
392 stosd ; store 1st page table entry
393 add eax,P_SIZE ; eax <-- next address
394
395 stosd ; store 2nd page table entry
396 add eax,P_SIZE ; eax <-- next address
397
398 stosd ; store 3rd page table entry
399 add eax,P_SIZE ; eax <-- next address
400
401 stosd ; store 4th page table entry
402
403 popf ; restore direction flag
404 pop di ; get DI back
405 pop cx ; get CX back
406 pop es ; get ES back
407 clc
408 ret
409
410mEp_inv_page:
411 stc
412 ret
413
414map_EMM_page endp
415
416 page
417;**********************************************************************
418;
419; unmap_page - unmap a physical page
420;
421; ENTRY: AX - physical page number to be unmapped
422; DESTROY:EAX
423;
424;**********************************************************************
425unmap_page proc near
426 ;
427 ; find FRS entry for the physical page and
428 ; update it as unmapped
429 ;
430 push es
431 push di
432 push bx
433 push cx
434 Get_FRS_Window DI ; di <-- address of current FRS
435 add di, ax ; di <-- address of physical page
436 add di, ax ; entry in FRS
437 mov [di], NULL_PAGE ; unmap the entry
438
439 ;
440 ; find out the segment of the physical page
441 ;
442 mov cx, [_physical_page_count]
443 mov di, offset DGROUP:_mappable_pages
444unmap_page_loop:
445 cmp ax, [di].mappable_pg
446 je unmap_page_found
447 add di, size Mappable_Page
448 loop unmap_page_loop
449
450 jmp short unmap_page_exit ; non-found : just return
451
452unmap_page_found:
453 mov bx, [di].mappable_seg ; get segment into bx first
454
455 ;
456 ; construct pointer to physical address of
457 ; page frame
458 ;
459 xchg ax,bx
460 shl bx,2 ; bx <-- index * 4
461 add bx,offset DGROUP:_page_frame_base ; bx <-- points to PTE address of phys page#
462 les di,[bx] ; es:di <-- points to PTE of page frame
463 xchg ax,bx
464
465 ;
466 ; construct PTE
467 ;
468 movzx eax, bx ; EAX <-- segment of physical page
469 shl eax, 4
470 and ax,0F000H ; clear the low 12 bits
471 or ax,P_AVAIL ; page ctl bits <-- user,present,write
472
473 cmp eax, 0A0000h ; Q:above 640K ?
474 jge unmap_page_ok ; Y: go ahead, unmap it
475 mov eax, 0 ; N: shouldn't unmap below 640K - make page NotPresent
476
477unmap_page_ok:
478 pushf
479 cld
480 stosd ; unmap pte of page frame
481 add eax,P_SIZE
482 stosd
483 add eax,P_SIZE
484 stosd
485 add eax,P_SIZE
486 stosd
487 popf
488
489unmap_page_exit:
490 pop cx
491 pop bx
492 pop di
493 pop es
494 ret
495unmap_page endp
496
497 page
498;**********************************************************************
499;
500; map_page - map a logical page to a phyical page
501;
502; ENTRY: AX - physical page number to be mapped
503; BX - logical page number to map
504; DX - handle pointer (do not destroy)
505; DESTROY:EAX,BX
506;
507;**********************************************************************
508map_page proc near
509 cmp ax,[_physical_page_count] ;Q: valid physical page# ?
510 jae short mp_inv_phy ; N: invalid page number
511 ; Y: continue with it
512 cmp bx,0FFFFh ;Q: unmap ?
513 je short mp_unmap_page ; Y: go ahead
514
515 xchg bx, dx
516 cmp dx,[bx.ht_count] ;Q: valid logical page# ?
517 xchg bx, dx
518 jae short mp_inv_log ; N: invalid page number
519 ; Y: continue with it
520
521 xchg bx, dx
522 add dx,[bx.ht_index] ; dx <-- index into _emm_page
523 xchg bx, dx
524 shl bx,1 ; bx <-- index * 2
525 add bx,[_emm_page]
526 mov bx,[bx] ; bx <-- emm page#
527 call map_EMM_page
528 jc short mp_inv_emm_page ; emm page range error
529 ret
530
531mp_unmap_page:
532 call unmap_page
533 clc
534 ret
535
536mp_inv_emm_page:
537 mov byte ptr [bp.rAX+1],SOURCE_CORRUPTED
538 stc
539 ret
540
541mp_inv_phy:
542 mov byte ptr [bp.rAX+1],PHYS_PAGE_RANGE
543 stc
544 ret
545
546mp_inv_log:
547 mov byte ptr [bp.rAX+1],LOG_PAGE_RANGE
548 stc
549 ret
550map_page endp
551
552
553 page
554;***********************************************
555;
556; _MapHandlePage - map a handle's page
557;
558; This routine maps 4 386 pages into the address
559; space.
560;
561; ENTRY: PROTECTED MODE ONLY
562; AH = 44h = map handle page function #
563; AL = window # (physical page #)
564; BX = logical page #
565; DX = EMM handle
566; REGS on STACK: SI = not used by this function
567; SS:[EBP] -> regp stack frame
568; DS = DGROUP
569;
570; EXIT: page table entries set up
571; AH = status of this function
572; = EMM_HW_MALFUNCTION if entry in real/virtual mode.
573;
574; USED: EAX, EBX, EDX, EDI
575;
576;***********************************************
577
578Dword_Align _TEXT
579_MapHandlePage proc near
580
581 Validate_Handle <short mhp_inv_handle>
582
583 mov byte ptr [bp.rAX+1],OK ; Assume success!
584 movzx eax, al ; Physical page
585 movzx ebx, bx ; Logical page
586
587 push eax
588 mov eax, cr3
589 mov cr3, eax ; Flush old mapping now
590 pop eax
591
592 jmp map_page ; Common page mapping code
593
594mhp_inv_handle:
595 mov byte ptr [bp.rAX+1], INVALID_HANDLE
596 ret
597
598_MapHandlePage endp
599
600 page
601;***********************************************
602;
603; _SavePageMap - save current page mapping
604;
605; This routine save the current page mapping context for a handle.
606;
607; ENTRY: PROTECTED MODE
608; AH = 07h = save page map function #
609; DX = EMM handle
610; REGS on STACK: SI = not used by this function
611; SS:[BP] -> regp stack frame
612; DS = DGROUP
613;
614; EXIT: current state saved
615; AH = status of this function
616;
617; USED: AX,BX,CX,DX,SI,DI
618;
619;***********************************************
620
621Dword_Align _TEXT
622_SavePageMap proc near
623 cmp [_page_frame_pages], 4
624 jb short srpm_nopf ; no page frame
625
626 mov ax, dx ; Save for later
627 Validate_Handle <short srpm_inv_handle>
628 ; check state of handle's page area
629 imul bx,ax,SIZE SaveMap_struc ; BX = offset within Save Area for
630 ; this handle's save area
631 lea di,_save_map[bx] ; DS:DI points to handle's save area
632 cmp [di].s_handle,NULL_HANDLE
633 ;Q: save area in use ?
634 jne short spm_prev_saved ; Y: return error
635 ; N: use it now
636 cld
637 push ds
638 pop es
639 stosw ; store handle # in s_handle
640 Get_FRS_window SI ; Current FRS page mappings
641 movsd ; move to save area
642 movsd ; Lim 3.2 has only 4 page frames
643
644 mov byte ptr [bp.rAX+1],OK ; ok return
645 ret
646
647spm_prev_saved:
648 mov byte ptr [bp.rAX+1],MAP_PREV_SAVED
649 ret
650
651srpm_inv_handle: ; Shared error returns
652 mov byte ptr [bp.rAX+1],INVALID_HANDLE
653 ret
654
655srpm_nopf:
656 mov byte ptr [bp.rAX+1], EMM_HW_MALFUNCTION ; No page frame!!!
657 ret
658
659_SavePageMap endp
660
661 page
662;***********************************************
663;
664; _RestorePageMap - restore handle's saved page mapping
665;
666; This routine restores the current page mapping context
667; from a handle's save area.
668;
669; ENTRY: PROTECTED MODE ONLY
670; AH = 08h = restore page map function #
671; DX = EMM handle
672; REGS on STACK: SI = not used by this function
673; SS:[BP] -> regp stack frame
674; DS = DGROUP
675;
676; EXIT: current state restored
677; AH = status of this function
678;
679; USED: AX,BX,CX,DX,SI,DI
680;
681;***********************************************
682
683Dword_Align _TEXT
684_RestorePageMap proc near
685 cmp [_page_frame_pages], 4
686 jb short srpm_nopf ; no page frame
687
688 mov ax, dx ; Save for later
689 Validate_Handle srpm_inv_handle
690 ; check state of handle's page area
691 imul bx,ax,SIZE SaveMap_struc ; BX = offset within Save Area for
692 ; this handle's save area
693 lea si,_save_map[bx] ; DS:SI points to handle's save area
694 cmp [si].s_handle,NULL_HANDLE
695 ;Q: save area in use ?
696 je short rpm_no_map_saved ; N: return error
697 ; Y: restore it
698
699 mov byte ptr [bp.rAX+1],OK ; Assume success
700 mov [si].s_handle,NULL_HANDLE ; null handle's save area
701
702 lea si,[si].s_map ; SI -> handle's save area
703 Get_FRS_window DI ; Get pointer to current window
704 push ds
705 pop es ; ES <-- DGROUP
706 cld
707 movsd ; restore 4 words
708 movsd ; Lim 3.2 has only 4 page frames
709 jmp _set_windows ; Restore mapping
710
711rpm_no_map_saved:
712 mov byte ptr [bp.rAX+1],NO_MAP_SAVED
713 ret
714
715_RestorePageMap endp
716
717 page
718;***********************************************
719;
720; _GetSetPageMap - get/set page map to/from external save area
721;
722; This routine stores the current page mapping context (Intel
723; compatible form for now) to an external save area and/or restores
724; the current page mapping context from an external save area.
725;
726; ENTRY: PROTECTED MODE ONLY
727; AH = 4Eh = Get/Set page map function number
728; or AH = 5Ch = Get/Set large page map function number
729; AL = SUBFUNCTION CODE
730; AL = 0 => Get page map
731; AL = 1 => Set page map
732; AL = 2 => Get and Set page map
733; AL = 3 => return size of page map
734; REGS on STACK: SI = not used by this function
735; SS:[BP] -> regp stack frame
736; DS = DGROUP
737;
738; EXIT: current state saved / restored
739; AH = status of this function
740;
741; USED: BX,CX,DX,SI,DI
742;
743;***********************************************
744Dword_Align _TEXT
745_GetSetPageMap proc near
746
747 cmp al,GSPM_GET ;Q: get page map subfunction ?
748 je short _get_map ; Y: get it
749
750 cmp al,GSPM_SET ;Q: set page map subfunction ?
751 je _set_map ; Y: set it
752
753 cmp al,GSPM_GETSET ;Q: get & set page map subfunction ?
754 jne short gspm_chk_size ; N: check for size function
755 call _get_map ; Y: get current map first
756 jmp short _set_map ; set new one
757
758gspm_chk_size:
759 cmp al, GSPM_SIZE ;Q: return map size subfunction ?
760 jne short gspm_inv_subfun ; N: return invalid subfunction
761
762 mov al, [_cntxt_bytes] ; size of map
763 mov ah, OK ; ok return
764 mov word ptr [bp.rAX], ax
765 ret
766
767gspm_inv_subfun:
768 mov byte ptr [bp.rAX+1],INVALID_SUBFUNCTION
769 ret
770
771gspm_inv_fun:
772 mov byte ptr [bp.rAX+1],INVALID_FUNCTION
773 ret
774
775_GetSetPageMap endp
776
777 page
778;***********************************************
779;
780; _get_map - save current mapping register state to external area
781;
782; ENTRY: on stack
783; clients ES:DI -> client's buffer for state
784; SS:[BP] -> regp stack frame
785; DS = DGROUP
786;
787; EXIT: state stored in client's buffer
788; return code set on stack
789;
790; USED: AX,BX,CX,DX,SI,DI,ES
791;
792; DESCRIPTION: This function saves the current mapping
793; into the save area specified.
794;
795;***********************************************
796Dword_Align _TEXT
797_get_map proc
798
799 cld
800 call _dest_addr ; DX:AX ptr for client's buff
801 mov es,dx
802 mov di,ax ; ES:DI pts to clients buffer
803
804 Get_FRS_window SI ; Get pointer to current window
805 movzx ecx, [_cntxt_pages]
806 mov ax, cx
807 stosw ; save # pages
808 shr cx, 1 ; now dwords
809 rep movsd ; mov bytes to current map area
810 mov byte ptr [bp.rAX+1],OK ; ok return
811 ret
812
813_get_map endp
814
815 page
816;***********************************************
817;
818; _set_map - restore mapping register state
819;
820; ENTRY: on stack
821; clients DS:SI -> client's buffer containing state to restore
822; SS:[BP] -> regp stack frame
823; DS = DGROUP
824;
825; EXIT: state restored from client's buffer
826; return code set on stack
827; CLC => no errors
828; STC => error occurred
829;
830; USED: EAX,BX,CX,DX,SI,DI,ES
831;
832;
833; DESCRIPTION: This function restores the mapping from the state info input.
834; The mapping is assumed to be the same as in the
835; save_current_map function. The count in the saved
836; state is verified.
837;
838;***********************************************
839Dword_Align _TEXT
840_set_map proc near
841
842 mov byte ptr [bp.rAX+1],OK ; Assume success
843 Get_FRS_window DI ; Get pointer to current window
844 ; before DS gets trashed
845 push ds
846 pop es ; use ES to address data
847 push dx
848 mov si, ax
849 call _source_addr ; DX:AX ptr for client's buff
850 mov ds,dx
851 xchg si,ax ; DS:SI pts to clients buffer
852 pop dx
853
854 cld
855 movzx ecx, es:[_cntxt_pages] ; number of words in mapping
856 lodsw ; saved size
857 cmp ax, cx ; should be this
858 jne short sm_inv_source ; Wrong, saved data corrupted
859 shr cx, 1 ; now a word count
860 rep movsd
861 push es
862 pop ds ; DS <-- DGROUP
863 jmp _set_windows ; make it effective
864
865sm_inv_source:
866 mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED
867 ret
868
869sm_exit:
870 ret
871
872_set_map endp
873
874 page
875;***********************************************
876;
877; _set_windows - re-map all mapped physical pages
878;
879; This routine maps all mapped 386 pages of the EMM page frame into the
880; linear address space for the page frame.
881;
882; ENTRY: PROTECTED MODE ONLY
883; DS = DGROUP
884; SS:[BP] -> regp stack frame
885;
886; EXIT: page tables changed to map these pages.
887; _current_map contents initialized.
888;
889; uses:
890; FLAGS, EAX, EBX, ECX, ESI, EDI
891;
892;***********************************************
893;
894_set_windows proc near
895;
896 xor ax, ax ; start from PHYS page 0
897 Get_FRS_Window SI ; SI <-- current FRS map
898sw_loop:
899 mov bx, word ptr [si] ; BX <-- emm page #
900 add si, 2 ; prepare for next PHYS page
901 cmp bx, 0FFFFh ; not mapped ?
902 je sw_unmap_page ; Y: unmap it
903 cmp bx, [_total_pages] ; emm page out of range ?
904 ja sw_corrupt ; Y: error
905 mov di, bx
906 shl di, 2 ; SI <-- _pft386 offset of emm page
907 add di, [_pft386]
908 cmp dword ptr [di], 0 ; pte not mapped ?
909 je sw_corrupt ; Y: error
910 push eax
911 call map_EMM_page ; map a page
912 pop eax
913sw_done_page:
914 inc ax
915 cmp ax, [_physical_page_count]
916 jb sw_loop ; next page
917
918 mov eax, cr3
919 mov cr3, eax ; flush TLB
920 ret
921
922sw_unmap_page:
923 push eax
924 call unmap_Page
925 pop eax
926 jmp short sw_done_page
927
928sw_corrupt:
929 mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED
930 pop dx
931 ret
932
933_set_windows endp
934
935 page
936;*******************************************************************************
937;
938; LIM 4.0 EXTRAS for Windows
939;
940;*******************************************************************************
941
942;***********************************************
943;
944; _GetSetPartial - get/set partial page map to/from external save area
945;
946; This routine stores the current page mapping context
947; to an external save area and/or restores the current page
948; mapping context from an external save area.
949;
950; ENTRY: PROTECTED MODE ONLY
951; AH = 4Fh = Get/Set page map function number
952; AL = SUBFUNCTION CODE
953; AL = 0 => Get page map
954; AL = 1 => Set page map
955; AL = 2 => return size of page map
956; REGS on STACK: SI = not used by this function
957; SS:[BP] -> regp stack frame
958; DS = DGROUP
959;
960; EXIT: current state saved / restored
961; AH = status of this function
962;
963; USED: BX,CX,DX,SI,DI
964;
965;***********************************************
966_GetSetPartial proc near
967 cmp al, 0 ; Get...?
968 jne gsppm_not0
969
970 call _source_addr ; uses AX, DX
971 mov fs, dx
972 mov si, ax
973 call _dest_addr ; uses AX, DX
974 mov es, dx
975 mov di, ax
976 cld
977 lods word ptr fs:[si]
978 stosw ; Save count in save area
979 or ax, ax
980 jz gsppm_ok ; nothing to do
981 movzx ecx, ax
982
983 mov dx, [_mappable_page_count]
984 cmp cx, dx
985 ja gsppm_inv_phys
986gsppm_get_loop:
987 lods word ptr fs:[si] ; Get segment
988 shr ax, 10 ; 16k page number
989 sub ax, CONV_STRT_PG ; first page in emm_mpindex arr
990 jb gsppm_inv_seg ; only pages above 256k
991 mov bx, ax
992 mov al, EMM_MPindex[bx] ; convert to physical page
993 cmp al, -1 ; does it exist
994 je gsppm_inv_seg
995 mov bx, ax
996 shl bx, 2
997 lea ax, _mappable_pages[bx]
998 mov bx, ax
999 mov bx, [bx.mappable_seg] ; segment for this page
1000 cmp bx, fs:[si-2]
1001 jne gsppm_inv_seg ; must match exactly
1002 mov bx, ax
1003 movzx ebx, [bx.mappable_pg] ; the physical page
1004 cmp bx, dx
1005 ja gsppm_inv_seg
1006 mov ax, bx
1007 stosw ; Save physical page
1008 Get_FRS_window BX ; Get pointer to current window
1009 add bx, ax ; get ptr to emm page# in FRS
1010 add bx, ax
1011 mov ax, [bx]
1012 stosw ; and current mapping
1013 loop gsppm_get_loop
1014
1015gsppm_ok:
1016 mov byte ptr [bp.rAX+1], OK
1017 ret
1018
1019gsppm_not0:
1020 cmp al, 1 ; Set...?
1021 jne gsppm_not1
1022 ; Set Partial Page Map
1023 call _source_addr ; uses AX, DX
1024 mov fs, dx
1025 mov si, ax
1026 movzx ecx, word ptr fs:[si] ; Get count from save area
1027 add si, 2
1028 jecxz gsppm_ok ; Zero count, do nothing
1029
1030 Get_FRS_window DX ; Get pointer to current window
1031 cmp cx, [_mappable_page_count]
1032 ja short gsppm_corrupt ; can't be more than phys pages
1033gsppm_set_loop:
1034 push esi
1035 movzx eax, word ptr fs:[si] ; Get Physical page
1036 cmp ax, [_mappable_page_count]
1037 jae gsppm_sl_bad
1038
1039 movzx esi, word ptr fs:[si+2] ; Get mapping (emm page#)
1040 mov di,dx
1041 add di,ax
1042 add di,ax ; di <-- current FRS phy page
1043 mov [di], si ; Save new mapping
1044
1045 cmp si, 0FFFFh ; Unmapped?
1046 je short gsppm_unmap ; yes, go unmap it
1047 cmp si, [_total_pages] ; valid page?
1048 jae short gsppm_sl_bad ; no, fail
1049
1050 mov bx, si ; bx <-- emm page#
1051 ; ax <-- phys page#
1052 call map_EMM_page
1053
1054gsppm_set_done:
1055 pop esi
1056 add esi, 4 ; Next page to map
1057 loop gsppm_set_loop
1058 mov eax, cr3 ; Flush TLB
1059 mov cr3, eax
1060 jmp gsppm_ok
1061
1062gsppm_unmap:
1063 call unmap_page ; with ax <-- phys page#
1064 jmp gsppm_set_done ; On to next page
1065
1066gsppm_sl_bad:
1067 pop esi
1068gsppm_corrupt:
1069 mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED
1070 ret
1071
1072gsppm_not1:
1073 cmp al, 2 ; Size?
1074 jne gspm_inv_subfun
1075 cmp bx, [_mappable_page_count] ; # of page frames
1076 ja short gsppm_inv_phys
1077 shl bx, 2 ; Size = pages * 4 + 2
1078 add bx, 2
1079 mov byte ptr [bp.rAX], bl
1080 jmp gsppm_ok
1081
1082gsppm_inv_subfun:
1083 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
1084 ret
1085
1086gsppm_inv_phys:
1087gsppm_inv_seg:
1088 mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
1089 ret
1090
1091_GetSetPartial endp
1092
1093 page
1094;***********************************************
1095;
1096; _MapHandleArray - map an array of a handle's pages
1097;
1098; This routine maps the physical pages according to
1099; an array of mappings.
1100;
1101; ENTRY: PROTECTED MODE ONLY
1102; AH = 50h = map handle page function #
1103; AL = Subfunction: 0) Physical pages described by their number
1104; 1) Physical pages described by segment
1105; CX = number of pages to be mapped
1106; DX = EMM handle
1107; REGS on STACK DS:SI = array of mappings
1108; SS:[BP] -> regp stack frame
1109; DS = DGROUP
1110; NOTE:
1111; There is a second entry point for this procedure at the label
1112; MapHandleArray_Entry_2. The entry conditions for this are identical
1113; to those specified above except that ESI points to the mapping array--
1114; the DS:SI on the stack are ignored. Also, the value in AH is undefined.
1115; This entry point is used by the AlterMapAndJump and AlterMapAndCall
1116; functions.
1117;
1118; EXIT: context block ve_window set up
1119; page table entries set up
1120; AH = status of this function
1121; = EMM_HW_MALFUNCTION if entry in real/virtual mode.
1122;
1123; USED: AX,BX,DX,SI,DI,FS
1124;
1125;***********************************************
1126Dword_Align _TEXT
1127_MapHandleArray proc near
1128 mov si, ax
1129 push dx
1130 call _source_addr ; DX:AX <-- mapping array
1131 xchg si, ax
1132 mov fs, dx
1133 pop dx ; FS:SI <-- mapping array
1134
1135MapHandleArray_Entry_2:
1136 cmp al, 1 ; Q: Is subfunction 0 or 1?
1137 ja mha_inv_sub ; N: Invalid subfunction
1138
1139 Validate_Handle <mha_inv_handle>
1140
1141 mov byte ptr [bp.rAX+1], OK ; Assume success
1142 movzx ecx, cx
1143 jecxz short mha_exit ; none to do, just return
1144
1145 or al, al ; which subfunction?
1146 jnz short mha_sub1 ; subfunction 1?
1147
1148 ;
1149 ; Subfunction 0: array contains logical and physical
1150 ; page numbers.
1151 ;
1152mha_sub0:
1153 movzx eax, fs:[si.mha0_phys_pg] ; physical page number
1154 movzx ebx, fs:[si.mha0_log_pg] ; logical page number
1155 call map_page ; map it if possible
1156 jc short mha_exit ; Error code already set
1157 add si, size mha_array0
1158 loop mha_sub0
1159 jmp short mha_exit
1160
1161 ;
1162 ; Subfunction 1: array contains logical page number and
1163 ; segment numbers corresponding to the
1164 ; desired physical pages.
1165 ;
1166mha_sub1:
1167 mov di, fs:[si.mha1_seg] ; segment to map
1168 mov ax, di ; save for later
1169 shr di, 10 ; 16k page number
1170 sub di, CONV_STRT_PG ; first page in emm_mpindex arr
1171 jb short mha_inv_seg ; only pages above 256k
1172 movsx edi, EMM_MPindex[di] ; convert to physical page
1173 cmp edi, -1 ; does it exist
1174 je short mha_inv_seg
1175 shl di, 2 ; index * 4
1176 lea di, _mappable_pages[di]
1177 cmp ax, [di.mappable_seg] ; segment for this page
1178 jne short mha_inv_seg ; must match exactly
1179 movzx eax, [di.mappable_pg] ; the physical page
1180 movzx ebx, fs:[si.mha1_log_pg] ; the logical page
1181 call map_page ; try to map it
1182 jc short mha_exit ; error code already set
1183 add si, size mha_array1
1184 loop mha_sub1 ; back for next segment to map
1185
1186mha_exit:
1187 mov eax, cr3 ; Always clear TLB, we may have
1188 mov cr3, eax ; mapped pages before an error
1189 ret
1190 ; ERRORS...
1191mha_inv_handle:
1192 mov byte ptr [bp.rAX+1], INVALID_HANDLE
1193 ret
1194mha_inv_sub:
1195 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
1196 ret
1197mha_inv_seg:
1198 mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
1199 jmp mha_exit
1200
1201_MapHandleArray endp
1202
1203
1204
1205 page
1206;***********************************************
1207;
1208; _AlterMapAndJump - map an array of a handle's pages and Jump to a
1209; a specified address
1210;
1211; This routine maps pages using the MapHandleArray procedure and jumps
1212; to the specified address
1213;
1214; ENTRY: PROTECTED MODE ONLY
1215; AL = Mapping method -- 0 = Physical pages, 1 = Segments
1216; DX = EMM handle
1217; REGS on STACK
1218; REGS on STACK -- DS:SI -> Map and Jump structure
1219; SS:[BP] -> regp stack frame
1220; DS = DGROUP
1221;
1222; EXIT: context block ve_window set up
1223; page table entries set up
1224; AH = status of this function
1225; = EMM_HW_MALFUNCTION if entry in real/virtual mode.
1226; Address specified in Map and Jump structure will be new return address
1227;
1228; USED: AX,BX,CX,SI,DI,FS,GS
1229;
1230;**********************************************
1231
1232_AlterMapAndJump PROC NEAR
1233
1234 push dx
1235 mov si, ax
1236 call _source_addr ; DX:AX <-- map & jump struct
1237 mov gs, dx
1238 xchg si, ax ; GS:SI <-- map & jump struct
1239 pop dx
1240 push si
1241 push ax
1242 push dx ; save EMM handle
1243 mov dx, WORD PTR gs:[si.maj_map_address] ; AX:DX <-- map array
1244 mov ax, WORD PTR gs:[si.maj_map_address+2]
1245 Set_EMM_GDT EMM2_GSEL
1246 mov fs, bx ; FS:0 <-- map array
1247 pop dx ; restore handle
1248 pop ax ; restore subfunction
1249 movzx ecx, byte ptr gs:[si.maj_log_phys_map_len] ; Length of map
1250 xor si, si ; FS:SI <-- map array
1251 call MapHandleArray_Entry_2 ; Map the array
1252 pop si
1253
1254 mov ah, byte ptr [bp.rAX+1]
1255 or ah, ah
1256 jnz SHORT AMJ_Error
1257 mov eax, dword ptr gs:[si.maj_target_address]
1258 mov word ptr [bp.retaddr], ax ; Put jump address in place of
1259 shr eax, 16 ; old IRET return address
1260 mov word ptr [bp.rCS], ax
1261 ;
1262 ; now, pop 5 words from client's stack because we are not
1263 ; going to go back. (See AlterMapAndCall for client's
1264 ; Stack frame structure)
1265 ;
1266 mov edi, dword ptr [bp.rFS+2+VTFO.VMTF_ESP] ; clients's ESP
1267 add edi, 5 * 2 ; "pop" 5 words
1268 mov dword ptr [bp.rFS+2+VTFO.VMTF_ESP], edi ; save it
1269 ;
1270 ; tell EMMpEntry to patch CS:IP onto its' iretd stack frame
1271 ;
1272 or word ptr [bp.PFlag], PFLAG_PATCH_CS_IP
1273AMJ_Error: ; Do the jump
1274 ret
1275
1276_AlterMapAndJump ENDP
1277
1278
1279 page
1280;***********************************************
1281;
1282; _AlterMapAndCall - map an array of a handle's pages and call a procedure
1283; at a specified address (similar to a FAR call)
1284; This function pushes the return address on the
1285; client's stack and Jumps to the specified procedure.
1286; The "Called" procedure will return to AMC_return_address
1287;
1288; ENTRY: PROTECTED MODE ONLY
1289; AL = Subfunction -- 0 = Map phys pages, 1 = Map segs, 2 = Frame size
1290; DX = EMM handle
1291; REGS on STACK DS:SI = Map and Call structure
1292; SS:[BP] -> regp stack frame
1293; DS = DGROUP
1294;
1295; EXIT: context block ve_window set up
1296; page table entries set up
1297; Transfer Space pushed on client's stack
1298; Return address CS and IP will point to called procedure
1299; AH = status of this function
1300; = EMM_HW_MALFUNCTION if entry in real/virtual mode.
1301;
1302; USED: AX,BX,CX,DX,SI,DI
1303;
1304;***********************************************
1305
1306_AlterMapAndCall PROC NEAR
1307
1308 cmp al, 2 ; Q: Which subfuction ?
1309 ja AMC_inv_sub ; >2: invalid subfunction
1310 je AMC_Stack_Fram_Size ; =2: Stack frame size subfuncion
1311 ; <2: map and call
1312 push dx
1313 mov si, ax
1314 call _source_addr ; DX:AX <-- map & call structure
1315 mov gs, dx
1316 xchg si, ax ; GS:SI <-- map & call structure
1317 pop dx
1318 ;
1319 ; check new and old map's length
1320 ;
1321 xor ch, ch
1322 mov cl, byte ptr gs:[si.mac_old_page_map_len] ; CX = Length of old map
1323 cmp cx, [_physical_page_count]
1324 jae AMC_inv_phys_pages
1325 mov cl, byte ptr gs:[si.mac_new_page_map_len] ; CX = Length of new map
1326 cmp cx, [_physical_page_count]
1327 jae AMC_inv_phys_pages
1328 ;
1329 ; get client's SS:ESP so we can push stuffs on it
1330 ;
1331 push ax
1332 push dx
1333
1334 mov edi, dword ptr [bp.rFS+2+VTFO.VMTF_ESP] ; clients's ESP
1335 mov ax, word ptr [bp.rFS+2+VTFO.VMTF_SS] ; client's SS
1336 xor dx, dx ; AX:DX <-- Seg:Off of Client's Stack
1337
1338 push ax ; client's Stack Segment
1339 Set_EMM_GDT EMM2_GSEL
1340 push bx ; client's Stack Selector
1341 ;
1342 ; get CS's Base to "push" on stack for later retf from client
1343 ;
1344 push GDTD_GSEL
1345 pop es ; ES:0 <-- GDT
1346 mov bx, cs ; selector
1347 and bl, SEL_LOW_MASK
1348 mov dx, word ptr es:[bx + 2] ; get lower 16 bit of Base
1349 mov al, byte ptr es:[bx + 4] ; get upper 8 bit of Base
1350 shr dx, 4
1351 shl al, 4
1352 or dh, al ; get the segment value
1353 mov bx, dx ; into BX
1354
1355 pop es ; ES:DI <-- client's SS
1356 pop cx ; CX <-- Client's stack Segment
1357
1358 pop dx
1359 pop ax
1360 ;
1361 ; save client's stack segment and target address on stack
1362 ; cause they (CX and EMM1_GSEL) get destroy
1363 ;
1364 push cx
1365 push word ptr gs:[si].mac_target_address+2
1366 push word ptr gs:[si].mac_target_address
1367 ;
1368 ; On the Client's stack :
1369 ;
1370 ; +-----------------+
1371 ; | client's Flag |
1372 ; +-----------------+
1373 ; | client's CS |
1374 ; +-----------------+
1375 ; | client's IP |
1376 ; +-----------------+
1377 ; | EMM_rEntry's CS |
1378 ; +-----------------+
1379 ; | EMM_rEntry's IP | <-- "SS:ESP" (ES:EDI)
1380 ; +-----------------+
1381 ;
1382 ; "pop" EMM_rEntry's CS:IP off the stack, save it on Ring0 stack
1383 ; in case thereis an error and need to restore state of stack.
1384 ; keep the rest (client's FLAG, CS and IP)
1385 ;
1386 push es:[di+2] ; EMM_rEntry's CS
1387 push es:[di] ; EMM_rEntry's IP
1388 add di, 2 * 2 ; "pop"
1389 ;
1390 ; save old map on stack
1391 ;
1392 movzx ecx, byte ptr gs:[si.mac_old_page_map_len] ; CX = Length of old map
1393 shl cx, 2 ; CX * 4 (4 bytes each entry)
1394 inc cx ; one more for length
1395 get_space_from_stack CX ; ES:DI <-- space on stack
1396 dec cx
1397 shr cx, 2 ; CX back to length in bytes
1398
1399 push ds
1400 push di ; save postion of stack
1401 push si
1402 push ax
1403 push bx
1404 push dx
1405 push cx ; save #pages
1406
1407 cld
1408 mov dx, word ptr gs:[si.mac_old_map_address] ; AX:DX <-- map array
1409 mov ax, word ptr gs:[si.mac_old_map_address+2]
1410 push es
1411 Set_EMM_GDT USER1_GSEL
1412 pop es
1413 mov ds, bx ; DS:0 <-- map array
1414 xor si, si
1415 pop cx
1416 mov ax, cx
1417 stosb ; store length of map
1418
1419 shl cx, 1 ; move word
1420 rep movsw
1421
1422 pop dx ; restore handle
1423 pop bx ; restore Segment of client Stack
1424 pop ax ; restore subfunction
1425 pop si
1426 pop di
1427 pop ds
1428 ;
1429 ; save FRS context on stack
1430 ;
1431 movzx ecx, [_cntxt_bytes]
1432 get_space_from_stack CX ; ES:DI <-- space on stack
1433
1434 push si
1435 push di
1436 get_FRS_Window SI ; DS:SI <-- mapping context
1437 shr ecx, 1 ; move words
1438 rep movsw
1439
1440 pop di
1441 pop si
1442 ;
1443 ; map new mapping
1444 ;
1445 push bx
1446 push ax
1447 push dx
1448
1449 push di ; save "stack pointer"
1450 push si
1451 push ax
1452 push dx ; save EMM handle
1453 mov dx, WORD PTR gs:[si.mac_new_map_address]; AX:DX <-- map array
1454 mov ax, WORD PTR gs:[si.mac_new_map_address+2]
1455 push es
1456 Set_EMM_GDT USER1_GSEL
1457 pop es
1458 mov fs, bx ; FS:0 <-- map array
1459 xor si, si
1460 pop dx ; restore handle
1461 pop ax ; restore subfunction
1462 movzx ecx, byte ptr gs:[si.mac_new_page_map_len]
1463 call MapHandleArray_Entry_2 ; Map the array
1464 pop si ; Restore structure pointer
1465 pop di ; restore "stack" pointer
1466 pop dx
1467 pop ax
1468 mov bh, byte ptr [bp.rAX+1]
1469 or bh, bh
1470 pop bx
1471 jnz AMC_map_Error
1472 ;
1473 ; save needed registers, return address and call address
1474 ; on client's stack
1475 ;
1476 dec di
1477 dec di ; "pre-decrement" stack
1478 std ; store backward
1479 stosw ; subfunction code
1480 mov ax, dx ; EMM handle
1481 stosw
1482 mov ax, ds ; DGROUP
1483 stosw
1484 mov ax, bx ; CS for return from called code
1485 stosw
1486 mov ax, offset AMC_return_address ; IP for return from called code
1487 mov es:[di], ax ; "push" without decrement "SP"
1488 cld
1489 ;
1490 ; NOW build a iretd stack frame to go back to virtual mode
1491 ;
1492 pop ax ; no error : we can throw
1493 pop ax ; away EMM-rEntry's CS:IP now
1494
1495 pop ax ; target address
1496 pop dx ; target address+2
1497 pop cx ; Stack Segment
1498
1499 push 0
1500 push word ptr [bp].rGS
1501 push 0
1502 push word ptr [bp].rFS
1503 push 0
1504 push word ptr [bp].rDS
1505 push 0
1506 push word ptr [bp].rES
1507 push 0
1508 push cx ; client's SS
1509 push edi ; client's ESP
1510 push PFLAG_VM ; VM bit
1511 mov bx, word ptr [bp].PFlag
1512 and bx, not PFLAG_VIRTUAL ; clear fake bit
1513 push bx
1514 push 0
1515 push dx ; target address+2
1516 push 0
1517 push ax ; target address
1518 ;
1519 ; restore registers context from stack frame
1520 ;
1521 mov eax, dword ptr [bp].rAX
1522 mov ebx, dword ptr [bp].rBX
1523 mov ecx, dword ptr [bp].rCX
1524 mov edx, dword ptr [bp].rDX
1525 mov esi, dword ptr [bp].rSI
1526 mov edi, dword ptr [bp].rDI
1527 mov ebp, dword ptr [bp].rFS+2 ; clients's EBP
1528 ;
1529 ; return to virtual mode via iretd with calling address on stack
1530 ;
1531 iretd
1532
1533AMC_map_Error:
1534 ;
1535 ; mapping error occur : restore state and exit
1536 ;
1537 movzx ecx, [_cntxt_bytes]
1538 push es
1539 pop ds ; DS:SI <-- stack
1540 xchg si, di
1541 release_space_to_stack CX ; DS:SI <-- space on stack
1542 ;
1543 movzx ecx, byte ptr gs:[di.mac_old_page_map_len] ; CX = Length of old map
1544 shl cx, 2 ; CX * 4 (4 bytes each entry)
1545 inc cx ; one more for length
1546 release_space_to_stack CX ; DS:SI <-- space on stack
1547 ;
1548 mov di, si
1549 mov cx, 4
1550 get_space_from_stack CX ; ES:DI <-- space on stack
1551 pop es:[di] ; restore EMM_rEntry's CS:IP
1552 pop es:[di+2]
1553
1554 pop ax ; discard target addr etc
1555 pop ax
1556 pop ax
1557
1558 ret
1559
1560AMC_Stack_Fram_Size:
1561 mov byte ptr [bp.rAX+1], OK ; No error
1562 mov ax, [_mappable_page_count] ; assume ALL mappable pages
1563 shl ax, 2 ; 4 bytes per page
1564 add ax, 1 + (3+5)*2 ; map length
1565 ; + 3 words already pushed by EMM_rEntry
1566 ; + 5 registers pushed
1567 add al, [_cntxt_bytes] ; FRS context
1568 adc ah, 0
1569 mov word ptr [bp.rBX], ax
1570 ret
1571
1572AMC_inv_phys_pages:
1573 mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
1574 ret
1575
1576AMC_inv_sub:
1577 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
1578 ret
1579
1580_AlterMapAndCall ENDP
1581
1582
1583;******************************************************************************
1584;
1585; AMC_return_address -- Return from procedure called through a Map & Call
1586;
1587; NOTE: MapHandleArray will only access AH on the stack and so the
1588; TSTF stack frame will work properly for this procedure.
1589;
1590; ENTRY: VTFOE frame,EBP,EBX,ESI are on the stack
1591;
1592;******************************************************************************
1593
1594AMC_return_address proc far
1595
1596;
1597; This will causes an illegal instruction trap and goes into protected
1598; mode. The handler will return back to the point right after the
1599; 2 bytes ARPL instruction with ring0 stack having and IRETD stack frame
1600;
1601 arpl ax, ax
1602 ;
1603 ; In Protected Mode Now
1604 ;
1605 pushad ; saves all regs
1606 mov ax, sp ; saves stack frame address
1607 mov [_regp], ax ; to _regp
1608
1609 mov esi, dword ptr [bp.VTFOE.VMTF_ESP] ; clients's ESP
1610 mov ax, word ptr [bp.VTFOE.VMTF_SS] ; client's SS
1611 xor dx, dx ; AX:DX <-- Seg:Off of Client's Stack
1612
1613 Set_EMM_GDT EMM2_GSEL
1614 mov fs, bx ; FS:SI <-- client's Stack
1615
1616 cld ; forward
1617 ;
1618 ; "pop" back registers on "stack" FS:SI
1619 ;
1620 push fs
1621 pop ds
1622 lodsw
1623 mov es, ax ; DGROUP
1624 lodsw
1625 mov dx, ax ; EMM handle
1626 lodsw ; subfunction code
1627 ;
1628 ; restore mapping context
1629 ;
1630 push ax
1631
1632 push es
1633 pop ds ; DGROUP
1634 get_FRS_Window DI ; ES:DI <-- FRS mapping context regs
1635 push fs
1636 pop ds ; DS:SI <-- client's stack
1637 xor ch, ch
1638 mov cl, ES:[_cntxt_bytes]
1639 shr cx, 1 ; move word
1640 cld
1641 rep movsw
1642 ;
1643 ; map old mapping
1644 ;
1645 lodsb
1646 mov ah, 0
1647 mov cx, ax ; length
1648 pop ax ; subfunction code
1649 push si
1650 push cx
1651 push bp
1652 mov bp, [_regp] ; setup pushad frame first
1653 push es
1654 pop ds ; DS <-- DGROUP
1655 call MapHandleArray_Entry_2 ; map it
1656 pop bp
1657 pop cx
1658 pop si
1659 shl cx, 2 ; 4 bytes per mapping
1660 release_space_to_stack CX
1661 ;
1662 ; saves CS:IP (BX:CX) on iretd stack frame
1663 ;
1664 push fs
1665 pop ds ; DS <-- Client's Stack
1666 push ax
1667 lodsw
1668 mov word ptr [bp.VTFOE+VMTF_EIP], ax
1669 lodsw
1670 mov word ptr [bp.VTFOE+VMTF_CS], ax
1671 lodsw
1672 mov word ptr [bp.VTFOE+VMTF_EFLAGS], ax
1673 mov word ptr [bp.VTFOE+VMTF_EFLAGShi], PFLAG_VM
1674 pop ax
1675 ;
1676 ; save client's new stack pointer
1677 ;
1678 mov dword ptr [bp.VTFOE.VMTF_ESP], esi
1679 popad
1680 pop esi
1681 pop ebx
1682 pop ebp
1683 add esp, 4 ; discard "error" code
1684 ;
1685 ; set return status
1686 ;
1687 mov ah, OK
1688
1689 iretd
1690
1691AMC_return_address endp
1692
1693 page
1694;******************************************************************************
1695;
1696; _MoveExchangeMemory
1697;
1698; This function (23) will copy or exchange memory between EMM and
1699; conventional memory or EMM to EMM.
1700; Subfunction 0 is memory copy. Subfunction 1 is exchange.
1701; The current mapping context is preserved since the EMM pages are
1702; mapped into high memory using VM1s page table.
1703;
1704; ENTRY: PROTECTED MODE ONLY
1705; AL = Subfunction -- 0 = Copy, 1 = Exchange
1706; DX = EMM handle
1707; REGS on STACK DS:SI = Move/Exchange structure
1708; SS:[BP] -> regp stack frame
1709; DS = DGROUP
1710;
1711; EXIT: AL = Status
1712;
1713; USES: AX, BX, CX, DX, SI, DI
1714;
1715;==============================================================================
1716;
1717; ALGORITHM:
1718;
1719; BEGIN
1720; check/validate source/dest and overlay,etc
1721;
1722; save mapping context of first physical page frame as source page frame
1723; save mapping context of second physical page frame as dest page frame
1724;
1725; /*
1726; * setup source and dest memory pointers
1727; */
1728; if (source.type == conv.mem)
1729; DS:SI = source.initial.segment:source.initial.offset
1730; else
1731; if (backward.copy)
1732; calculate last source emm page and new offset
1733; map source.initial.page into source.page.frame
1734; DS:SI = segment.of.source.page.frame:source.initial.offset
1735;
1736; if (dest.type == conv.mem)
1737; ES:DI = dest.initial.segment:dest.initial.offset
1738; else
1739; if (backward.copy)
1740; calculate last dest emm page and new offset
1741; map dest.initial.page into dest.page.frame
1742; ES:DI = segment.of.dest.page.frame:dest.initial.offset
1743;
1744; /********
1745; *
1746; * DS:SI - addresses source data area
1747; * ES:DI - addresses dest buffer area
1748; *
1749; */
1750;
1751; for (total.byte.to.process != 0) {
1752; /*
1753; * find out how many bytes to process (least bytes to process)
1754; */
1755; if (source.type == conv.mem)
1756; bytes.to.process = 0x4000 - dest.offset
1757; else
1758; if (dest.type == conv.mem)
1759; bytes.to.process = 0x4000 - source.offset
1760; else /* emm to emm */
1761; if (backward.copy)
1762; bytes.to.process = min(source.offset, dest.offset) + 1
1763; else
1764; bytes.to.process = 0x4000 - max(source.offset, dest.offset)
1765;
1766; /*
1767; * adjust the total
1768; */
1769; if (bytes.to.process > totol.bytes.to.process)
1770; bytes.to.process = totol.bytes.to.process
1771;
1772; total.bytes.to.process -= bytes.to.process
1773;
1774; /*
1775; * do the processing
1776; */
1777; move/exchange bytes.to.process bytes
1778;
1779; /*
1780; * adjust memory pointers and map in new pages if necessary
1781; * for the next iternation
1782; */
1783; if (total.bytes.to.process != 0)
1784; if (source.type == emm)
1785; if (SI == 0x4000)
1786; /*
1787; * forward.copy's index expire
1788; */
1789; map next emm source page into source.page.frame
1790; SI = 0
1791; if (SI == 0xffff)
1792; /*
1793; * backward.copy's index expire
1794; */
1795; map prev emm source page into source.page.frame
1796; SI = 0x3fff
1797; else
1798; normalize DS:SI
1799;
1800; if (dest.type == emm)
1801; if (DI == 0x4000)
1802; /*
1803; * forward.copy's index expire
1804; */
1805; map next emm dest page into dest.page.frame
1806; DI = 0
1807; if (DI == 0xffff)
1808; /*
1809; * backward.copy's index expire
1810; */
1811; map prev emm dest page into dest.page.frame
1812; DI = 0x3fff
1813; else
1814; normalize ES:DI
1815; }
1816;
1817; restore first page frame's mapping context
1818; restore second page frame's mapping context
1819; END
1820;
1821;==============================================================================
1822
1823
1824_MoveExchangeMemory proc near
1825 mov byte ptr [bp.rAX+1], OK ; Assume everything work OK
1826 cld ; Assume forward direction
1827
1828 cmp al, 1 ; Q: Valid subfunction?
1829 ja mem_inv_sub ; N: Error
1830
1831 push ds
1832 pop fs ; fs <-- addresses MEMM's data group
1833
1834 push dx
1835 push cx
1836 push bx
1837 push ax
1838
1839 push bp
1840 mov bp,[_regp]
1841 mov ax, word ptr [bp.rDS] ; DX:AX <-- move/xchg struct
1842 mov dx, word ptr [bp.rSI]
1843 Set_EMM_GDT USER1_GSEL ; use USER1_GSEL since both EMM1_GSEL
1844 ; and EMM2_GSEL will be used
1845 mov ds, bx
1846 xor si, si ; DS:SI <-- Move/Exchange structure
1847 pop bp
1848 pop ax
1849 pop bx
1850 pop cx
1851 pop dx
1852
1853 mov ecx, [si.mem_region_length]; ECX = Length of memory region
1854 or ecx, ecx ; Q: Move 0 bytes?
1855 jz mem_no_error ; Y: Silly! -- Just return
1856 cmp ecx, 0100000h ; Q: Move greater than 1 Meg?
1857 ja mem_inv_region_len ; Y: Error
1858
1859 mov bl, [si.mem_source.mem_memory_type]; Q: Is move Conventional
1860 or bl, [si.mem_dest.mem_memory_type] ; to Conven?
1861 jz mem_conv_to_conv ; Y: Go do it
1862
1863 mov bl, [si.mem_source.mem_memory_type]; Q: Is move EMM
1864 and bl, [si.mem_dest.mem_memory_type] ; to EMM
1865 jz SHORT mem_no_overlap ; N: No overlap
1866 mov bx, [si.mem_source.mem_handle]
1867 cmp bx, [si.mem_dest.mem_handle] ; Q: Same handle?
1868 jnz SHORT mem_no_overlap ; N: No overlap
1869 movzx ebx, [si.mem_source.mem_initial_seg_page]
1870 movzx edx, [si.mem_source.mem_initial_offset]
1871 shl ebx, 14 ; * 4000h
1872 add ebx, edx ; EBX = Source offset within EMM
1873 push ebx ; Save it temporarily
1874 movzx edx, [si.mem_dest.mem_initial_seg_page]
1875 movzx ebx, [si.mem_dest.mem_initial_offset]
1876 shl edx, 14 ; * 4000h
1877 add edx, ebx ; EDX = Dest offset within EMM
1878 pop ebx ; Source offset
1879 sub edx, ebx ; EDX = Source - Destination
1880 jg SHORT mem_dest_gt_source ; Don't negate if Dest > Source
1881 or al, Source_GT_Dest_Flag ; Set flag to note Source > Dest
1882 neg edx ; Absolute value of EDX
1883mem_dest_gt_source:
1884 cmp edx, ecx ; Q: Is there an overlap?
1885 jae SHORT mem_no_overlap ; N: Continue
1886 test al, 1 ; Q: Is this an exchange?
1887 jnz mem_inv_overlap ; Y: Error -- Cant overlap xchg
1888 mov byte ptr [bp.rAX+1], VALID_OVERLAP ; Assume everything OK but overlap
1889 or al, Overlap_Flag ; N: Note this for later
1890 test al, Source_GT_Dest_Flag ; Q: Is it gonna be backward copy
1891 jnz mem_no_overlap ; N: Continue
1892 or al, Backward_Copy_Flag ; Y: Note for later
1893 std ; Set backword direction
1894
1895mem_no_overlap:
1896 ;
1897 ; check validility of source
1898 ;
1899 lea di, [si.mem_source]
1900 call validate_for_Move_or_Exchange
1901 or ah, ah
1902 jnz mem_error_exit
1903 ;
1904 ; check validility of dest
1905 ;
1906 lea di, [si.mem_dest]
1907 call validate_for_Move_or_Exchange
1908 or ah, ah
1909 jnz mem_error_exit
1910
1911 or edx, edx ; delayed test for exact move/xchg
1912 je mem_valid_overlap ; WEIRD!!! -- Move to same place!
1913;
1914; initialize loop
1915;
1916 push ds
1917 pop gs
1918 mov bx, si ; GS:BX <-- move/exchange structure
1919 ;
1920 ; save first 2 physical page frames' mapping and use those pages
1921 ; as source and dest physical pages
1922 ;
1923 push fs
1924 pop ds ; DS <-- DGROUP
1925 get_FRS_Window SI
1926 push word ptr [SI] ; save 1st pgae's mapping on stack
1927 push word ptr [SI+2] ; save 2st page's mapping on stack
1928
1929 ;
1930 ; setup dest
1931 ;
1932mem_set_dest:
1933 cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ?
1934 jnz mem_map_dest ; N: map in emm page
1935 ;
1936 ; conv memory : setup starting address of dest (always forward)
1937 ;
1938 mov cx, gs:[bx.mem_dest.mem_initial_seg_page]
1939 mov dx, gs:[bx.mem_dest.mem_initial_offset] ; CX:DX <-- dest address
1940
1941 push ax
1942 push bx
1943 mov ax, cx ; AX:DX <-- first byte
1944 Set_EMM_GDT EMM2_GSEL
1945 mov es, bx
1946 xor di, di ; ES:DI <-- dest SelOff
1947 pop bx
1948 pop ax
1949 push 0ffffh ; fake a logical page#
1950 jmp mem_set_source
1951
1952mem_map_dest:
1953 ;
1954 ; emm memory : find out starting address of dest
1955 ;
1956 mov dx, gs:[bx.mem_dest.mem_initial_seg_page] ; initial logical page#
1957 mov di, gs:[bx.mem_dest.mem_initial_offset] ; initial offset
1958
1959 test al, Backward_Copy_Flag ; Q: Backward copy ?
1960 jz SHORT mem_map_dest_forward ; N: forward
1961
1962 ;
1963 ; backward move : calculate last logical page# and offset
1964 ;
1965 mov ecx, gs:[bx.mem_region_length]
1966 movzx edi, gs:[bx.mem_dest.mem_initial_offset]
1967 dec edi
1968 add ecx, edi
1969 push ecx
1970 and ecx, 00003fffh
1971 mov edi, ecx ; new offset
1972 pop ecx
1973 shr ecx, 14 ; / 16K = # of pages
1974 add dx, cx ; last emm page#
1975
1976mem_map_dest_forward:
1977 push dx ; put current dest logical page# on stack
1978 ;
1979 ; prepare to map
1980 ;
1981 push ax
1982 push bx
1983
1984 push dx
1985 mov dx, gs:[bx.mem_dest.mem_handle]
1986 Handle2HandlePtr
1987 pop bx
1988 mov ax, 1 ; 2nd page frame
1989 call map_page
1990 jc mem_mapping_error_3_pop ; pop out dest seg_page
1991
1992 ; contruct GDT entry for EMM2_GSEL for ES:0
1993 ;
1994 mov ax, [PF_Base]
1995 add ax, 0400h ; 2nd page frame segment
1996 xor dx, dx ; offset 0
1997 Set_EMM_GDT EMM2_GSEL
1998 mov es, bx ; ES:DI <-- dest address
1999
2000 pop bx
2001 pop ax
2002
2003 ;
2004 ; setup source
2005 ;
2006mem_set_source:
2007 cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ?
2008 jnz mem_map_source ; N: map in emm page
2009 ;
2010 ; conv memory : setup starting address of source (always forward)
2011 ;
2012 mov cx, gs:[bx.mem_source.mem_initial_seg_page]
2013 mov dx, gs:[bx.mem_source.mem_initial_offset] ; CX:DX <-- source address
2014
2015 push ax
2016 push bx
2017 push es
2018 mov ax, cx ; AX:DX <-- first byte
2019 Set_EMM_GDT EMM1_GSEL
2020 mov ds, bx
2021 xor si, si
2022 pop es
2023 pop bx
2024 pop ax
2025 push 0ffffh ; fake a logical page#
2026 jmp short mem_set_done
2027
2028mem_map_source:
2029 ;
2030 ; emm memory : find out starting address of dest
2031 ;
2032 mov dx, gs:[bx.mem_source.mem_initial_seg_page] ; initial logical page#
2033 mov si, gs:[bx.mem_source.mem_initial_offset] ; inital offset
2034
2035 test al, Backward_Copy_Flag ; Q: Backward copy ?
2036 jz SHORT mem_map_source_forward ; N: forward
2037
2038 ;
2039 ; backward move : calculate last logical page# and offset
2040 ;
2041 mov ecx, gs:[bx.mem_region_length]
2042 movzx esi, gs:[bx.mem_source.mem_initial_offset]
2043 dec esi
2044 add ecx, esi
2045 push ecx
2046 and ecx, 00003fffh
2047 mov esi, ecx ; new offset
2048 pop ecx
2049 shr ecx, 14 ; / 16K = # of pages
2050 add dx, cx ; last emm page#
2051
2052mem_map_source_forward:
2053 push dx ; put current source logical page# on stack
2054 ;
2055 ; prepare to map
2056 ;
2057 push ax
2058 push bx
2059
2060 push dx
2061 mov dx, gs:[bx.mem_source.mem_handle]
2062 Handle2HandlePtr
2063 pop bx
2064 mov ax, 0 ; 1st page frame
2065 call map_page
2066 jc mem_mapping_error_4_pop ; pop out dest and source seg_page
2067
2068 ; contruct GDT entry for EMM1_GSEL for DS:0
2069 ;
2070 mov ax, [PF_Base] ; 1st page frame segment
2071 xor dx, dx ; offset 0
2072 push es
2073 Set_EMM_GDT EMM1_GSEL
2074 pop es ; ES:0 <-- GDT
2075 mov ds, bx ; ES:DI <-- dest address
2076
2077 pop bx
2078 pop ax
2079
2080 ; DS:SI <-- source address
2081 ; ES:DI <-- dest address
2082
2083mem_set_done:
2084 mov edx, gs:[bx.mem_region_length] ; total length to move/xchg
2085
2086;
2087; main move/exchange loop
2088;
2089mem_loop:
2090 mov ecx, cr3
2091 mov cr3, ecx ; flush TLB after each map loop
2092
2093 mov ecx, 4000h ; maximum length to move/xchg
2094 ; in one mapping (<16K)
2095 cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ?
2096 jnz mem_source_is_emm ; N: check dest
2097 sub cx, di ; CX <-- length to move/xchg
2098 jmp short mem_calculate_length
2099mem_source_is_emm:
2100 cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ?
2101 jnz mem_both_are_emm ; N: find out which
2102 ; emm has less
2103 ; to move/exchange
2104 sub cx, si ; CX <-- length to move/xchg
2105 jmp short mem_calculate_length
2106mem_both_are_emm:
2107 test al, Backward_Copy_Flag ; Q:backward copy ?
2108 jz SHORT mem_2_emm_forward ; N:forward
2109 mov cx, si
2110 inc cx
2111 cmp si, di ; Q:si<di ? (min(si,di))
2112 jb short mem_calculate_length ; Y: use si
2113 mov cx, di ; N: use di
2114 inc cx
2115 jmp short mem_calculate_length
2116
2117mem_2_emm_forward:
2118 cmp si, di ; Q:si>di ? (max(si,di))
2119 ja mem_si_gt_di ; Y: use si
2120 sub cx, di ; N: use di
2121 jmp short mem_calculate_length
2122mem_si_gt_di:
2123 sub cx, si ; si>di
2124
2125mem_calculate_length:
2126 cmp ecx, edx ; Q: bytes in this batch > total
2127 jbe mem_do_move_xchg ; N: go ahead to move/xchg
2128 mov ecx, edx ; Y: use total instead
2129
2130;
2131; move/xchg loop
2132;
2133mem_do_move_xchg:
2134 sub edx, ecx ; Adjust total first
2135
2136 test al, 1 ; Q: Is this an exchange?
2137 jnz SHORT mem_exchange ; Y: Do it
2138 test al, Backward_Copy_Flag ; N: Q:Is this backward copy ?
2139 jz SHORT mem_move_forward ; N: forward
2140;
2141; memory move backward
2142;
2143 rep movsb
2144 jmp mem_next_round
2145;
2146; memory move forward
2147;
2148mem_move_forward:
2149 push eax
2150 mov eax, ecx
2151 shr ecx, 2 ; ECX = # DWORDS to copy
2152 rep movsd ; Move the DWORDS
2153 mov ecx, eax
2154 and ecx, 00000003h ; ECX = # BYTES left to copy
2155 rep movsb ; Move the BYTES
2156 pop eax
2157 jmp short mem_next_round
2158;
2159; momory exchange
2160;
2161mem_exchange:
2162 push dx
2163 push ax
2164 push bx
2165 push ecx ; Save total # bytes on stack
2166 shr ecx, 2 ; ECX = # DWORDS to exchange
2167 jecxz mem_xchg_bytes ; Exit if no DWORDS left
2168 mov dx, 4 ; Size of DWORD
2169mem_xchg_dword_loop:
2170 mov eax, [si]
2171 mov ebx, es:[di]
2172 mov es:[di], eax
2173 mov [si], ebx
2174 add si, dx
2175 add di, dx
2176 loop mem_xchg_dword_loop ; Loop until all DWORDS exchanged
2177mem_xchg_bytes:
2178 pop ecx
2179 and ecx, 00000003h ; ECX = # BYTES left to exchange
2180 jecxz mem_xchg_done ; Exit if no DWORDS left
2181mem_xchg_byte_loop:
2182 mov al, [si]
2183 mov bl, es:[di]
2184 mov es:[di], al
2185 mov [si], bl
2186 inc si
2187 inc di
2188 loop mem_xchg_byte_loop ; Loop until all BYTES exchanged
2189mem_xchg_done:
2190 pop bx
2191 pop ax
2192 pop dx ; DONE!!!!
2193
2194;
2195; prepare for next iteration
2196;
2197mem_next_round:
2198 ;
2199 ; get source and dest's current mapped logical page
2200 ; from stack
2201 ;
2202 pop cx ; source logical page#
2203 shl ecx, 16 ; put in high word
2204 pop cx ; dest logical page#
2205
2206 or edx, edx ; Q: all done ?
2207 jz mem_exit ; Y: restore context first
2208
2209 ; fix dest addresses
2210 ;
2211 cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ?
2212 jnz mem_map_next_dest ; N: map next page
2213 normalize ES,DI
2214 jmp mem_check_source
2215
2216mem_map_next_dest:
2217 cmp di, 4000h ; Q: di expires (forward)?
2218 je short mem_map_next_dest_forward ; Y:
2219 cmp di, 0ffffh ; Q: di expires (backward) ?
2220 jne short mem_check_source ; N: go check source
2221
2222 mov di, 3fffh ; set di for next round
2223 dec cx ; next logical page
2224 jmp SHORT mem_map_next_dest_do_map
2225
2226mem_map_next_dest_forward:
2227 xor di, di ; clear di for next round
2228 inc cx ; next logical page
2229
2230 ;
2231 ; map in the next dest page
2232 ;
2233mem_map_next_dest_do_map:
2234 push dx
2235 push ax
2236 push bx
2237 push ecx
2238 push ds
2239 push fs
2240 pop ds
2241 mov dx, gs:[bx.mem_dest.mem_handle]
2242 Handle2HandlePtr
2243 mov ax, 1 ; 2nd page frame
2244 mov bx, cx
2245 call map_page
2246 pop ds
2247 pop ecx
2248 pop bx
2249 pop ax
2250 pop dx
2251 jc mem_mapping_error
2252
2253 ;
2254 ; fix source addresses
2255 ;
2256mem_check_source:
2257 ror ecx, 16 ; get source log page in low word
2258 cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ?
2259 jnz mem_map_next_source ; N: map next page
2260 normalize DS,SI
2261 jmp mem_check_done
2262
2263mem_map_next_source:
2264 cmp si, 4000h ; Q: si expires (forward)?
2265 je short mem_map_next_source_forward ; Y:
2266 cmp si, 0ffffh ; Q: si expires (backward) ?
2267 jne short mem_check_done ; N: all done
2268
2269 mov si, 3fffh ; set si for next round
2270 dec cx ; next logical page
2271 jmp SHORT mem_map_next_source_do_map
2272
2273mem_map_next_source_forward:
2274 xor si, si ; clear si for next round
2275 inc cx ; next logical page
2276
2277 ;
2278 ; map in the next source page
2279 ;
2280mem_map_next_source_do_map:
2281 push dx
2282 push ax
2283 push bx
2284 push ecx
2285 push ds
2286 push fs
2287 pop ds
2288 mov dx, gs:[bx.mem_source.mem_handle]
2289 Handle2HandlePtr
2290 mov ax, 0 ; 1st page frame
2291 mov bx, cx
2292 call map_page
2293 pop ds
2294 pop ecx
2295 pop bx
2296 pop ax
2297 pop dx
2298 jc mem_mapping_error
2299 ;
2300 ; push back the logical pages on stack for
2301 ; next iternation : dest first, then source
2302 ;
2303mem_check_done:
2304 ror ecx, 16
2305 push cx
2306 ror ecx, 16
2307 push cx
2308 jmp mem_loop
2309
2310;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2311;
2312; conv to conv
2313;
2314;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2315mem_conv_to_conv:
2316 ;
2317 ; check validility of source
2318 ;
2319 lea di, [si.mem_source]
2320 call validate_for_Move_or_Exchange
2321 or ah, ah
2322 jnz mem_error_exit
2323 ;
2324 ; check validility of dest
2325 ;
2326 lea di, [si.mem_dest]
2327 call validate_for_Move_or_Exchange
2328 or ah, ah
2329 jnz mem_error_exit
2330
2331 push ax ; save subfunction
2332 push [si.mem_region_length] ; save length
2333
2334 movzx eax, [si.mem_dest.mem_initial_seg_page]
2335 movzx edx, [si.mem_dest.mem_initial_offset]
2336 mov edi, eax
2337 shl edi, 4
2338 add edi, edx ; EDI <-- dest linear addr
2339 Set_EMM_GDT EMM2_GSEL
2340 Set_Page_Gran EMM2_GSEL
2341 push bx ; save dest GDT selector
2342
2343 movzx eax, [si.mem_source.mem_initial_seg_page]
2344 movzx edx, [si.mem_source.mem_initial_offset]
2345 mov esi, eax
2346 shl esi, 4
2347 add esi, edx ; ESI <-- source linear addr
2348 Set_EMM_GDT EMM1_GSEL
2349 Set_Page_Gran EMM1_GSEL
2350 mov ds, bx
2351
2352 pop es ; recover dest GDT sel
2353 pop ecx ; recover length
2354 pop ax ; recover subfunction
2355 ;
2356 ; test for overlapping transfer
2357 ;
2358 mov byte ptr [bp.rAX+1], VALID_OVERLAP ; assume valid overlap
2359 sub edi, esi ; EDI = Source - Destination
2360 jg SHORT mem_dest_gt_source_2 ; Don't negate if Dest > Source
2361 or al, Source_GT_Dest_Flag ; Set flag to note Source > Dest
2362 neg edi ; Absolute value of EDI
2363mem_dest_gt_source_2:
2364 mov ebx, edi ; Use EBX instead
2365 cmp ebx, ecx ; Q: Is there an overlap?
2366 jae SHORT mem_no_overlap_2 ; N: Continue
2367 test al, 1 ; Q: Is this an exchange?
2368 jnz mem_inv_overlap ; Y: Error -- Cant overlap xchg
2369 or al, Overlap_Flag ; N: Note this for later
2370 test al, Source_GT_Dest_Flag ; Q: Is it gonna be backward copy
2371 jnz mem_no_overlap_2 ; N: Continue
2372 or al, Backward_Copy_Flag ; Y: Note for later
2373
2374 mov edx, (not 1)+1 ; increment value of -1 (2's compliment of 4)
2375 mov esi, ecx ; Fix ESI and EDI for reverse copy
2376 dec esi
2377 mov edi, esi
2378 jmp short mem_conv_copy
2379
2380mem_no_overlap_2:
2381 mov byte ptr [ebp.rAX+1], OK ; Everything worked OK
2382 mov edx, 1 ; increment value of 1
2383 xor esi, esi ; DS:ESI <-- source addr
2384 xor edi, edi ; ES:EDI <-- dest addr
2385
2386 test al, 1 ; Q:copy ?
2387 jnz mem_conv_xchg ; N:go do exchange
2388
2389mem_conv_copy:
2390 or ebx, ebx
2391 je mem_valid_overlap ; WEIRD!!! -- Move to same place!
2392
2393 jecxz mem_conv_done
2394mem_conv_copy_loop:
2395 mov bl, [esi]
2396 mov es:[edi], bl
2397 add esi, edx
2398 add edi, edx
2399 dec ecx
2400 jnz mem_conv_copy_loop
2401 jmp mem_conv_done ; DONE!!!!
2402
2403mem_conv_xchg:
2404 jecxz mem_conv_done
2405mem_conv_xchg_loop:
2406 mov al, [esi]
2407 mov bl, es:[edi]
2408 mov es:[edi], al
2409 mov [esi], bl
2410 inc esi
2411 inc edi
2412 dec ecx
2413 jnz mem_conv_xchg_loop ; Loop until all BYTES exchanged
2414mem_conv_done:
2415 Set_Byte_Gran EMM1_GSEL ; make sure EMM1_GSEL and
2416 Set_Byte_Gran EMM2_GSEL ; EMM2_GSEL are Byte Granulated
2417 ret
2418
2419mem_error_exit:
2420 cld
2421 mov byte ptr [bp.rAX+1], ah ; error code already set in ah
2422 ret
2423mem_valid_overlap:
2424 mov byte ptr [bp.rAX+1], VALID_OVERLAP
2425 ret
2426mem_no_error:
2427 mov byte ptr [bp.rAX+1], OK
2428 ret
2429
2430mem_inv_sub:
2431 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
2432 ret
2433mem_inv_region_len:
2434 mov byte ptr [bp.rAX+1], INVALID_REGION_LENGTH
2435 ret
2436mem_bad_memory_types:
2437 mov byte ptr [bp.rAX+1], INVALID_MEMORY_TYPE
2438 ret
2439mem_inv_overlap:
2440 mov byte ptr [bp.rAX+1], OVERLAPPING_EXCHANGE
2441 ret
2442;
2443; discard old ax,bx,source seg_page#,dest seg_page#
2444;
2445mem_mapping_error_4_pop:
2446 pop bx
2447mem_mapping_error_3_pop:
2448 pop bx
2449 pop bx
2450 pop bx
2451mem_mapping_error:
2452 mov eax, cr3 ; Always clear TLB, we may have
2453 mov cr3, eax ; mapped pages before an error
2454;
2455; all done, need to restore context of physical page frames
2456;
2457mem_exit:
2458 push fs ; get DGROUP back into DS
2459 pop ds
2460 get_FRS_Window BX
2461 pop word ptr [bx+2]
2462 pop word ptr [bx]
2463 cld ; string forward again
2464 jmp _set_windows ; remap all pages
2465
2466_MoveExchangeMemory endp
2467
2468
2469;******************************************************************************
2470;
2471; validate_for_Move_Or_Exchange
2472;
2473; This procedure is called by _MoveExchangeMemory to validate
2474; varies parameter on the memeory descriptor structure.
2475; It is called once for the source and once for the
2476; destination memory descriptor structures.
2477;
2478; ENTRY:
2479; CX = move length
2480; DS:DI = Move/Exchange memory descriptor data structure (source or dest)
2481; FS = MEMM's data segment
2482; EXIT:
2483; AH = Status (0 = No error) -- AL is preserved
2484;
2485; USES:
2486; DI, Flags
2487; AL and all other registers are preserved
2488;
2489;==============================================================================
2490
2491validate_for_Move_Or_Exchange PROC NEAR
2492
2493 push edx ; Used as temporary variable
2494 push eax
2495
2496 mov dl, [di.mem_memory_type]
2497 or dl, dl ; Q: Conventional memory?
2498 jz ME_Map_Conventional ; Y: Nothing to map
2499 cmp dl, 1 ; Q: Expanded memory?
2500 jne ME_Map_Inv_Mem ; N: Invalid memory type
2501 ; Y: EMM memory -- Must map it
2502 mov dx, [di.mem_handle] ; Get the handle
2503
2504 push ds ; validate_handle expect DS
2505 push fs ; points to dgroup
2506 pop ds
2507 Validate_Handle ME_Map_Inv_Handle ; check it
2508 pop ds
2509
2510 xchg bx, dx
2511 mov ax, fs:[bx.ht_count] ; EAX = # pages in handle
2512 xchg bx, dx
2513 cmp ax,[di.mem_initial_seg_page];Q: Is initial page in range
2514 jbe ME_Map_Invalid_log_page ; N: Error
2515 cmp [di.mem_initial_offset], 04000h; Q: Is offset unreasonable?
2516 jae ME_Map_Invalid_Offset ; Y: Error
2517
2518 movzx edx, [di.mem_initial_offset]
2519 add edx, ecx
2520 add edx, 16 * 1024 - 1 ; round up to nearest emm page boundary
2521 shr edx, 14 ; / 16K = # of emm pages
2522 add dx, [di.mem_initial_seg_page] ; last emm page of move/exchange
2523 cmp dx, ax
2524 ja ME_Map_Not_Enough_EMM ;Q: Is last page in range
2525 jmp short ME_Map_OK ; N: error
2526
2527ME_Map_Conventional:
2528 movzx edx, word ptr [di.mem_initial_seg_page]
2529 shl edx, 4
2530 movzx edi, word ptr [di.mem_initial_offset]
2531 add edx, edi ; EDX --> Conven mem to move/exch
2532 mov edi, edx ; Use EDI for test
2533 add edi, ecx ; EDI = Base + Move length
2534 cmp edi, 100000h ; Q: Is there wraparound?
2535 jae SHORT ME_Map_Inv_Wraparound ; Y: Error
2536 cmp fs:[_page_frame_pages], 0 ; Is there a page frame?
2537 je short No_EMM_Overlap ; no, no problem
2538 cmp edi, 0E0000h ; Q: Is move ABOVE EMM area?
2539 jae SHORT No_EMM_Overlap ; Y: That's not a problem
2540 movzx eax, fs:[PF_Base] ; Where page frame starts
2541 shl eax, 4
2542 cmp edi, eax ; Q: Does move run into EMM area?
2543 ja SHORT ME_Map_Inv_Overlap ; Y: Error
2544No_EMM_Overlap:
2545 ; N: Everything is okie dokie
2546ME_Map_OK:
2547 pop eax
2548 pop edx
2549 mov ah, OK
2550 ret
2551
2552ME_Map_Inv_Mem:
2553 pop eax
2554 pop edx
2555 mov ah, INVALID_MEMORY_TYPE
2556 ret
2557
2558ME_Map_Inv_Handle:
2559 pop ds
2560 pop eax
2561 pop edx
2562 mov ah, INVALID_HANDLE
2563 ret
2564
2565ME_Map_Invalid_log_page:
2566 pop eax
2567 pop edx
2568 mov ah, LOG_PAGE_RANGE
2569 ret
2570
2571ME_Map_Invalid_Offset:
2572 pop eax
2573 pop edx
2574 mov ah, INVALID_OFFSET
2575 ret
2576
2577ME_Map_Not_Enough_EMM:
2578 pop eax
2579 pop edx
2580 mov ah, INSUFFICIENT_EMM_PAGES
2581 ret
2582
2583ME_Map_Inv_Overlap:
2584 pop eax
2585 pop edx
2586 mov ah, CONVENTIONAL_EMM_OVERLAP
2587 ret
2588
2589ME_Map_Inv_Wraparound:
2590 pop eax
2591 pop edx
2592 mov ah, INVALID_WRAPAROUND
2593 ret
2594
2595validate_for_Move_Or_Exchange ENDP
2596
2597
2598 page
2599;***********************************************
2600;
2601; _AlternateMapRegisterSet - handle alternative register sets
2602;
2603; This routine switches the current register set or stores
2604; the current page mapping context to an external save area and/or
2605; restores the current page mapping context from an external save area.
2606;
2607; ENTRY: PROTECTED MODE ONLY
2608; AH = 5Bh = Alternate Map Register Set function
2609; AL = SUBFUNCTION CODE
2610; AL = 0 => Get Alternate Map Register Set
2611; AL = 1 => Set Alternate Map Register Set
2612; AL = 2 => Get and Set Alternate Map Register Set
2613; AL = 3 => Get Alternate Map Save Array size
2614; AL = 4 => Allocate Alternate Map Register Set
2615; AL = 5 => Deallocate Alternate Map Register Set
2616; AL = 6 => Enable DMA on Alternate Map Register Set
2617; AL = 7 => Disable DMA on Alternate Map Register Set
2618; See sub-functions for individual ENTRY registers
2619; SS:[EBP] -> regp stack frame
2620; DS = DGROUP
2621;
2622; EXIT: from individual sub-function or error with
2623; AH = INVALID_SUBFUNCTION
2624;
2625; USED: EAX,ESI
2626;
2627;***********************************************
2628Dword_Align _TEXT
2629_AlternateMapRegisterSet proc near
2630 cmp [_OSEnabled], OS_DISABLED
2631 jae short AMRS_NotAllowed ; Disabled by OS
2632 cmp al, 08h ; Valid sub-function?
2633 ja short AMRS_invalid
2634 cld ; Done for all sub-functions
2635 mov byte ptr [bp.rAX+1], OK ; Assume success!
2636 movzx esi, al ; get offset to function dispatch
2637 shl si, 1
2638 jmp CS:AMRS_map[si] ; go to relevant sub-function
2639 ; Return directly or to AMRS_exit...
2640AMRS_exit: ; Exit with AH already set
2641 ret
2642
2643AMRS_NotAllowed:
2644 mov byte ptr [bp.rAX+1], ACCESS_DENIED
2645 ret
2646
2647AMRS_invalid:
2648 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
2649 ret ; Error return!
2650
2651AMRS_bad_src:
2652 mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED
2653 ret ; Error return!
2654
2655AMRS_noDMA:
2656 mov byte ptr [bp.rAX+1], FRSET_NO_DMA
2657 ret ; Error return!
2658
2659Dword_Align _TEXT
2660AMRS_map dw _TEXT:AMRS_get
2661 dw _TEXT:AMRS_set
2662 dw _TEXT:AMRS_size
2663 dw _TEXT:AMRS_allocate
2664 dw _TEXT:AMRS_deallocate
2665 ; For now...
2666 dw _TEXT:AMRS_noDMA ; AMRS_DMAallocate
2667 dw _TEXT:AMRS_noDMA ; AMRS_DMAassign
2668 dw _TEXT:AMRS_noDMA ; AMRS_DMAdeassign
2669 dw _TEXT:AMRS_noDMA ; AMRS_DMAfree
2670
2671 page
2672;***********************************************
2673;
2674; AMRS_get - get the current 'fast' register set
2675;
2676; ENTRY: on stack
2677; SS:[EBP] -> regp stack frame
2678; DS = DGROUP
2679;
2680; EXIT: on stack
2681; BL = register set number,
2682; state stored in client's buffer if BL == 0
2683; ES:SI set to point to client's buffer
2684; return code set on stack
2685;
2686; USED: EAX, EBX
2687;
2688; DESCRIPTION: This function returns the current register set number.
2689; If it is zero, it returns the save area previously specified
2690;
2691;-----------------------------------------------
2692Dword_Align _TEXT
2693AMRS_get:
2694 mov al, [CurRegSetn] ; Get current set number
2695 mov byte ptr [bp.rBX], al ; to be picked up later
2696 or al, al
2697 jz short AMRS_get0
2698 ret ; non-zero - all done
2699AMRS_get0: ; Echo save area address
2700 movzx eax, [EMM_savES] ; saved ES for reg set 0
2701 mov word ptr [bp.rES], ax
2702 movzx edi, [EMM_savDI] ; saved DI for reg set 0
2703 mov word ptr [bp.rDI], di
2704 or ax, ax
2705 jnz short AMRS_get2 ; got dest addr
2706 or di, di
2707 jz short AMRS_get1 ; not specified yet
2708AMRS_get2:
2709 xor dx, dx
2710 Set_EMM_GDT EMM1_GSEL
2711 mov es, bx ; ES:DI <-- temp store
2712 Get_FRS_window SI ; Get pointer to current window
2713 movzx eax, [_cntxt_pages] ; how many pages
2714 stosw ; save size
2715 mov ecx, eax
2716 shr ecx, 1 ; convert to dwords
2717 rep movsd ; save the map
2718AMRS_get1:
2719 ret
2720
2721 page
2722;***********************************************
2723;
2724; AMRS_set - set the current 'fast' register set
2725;
2726; ENTRY: BL = register set number
2727; on stack
2728; if BL == 0
2729; ES:DI -> buffer containing mappings for register set 0
2730; SS:[EBP] -> regp stack frame
2731; DS = DGROUP
2732;
2733; EXIT: return code set on stack
2734;
2735; USED: EAX, EBX, ECX, EDX, ESI, EDI
2736;
2737; DESCRIPTION: This function sets the current register set number.
2738; If it is zero, it uses the save area specified in ES:DI.
2739;
2740;-----------------------------------------------
2741Dword_Align _TEXT
2742AMRS_set:
2743 cmp bl, FRS_COUNT ; Validate new Reg Set
2744 jae AMRS_inv_FRS
2745 movzx eax, bl
2746 imul eax, size FRS_struc
2747 xchg ax, bx
2748 lea bx, FRS_array[bx] ; Get pointer to the new Reg Set
2749 cmp [bx.FRS_alloc], 0 ; Make sure it is allocated
2750 xchg ax, bx
2751 je AMRS_undef_FRS ; unallocated, go complain
2752
2753 cmp bl, 0 ; New reg set 0?
2754 je short AMRS_set0 ; yes, always set context
2755 cmp bl, [CurRegSetn] ; Setting the same reg set?
2756 je AMRS_exit ; yes, just return
2757AMRS_set0: ; Now set up new reg set
2758 mov word ptr [CurRegSet], ax ; Set Current reg. set Offset
2759 mov [CurRegSetn], bl
2760
2761 or bl, bl ; Real register set?
2762 jne _set_windows ; yes, go deal with it
2763 ; no, deal with reg set 0
2764 mov ax, word ptr [bp.rES] ; Pick up user's pointer
2765 mov [EMM_savES], ax ; and save for AMRS_get
2766 mov dx, word ptr [bp.rDI]
2767 mov [EMM_savDI], dx ; AX:DX <-- regs cntxt restore area
2768 push ax
2769 or ax, dx
2770 pop ax
2771 jz _set_windows ; AX:DX == 0:0 implies no save area
2772
2773 ; construct GDT entry using EMM1_GSEL to access user's FRS buffer
2774 ;
2775 push es
2776 Set_EMM_GDT EMM1_GSEL
2777 pop es
2778
2779 mov fs, bx ; FS:SI <-- FRS buffer
2780 xor si, si
2781 lods word ptr fs:[si] ; get saved count
2782 movzx ecx, [_cntxt_pages] ; what it should be
2783 cmp ax, cx ; Sensible count?
2784 jne _set_windows ; no, restore last context
2785 Get_FRS_window DI
2786 shr ecx, 1 ; size in dwords
2787 push ds ; xchg ds,fs
2788 push fs
2789 pop ds
2790 pop fs ; use DS as default seg. reg.
2791 rep movsd
2792 push ds
2793 push fs
2794 pop ds
2795 pop fs
2796 jmp _set_windows ; set up mappings
2797
2798 page
2799;***********************************************
2800;
2801; AMRS_size - get the size of the register set 0 save area
2802;
2803; ENTRY:
2804; SS:[EBP] -> regp stack frame
2805; DS = DGROUP
2806;
2807; EXIT: return code set on stack
2808; DX = size of the save area
2809;
2810; USED: none
2811;
2812; DESCRIPTION: This function returns the size of the save area used
2813; for register set 0.
2814;
2815;-----------------------------------------------
2816AMRS_size:
2817 movzx eax, [_cntxt_bytes] ; Previously calculated value
2818 mov word ptr [bp.rDX], ax
2819 ret
2820
2821 page
2822;***********************************************
2823;
2824; AMRS_allocate - allocate a fast register set
2825;
2826; ENTRY:
2827; SS:[EBP] -> regp stack frame
2828; DS = DGROUP
2829;
2830; EXIT: return code set on stack
2831; BL = register set number
2832;
2833; USED: EBX, ESI
2834;
2835; DESCRIPTION: This function allocates a free register set.
2836;
2837;-----------------------------------------------
2838AMRS_allocate:
2839 cmp [FRS_free], 0 ; See if any are free
2840 je short AMRS_noRS ; no, none available
2841 ; Search for first free set
2842 dec [FRS_free] ; We are going to take one
2843 lea di, [FRS_array] ; Start of FRS structures
2844 xor bl, bl ; FRS number
2845AMRS_search:
2846 cmp [di.FRS_alloc], 0 ; This one free?
2847 je short AMRS_foundRS ; yes, bl has the number
2848 add di, size FRS_struc ; on to the next one
2849 inc bl
2850 cmp bl, FRS_COUNT ; Safety... should never fail
2851 jb short AMRS_search
2852
2853 mov byte ptr [bp.rAX+1], EMM_SW_MALFUNCTION ; Honesty...
2854 ret
2855
2856AMRS_foundRS:
2857 mov [di.FRS_alloc], 1 ; Allocate it
2858 Get_FRS_Window SI
2859 lea di, [di.FRS_Window]
2860 movzx ecx, [_cntxt_pages]
2861 shr ecx, 1
2862 rep movsd ; Initialise to current mapping
2863 mov byte ptr [bp.rBX], bl ; Return the number
2864 ret
2865
2866AMRS_noRS: ; None free; return error
2867 mov byte ptr [bp.rAX+1], NO_MORE_FRSETS
2868 ret
2869
2870 page
2871;***********************************************
2872;
2873; AMRS_deallocate - deallocate a fast register set
2874;
2875; ENTRY: BL = register set to deallocate
2876; SS:[EBP] -> regp stack frame
2877; DS = DGROUP
2878;
2879; EXIT: return code set on stack
2880;
2881; USED: EAX
2882;
2883; DESCRIPTION: This function deallocates a register set.
2884;
2885;-----------------------------------------------
2886AMRS_deallocate:
2887 or bl, bl
2888 jz AMRS_exit ; Deallocating 0 is ignored
2889 cmp bl, [CurRegSetn] ; Can't deallocate current set
2890 je short AMRS_undef_FRS
2891 cmp bl, FRS_COUNT
2892 jae short AMRS_undef_FRS ; Invalid Register set
2893 movzx eax, bl
2894 imul eax, size FRS_struc ; Offset into array
2895 xchg ax, bx
2896 cmp FRS_array[bx.FRS_alloc], 0 ; Paranoid...
2897 xchg ax, bx
2898 je short AMRS_undef_FRS ; Not allocated, complain
2899 xchg ax, bx
2900 mov FRS_array[bx.FRS_alloc], 0 ; Mark it free
2901 xchg ax, bx
2902 inc [FRS_free] ; one more set free
2903 ret
2904
2905AMRS_Inv_FRS:
2906AMRS_undef_FRS:
2907 mov byte ptr [bp.rAX+1], FRSET_UNDEFINED
2908 ret
2909
2910_AlternateMapRegisterSet endp
2911
2912
2913 page
2914;******************************************************************************
2915; _Get_Key_Val - use the timer to get a random number for OSDisable Key
2916;
2917; ENTRY DS, ES = DGROUP selectors
2918;
2919; STACK
2920;
2921; EXIT EAX has randomish number
2922;
2923; USES Flags, EAX, EDX
2924;
2925;------------------------------------------------------------------------------
2926_Get_Key_Val proc near
2927 call Get_Counter_Value ; (Who cares about the junk in
2928 mov dx, ax ; the high words...?)
2929 call Get_Counter_Value ; Likely to be very close
2930 mul edx ; Mess it all up!
2931 ret
2932
2933_Get_Key_Val endp
2934
2935;******************************************************************************
2936;
2937; NAME:
2938; Get_Counter_Value
2939;
2940; DESCRIPTION:
2941; Returns the current system timer counter value
2942;
2943; ENTRY:
2944; Assumes nothing
2945;
2946; EXIT:
2947; AX = Current counter value (High word of EAX NOT CHANGED)
2948;
2949; USES:
2950; Flags
2951;
2952;------------------------------------------------------------------------------
2953
2954Get_Counter_Value PROC NEAR
2955
2956System_Clock_Port EQU 40h
2957Sys_Clock_Ctrl_Port EQU 43h
2958
2959Latch_Counter EQU 0
2960
2961 mov al, Latch_Counter
2962 out Sys_Clock_Ctrl_Port, al ; Latch the timer counter
2963 jmp $+2
2964 in al, System_Clock_Port ; Read the LSB
2965 mov ah, al
2966 jmp $+2
2967 in al, System_Clock_Port ; Read the MSB
2968 xchg ah, al ; AX = Counter value
2969 ret
2970
2971Get_Counter_Value ENDP
2972
2973
2974_TEXT ENDS
2975END
2976
2977
2978 \ No newline at end of file