2 ;******************************************************************************
3 title EMMP
- EMM protected mode functions
4 ;******************************************************************************
6 ; (C) Copyright MICROSOFT Corp. 1986, 1987
8 ; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver
9 ; EMMLIB.LIB - Expanded Memory Manager Functions Library
11 ; Module: EMMP - WIN386 EMM functions
17 ;******************************************************************************
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)
27 ;******************************************************************************
29 ; Functional Description:
30 ; This file contains the EMM functions which require greatest efficiency.
32 ;******************************************************************************
33 .lfcond
; list false conditionals
48 ;******************************************************************************
50 ;******************************************************************************
54 public _RestorePageMap
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
71 ;******************************************************************************
72 ; E X T E R N A L R E F E R E N C E S
73 ;******************************************************************************
77 extrn _source_addr
:near
80 extrn SetDescInfoResident
:near
81 extrn SegOffTo24Resident
:near
89 ;extrn _regp:dword ; pointer to entry stack frame
91 ;extrn Cur_VM_Handle:dword
94 ;extrn _MaxEMMSize:dword
95 ;extrn _VEMMD_PgFrame:word
96 ;extrn _VEMMD_Last_Offset:word
98 extrn _OSEnabled
:dword
99 ;extrn NullAvailPTE:dword
100 ;extrn NullUnavailPTE:dword
102 extrn _total_pages
:word ; total # of EMM pages in system
105 ; table of offsets into in to the first page table
106 ; for user logical emm page map
108 extrn _page_frame_base
:dword
112 extrn _mappable_pages
:word ; table of mappable pages
113 extrn _mappable_page_count
:word ; how many in the table
114 extrn _page_frame_pages
:word ; how many in the page frame
115 extrn _physical_page_count
:word ; number of physical pages
116 extrn _VM1_EMM_Pages
:word ; pages not in the page frame
117 ;extrn _VM1_EMM_Offset:word ; offset of these in a context
118 extrn _cntxt_pages
:byte ; number of pages in a context
119 extrn _cntxt_bytes
:byte ; number of bytes in a context
123 ; table of indexes into the above - maps segment to physical page
125 extrn EMM_MPindex
:byte
128 ; ptr to table of emm page # for each handle's logical pages.
133 ; handle data structure
135 extrn _handle_table
:word
136 extrn _handle_table_size
:word
139 ; save area for handles
144 ; Save area and misc variables for 4.0 function 27
149 extrn CurRegSetn
:byte
151 extrn CurRegSet
:dword
158 ;******************************************************************************
160 ;******************************************************************************
162 assume
cs:_TEXT
, ds:DGROUP
, ss:DGROUP
165 ;***********************************************
169 ; ENTRY: Sel,Off - Selector:offset to be normalize
170 ; protected mode only
172 ; EXIT: Sel:Off normalized
175 ; NOTE: Sel and Off should not be BX,DX,AX
177 ;***********************************************
178 normalize
MACRO Sel
,Off
185 push Sel
; save for later reload
186 mov bx, Sel
; get Selector into BX
188 push GDTD_GSEL
; ES -> GDT
191 and bl,SEL_LOW_MASK
; mask off mode bits
192 mov dx,es:[bx+2] ; AL:DX <-- base address
194 add dx,Off
; adjust base address
196 mov es:[bx+2],dx ; store it back
198 xor Off
, Off
; new Offset
200 pop Sel
; reload Selector (flush cache)
209 ;***********************************************
211 ; get_space_from_stack
213 ; ENTRY: Len - amount of space requested
215 ; EXIT: Len space allocated on ES:DI (client's stack)
216 ; ES:DI - points to First element on top of stack
220 ;***********************************************
221 Get_space_from_stack
MACRO Len
226 ;***********************************************
228 ; release_space_to_stack
230 ; ENTRY: Len - amount of space to be release
232 ; EXIT: Len space released from client's stack (DS:SI)
236 ;***********************************************
237 release_space_to_stack
MACRO Len
242 ;***********************************************
244 ; Set_EMM_GDT - set GDT entry of selector with some fix infos
245 ; like access and limit
247 ; ENTRY: Handle - selector of GDT to modify
249 ; EXIT: GDT entry set
252 ; USES: ax,bx,cx,dx,es
254 ;***********************************************
255 Set_EMM_GDT
MACRO handle
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
262 pop es ; ES:0 <-- GDT
263 call SetDescInfoResident
; set GDT entry
266 ;***********************************************
268 ; Set_Byte_Gran - set granularity of GDT entry to byte
270 ; ENTRY: Handle - selector of GDT to modify
272 ; EXIT: Granularity bit clear in GDT
277 ;***********************************************
278 Set_Byte_Gran
MACRO handle
280 mov bx, handle
; GDT selector
282 pop es ; ES:0 <-- GDT
283 and byte ptr es:[bx+6],NOT R_GRAN
; clear gran bit
286 ;***********************************************
288 ; Set_Page_Gran - set granularity of GDT entry to page
290 ; ENTRY: Handle - selector of GDT to modify
292 ; EXIT: Granularity bit set in GDT
297 ;***********************************************
298 Set_Page_Gran
MACRO handle
300 mov bx, handle
; GDT selector
302 pop es ; ES:0 <-- GDT
303 or byte ptr es:[bx+6], R_GRAN
; set gran bit
306 ;***********************************************
308 ; Get_FRS_window - get pointer to Fast Register Set window
310 ; ENTRY: Reg - points to an FRS_struc
312 ; EXIT: Reg - points to FRS_window entry in the structure
316 ;***********************************************
317 Get_FRS_window
MACRO Reg
319 mov Reg
, word ptr [CurRegSet
] ; just offset (assume dgroup)
320 add Reg
, FRS_window
; points to FRS window entries
324 ;**********************************************************************
326 ; map_EMM_page - set page table entries for a page frame
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
333 ;***********************************************
334 map_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#)
347 ; construct pointer to physical address of the first
348 ; 386 page and move it into eax
350 mov cx,bx ; emm page# in cx to save in FRS later
351 shl bx,2 ; bx <-- pft index * 4
354 ; continue calulation of pte
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
361 pop bx ; bx <-- physical page index
364 ; save mapping (offset into _pft386 struct) into
365 ; current FRS's physical page entry
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
373 ; construct pointer to physical address of
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
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
389 pushf ; preserve direction flag
392 stosd ; store 1st page table entry
393 add eax,P_SIZE
; eax <-- next address
395 stosd ; store 2nd page table entry
396 add eax,P_SIZE
; eax <-- next address
398 stosd ; store 3rd page table entry
399 add eax,P_SIZE
; eax <-- next address
401 stosd ; store 4th page table entry
403 popf ; restore direction flag
417 ;**********************************************************************
419 ; unmap_page - unmap a physical page
421 ; ENTRY: AX - physical page number to be unmapped
424 ;**********************************************************************
427 ; find FRS entry for the physical page and
428 ; update it as unmapped
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
440 ; find out the segment of the physical page
442 mov cx, [_physical_page_count
]
443 mov di, offset DGROUP
:_mappable_pages
445 cmp ax, [di].mappable_pg
447 add di, size Mappable_Page
450 jmp short unmap_page_exit
; non-found : just return
453 mov bx, [di].mappable_seg
; get segment into bx first
456 ; construct pointer to physical address of
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
468 movzx eax, bx ; EAX <-- segment of physical page
470 and ax,0F000H ; clear the low 12 bits
471 or ax,P_AVAIL
; page ctl bits <-- user,present,write
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
480 stosd ; unmap pte of page frame
498 ;**********************************************************************
500 ; map_page - map a logical page to a phyical page
502 ; ENTRY: AX - physical page number to be mapped
503 ; BX - logical page number to map
504 ; DX - handle pointer (do not destroy)
507 ;**********************************************************************
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
516 cmp dx,[bx.ht_count
] ;Q: valid logical page# ?
518 jae short mp_inv_log
; N: invalid page number
519 ; Y: continue with it
522 add dx,[bx.ht_index
] ; dx <-- index into _emm_page
524 shl bx,1 ; bx <-- index * 2
526 mov bx,[bx] ; bx <-- emm page#
528 jc short mp_inv_emm_page
; emm page range error
537 mov byte ptr [bp.rAX+1],SOURCE_CORRUPTED
542 mov byte ptr [bp.rAX+1],PHYS_PAGE_RANGE
547 mov byte ptr [bp.rAX+1],LOG_PAGE_RANGE
554 ;***********************************************
556 ; _MapHandlePage - map a handle's page
558 ; This routine maps 4 386 pages into the address
561 ; ENTRY: PROTECTED MODE ONLY
562 ; AH = 44h = map handle page function #
563 ; AL = window # (physical page #)
564 ; BX = logical page #
566 ; REGS on STACK: SI = not used by this function
567 ; SS:[EBP] -> regp stack frame
570 ; EXIT: page table entries set up
571 ; AH = status of this function
572 ; = EMM_HW_MALFUNCTION if entry in real/virtual mode.
574 ; USED: EAX, EBX, EDX, EDI
576 ;***********************************************
579 _MapHandlePage proc
near
581 Validate_Handle
<short mhp_inv_handle
>
583 mov byte ptr [bp.rAX+1],OK
; Assume success!
584 movzx eax, al ; Physical page
585 movzx ebx, bx ; Logical page
589 mov cr3, eax ; Flush old mapping now
592 jmp map_page
; Common page mapping code
595 mov byte ptr [bp.rAX+1], INVALID_HANDLE
601 ;***********************************************
603 ; _SavePageMap - save current page mapping
605 ; This routine save the current page mapping context for a handle.
607 ; ENTRY: PROTECTED MODE
608 ; AH = 07h = save page map function #
610 ; REGS on STACK: SI = not used by this function
611 ; SS:[BP] -> regp stack frame
614 ; EXIT: current state saved
615 ; AH = status of this function
617 ; USED: AX,BX,CX,DX,SI,DI
619 ;***********************************************
622 _SavePageMap proc
near
623 cmp [_page_frame_pages
], 4
624 jb short srpm_nopf
; no page frame
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
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
644 mov byte ptr [bp.rAX+1],OK
; ok return
648 mov byte ptr [bp.rAX+1],MAP_PREV_SAVED
651 srpm_inv_handle: ; Shared error returns
652 mov byte ptr [bp.rAX+1],INVALID_HANDLE
656 mov byte ptr [bp.rAX+1], EMM_HW_MALFUNCTION
; No page frame!!!
662 ;***********************************************
664 ; _RestorePageMap - restore handle's saved page mapping
666 ; This routine restores the current page mapping context
667 ; from a handle's save area.
669 ; ENTRY: PROTECTED MODE ONLY
670 ; AH = 08h = restore page map function #
672 ; REGS on STACK: SI = not used by this function
673 ; SS:[BP] -> regp stack frame
676 ; EXIT: current state restored
677 ; AH = status of this function
679 ; USED: AX,BX,CX,DX,SI,DI
681 ;***********************************************
684 _RestorePageMap proc
near
685 cmp [_page_frame_pages
], 4
686 jb short srpm_nopf
; no page frame
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
699 mov byte ptr [bp.rAX+1],OK
; Assume success
700 mov [si].s_handle
,NULL_HANDLE
; null handle's save area
702 lea si,[si].s_map
; SI -> handle's save area
703 Get_FRS_window
DI ; Get pointer to current window
705 pop es ; ES <-- DGROUP
707 movsd ; restore 4 words
708 movsd ; Lim 3.2 has only 4 page frames
709 jmp _set_windows
; Restore mapping
712 mov byte ptr [bp.rAX+1],NO_MAP_SAVED
718 ;***********************************************
720 ; _GetSetPageMap - get/set page map to/from external save area
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.
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
738 ; EXIT: current state saved / restored
739 ; AH = status of this function
741 ; USED: BX,CX,DX,SI,DI
743 ;***********************************************
745 _GetSetPageMap proc
near
747 cmp al,GSPM_GET
;Q: get page map subfunction ?
748 je short _get_map
; Y: get it
750 cmp al,GSPM_SET
;Q: set page map subfunction ?
751 je _set_map
; Y: set it
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
759 cmp al, GSPM_SIZE
;Q: return map size subfunction ?
760 jne short gspm_inv_subfun
; N: return invalid subfunction
762 mov al, [_cntxt_bytes
] ; size of map
763 mov ah, OK
; ok return
764 mov word ptr [bp.rAX], ax
768 mov byte ptr [bp.rAX+1],INVALID_SUBFUNCTION
772 mov byte ptr [bp.rAX+1],INVALID_FUNCTION
778 ;***********************************************
780 ; _get_map - save current mapping register state to external area
783 ; clients ES:DI -> client's buffer for state
784 ; SS:[BP] -> regp stack frame
787 ; EXIT: state stored in client's buffer
788 ; return code set on stack
790 ; USED: AX,BX,CX,DX,SI,DI,ES
792 ; DESCRIPTION: This function saves the current mapping
793 ; into the save area specified.
795 ;***********************************************
800 call _dest_addr
; DX:AX ptr for client's buff
802 mov di,ax ; ES:DI pts to clients buffer
804 Get_FRS_window
SI ; Get pointer to current window
805 movzx ecx, [_cntxt_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
816 ;***********************************************
818 ; _set_map - restore mapping register state
821 ; clients DS:SI -> client's buffer containing state to restore
822 ; SS:[BP] -> regp stack frame
825 ; EXIT: state restored from client's buffer
826 ; return code set on stack
828 ; STC => error occurred
830 ; USED: EAX,BX,CX,DX,SI,DI,ES
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
838 ;***********************************************
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
846 pop es ; use ES to address data
849 call _source_addr
; DX:AX ptr for client's buff
851 xchg si,ax ; DS:SI pts to clients buffer
855 movzx ecx, es:[_cntxt_pages
] ; number of words in mapping
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
862 pop ds ; DS <-- DGROUP
863 jmp _set_windows
; make it effective
866 mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED
875 ;***********************************************
877 ; _set_windows - re-map all mapped physical pages
879 ; This routine maps all mapped 386 pages of the EMM page frame into the
880 ; linear address space for the page frame.
882 ; ENTRY: PROTECTED MODE ONLY
884 ; SS:[BP] -> regp stack frame
886 ; EXIT: page tables changed to map these pages.
887 ; _current_map contents initialized.
890 ; FLAGS, EAX, EBX, ECX, ESI, EDI
892 ;***********************************************
894 _set_windows proc
near
896 xor ax, ax ; start from PHYS page 0
897 Get_FRS_Window
SI ; SI <-- current FRS map
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
906 shl di, 2 ; SI <-- _pft386 offset of emm page
908 cmp dword ptr [di], 0 ; pte not mapped ?
909 je sw_corrupt
; Y: error
911 call map_EMM_page
; map a page
915 cmp ax, [_physical_page_count
]
916 jb sw_loop
; next page
919 mov cr3, eax ; flush TLB
926 jmp short sw_done_page
929 mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED
936 ;*******************************************************************************
938 ; LIM 4.0 EXTRAS for Windows
940 ;*******************************************************************************
942 ;***********************************************
944 ; _GetSetPartial - get/set partial page map to/from external save area
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.
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
960 ; EXIT: current state saved / restored
961 ; AH = status of this function
963 ; USED: BX,CX,DX,SI,DI
965 ;***********************************************
966 _GetSetPartial proc
near
970 call _source_addr
; uses AX, DX
973 call _dest_addr
; uses AX, DX
977 lods word ptr fs:[si]
978 stosw ; Save count in save area
980 jz gsppm_ok
; nothing to do
983 mov dx, [_mappable_page_count
]
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
992 mov al, EMM_MPindex
[bx] ; convert to physical page
993 cmp al, -1 ; does it exist
997 lea ax, _mappable_pages
[bx]
999 mov bx, [bx.mappable_seg
] ; segment for this page
1001 jne gsppm_inv_seg
; must match exactly
1003 movzx ebx, [bx.mappable_pg
] ; the physical page
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
1012 stosw ; and current mapping
1016 mov byte ptr [bp.rAX+1], OK
1022 ; Set Partial Page Map
1023 call _source_addr
; uses AX, DX
1026 movzx ecx, word ptr fs:[si] ; Get count from save area
1028 jecxz gsppm_ok
; Zero count, do nothing
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
1035 movzx eax, word ptr fs:[si] ; Get Physical page
1036 cmp ax, [_mappable_page_count
]
1039 movzx esi, word ptr fs:[si+2] ; Get mapping (emm page#)
1042 add di,ax ; di <-- current FRS phy page
1043 mov [di], si ; Save new mapping
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
1050 mov bx, si ; bx <-- emm page#
1056 add esi, 4 ; Next page to map
1058 mov eax, cr3 ; Flush TLB
1063 call unmap_page
; with ax <-- phys page#
1064 jmp gsppm_set_done
; On to next page
1069 mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED
1075 cmp bx, [_mappable_page_count
] ; # of page frames
1076 ja short gsppm_inv_phys
1077 shl bx, 2 ; Size = pages * 4 + 2
1079 mov byte ptr [bp.rAX], bl
1083 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
1088 mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
1094 ;***********************************************
1096 ; _MapHandleArray - map an array of a handle's pages
1098 ; This routine maps the physical pages according to
1099 ; an array of mappings.
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
1107 ; REGS on STACK DS:SI = array of mappings
1108 ; SS:[BP] -> regp stack frame
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
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.
1123 ; USED: AX,BX,DX,SI,DI,FS
1125 ;***********************************************
1127 _MapHandleArray proc
near
1130 call _source_addr
; DX:AX <-- mapping array
1133 pop dx ; FS:SI <-- mapping array
1135 MapHandleArray_Entry_2:
1136 cmp al, 1 ; Q: Is subfunction 0 or 1?
1137 ja mha_inv_sub
; N: Invalid subfunction
1139 Validate_Handle
<mha_inv_handle
>
1141 mov byte ptr [bp.rAX+1], OK
; Assume success
1143 jecxz short mha_exit
; none to do, just return
1145 or al, al ; which subfunction?
1146 jnz short mha_sub1
; subfunction 1?
1149 ; Subfunction 0: array contains logical and physical
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
1162 ; Subfunction 1: array contains logical page number and
1163 ; segment numbers corresponding to the
1164 ; desired physical pages.
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
1187 mov eax, cr3 ; Always clear TLB, we may have
1188 mov cr3, eax ; mapped pages before an error
1192 mov byte ptr [bp.rAX+1], INVALID_HANDLE
1195 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
1198 mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
1201 _MapHandleArray endp
1206 ;***********************************************
1208 ; _AlterMapAndJump - map an array of a handle's pages and Jump to a
1209 ; a specified address
1211 ; This routine maps pages using the MapHandleArray procedure and jumps
1212 ; to the specified address
1214 ; ENTRY: PROTECTED MODE ONLY
1215 ; AL = Mapping method -- 0 = Physical pages, 1 = Segments
1218 ; REGS on STACK -- DS:SI -> Map and Jump structure
1219 ; SS:[BP] -> regp stack frame
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
1228 ; USED: AX,BX,CX,SI,DI,FS,GS
1230 ;**********************************************
1232 _AlterMapAndJump PROC
NEAR
1236 call _source_addr
; DX:AX <-- map & jump struct
1238 xchg si, ax ; GS:SI <-- map & jump struct
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
1254 mov ah, byte ptr [bp.rAX+1]
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
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)
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
1270 ; tell EMMpEntry to patch CS:IP onto its' iretd stack frame
1272 or word ptr [bp.PFlag
], PFLAG_PATCH_CS_IP
1273 AMJ_Error: ; Do the jump
1276 _AlterMapAndJump ENDP
1280 ;***********************************************
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
1288 ; ENTRY: PROTECTED MODE ONLY
1289 ; AL = Subfunction -- 0 = Map phys pages, 1 = Map segs, 2 = Frame size
1291 ; REGS on STACK DS:SI = Map and Call structure
1292 ; SS:[BP] -> regp stack frame
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.
1302 ; USED: AX,BX,CX,DX,SI,DI
1304 ;***********************************************
1306 _AlterMapAndCall PROC
NEAR
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
1314 call _source_addr
; DX:AX <-- map & call structure
1316 xchg si, ax ; GS:SI <-- map & call structure
1319 ; check new and old map's length
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
1329 ; get client's SS:ESP so we can push stuffs on it
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
1338 push ax ; client's Stack Segment
1339 Set_EMM_GDT EMM2_GSEL
1340 push bx ; client's Stack Selector
1342 ; get CS's Base to "push" on stack for later retf from client
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
1352 or dh, al ; get the segment value
1353 mov bx, dx ; into BX
1355 pop es ; ES:DI <-- client's SS
1356 pop cx ; CX <-- Client's stack Segment
1361 ; save client's stack segment and target address on stack
1362 ; cause they (CX and EMM1_GSEL) get destroy
1365 push word ptr gs:[si].mac_target_address
+2
1366 push word ptr gs:[si].mac_target_address
1368 ; On the Client's stack :
1370 ; +-----------------+
1372 ; +-----------------+
1374 ; +-----------------+
1376 ; +-----------------+
1377 ; | EMM_rEntry's CS |
1378 ; +-----------------+
1379 ; | EMM_rEntry's IP | <-- "SS:ESP" (ES:EDI)
1380 ; +-----------------+
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)
1386 push es:[di+2] ; EMM_rEntry's CS
1387 push es:[di] ; EMM_rEntry's IP
1388 add di, 2 * 2 ; "pop"
1390 ; save old map on stack
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
1397 shr cx, 2 ; CX back to length in bytes
1400 push di ; save postion of stack
1405 push cx ; save #pages
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]
1411 Set_EMM_GDT USER1_GSEL
1413 mov ds, bx ; DS:0 <-- map array
1417 stosb ; store length of map
1419 shl cx, 1 ; move word
1422 pop dx ; restore handle
1423 pop bx ; restore Segment of client Stack
1424 pop ax ; restore subfunction
1429 ; save FRS context on stack
1431 movzx ecx, [_cntxt_bytes
]
1432 get_space_from_stack
CX ; ES:DI <-- space on stack
1436 get_FRS_Window
SI ; DS:SI <-- mapping context
1437 shr ecx, 1 ; move words
1449 push di ; save "stack pointer"
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]
1456 Set_EMM_GDT USER1_GSEL
1458 mov fs, bx ; FS:0 <-- map array
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
1468 mov bh, byte ptr [bp.rAX+1]
1473 ; save needed registers, return address and call address
1477 dec di ; "pre-decrement" stack
1478 std ; store backward
1479 stosw ; subfunction code
1480 mov ax, dx ; EMM handle
1484 mov ax, bx ; CS for return from called code
1486 mov ax, offset AMC_return_address
; IP for return from called code
1487 mov es:[di], ax ; "push" without decrement "SP"
1490 ; NOW build a iretd stack frame to go back to virtual mode
1492 pop ax ; no error : we can throw
1493 pop ax ; away EMM-rEntry's CS:IP now
1495 pop ax ; target address
1496 pop dx ; target address+2
1497 pop cx ; Stack Segment
1500 push word ptr [bp].rGS
1502 push word ptr [bp].rFS
1504 push word ptr [bp].rDS
1506 push word ptr [bp].rES
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
1515 push dx ; target address+2
1517 push ax ; target address
1519 ; restore registers context from stack frame
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
1529 ; return to virtual mode via iretd with calling address on stack
1535 ; mapping error occur : restore state and exit
1537 movzx ecx, [_cntxt_bytes
]
1539 pop ds ; DS:SI <-- stack
1541 release_space_to_stack
CX ; DS:SI <-- space on stack
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
1550 get_space_from_stack
CX ; ES:DI <-- space on stack
1551 pop es:[di] ; restore EMM_rEntry's CS:IP
1554 pop ax ; discard target addr etc
1560 AMC_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
1569 mov word ptr [bp.rBX], ax
1573 mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
1577 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
1580 _AlterMapAndCall ENDP
1583 ;******************************************************************************
1585 ; AMC_return_address -- Return from procedure called through a Map & Call
1587 ; NOTE: MapHandleArray will only access AH on the stack and so the
1588 ; TSTF stack frame will work properly for this procedure.
1590 ; ENTRY: VTFOE frame,EBP,EBX,ESI are on the stack
1592 ;******************************************************************************
1594 AMC_return_address proc
far
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
1603 ; In Protected Mode Now
1605 pushad ; saves all regs
1606 mov ax, sp ; saves stack frame address
1607 mov [_regp
], ax ; to _regp
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
1613 Set_EMM_GDT EMM2_GSEL
1614 mov fs, bx ; FS:SI <-- client's Stack
1618 ; "pop" back registers on "stack" FS:SI
1625 mov dx, ax ; EMM handle
1626 lodsw ; subfunction code
1628 ; restore mapping context
1634 get_FRS_Window
DI ; ES:DI <-- FRS mapping context regs
1636 pop ds ; DS:SI <-- client's stack
1638 mov cl, ES:[_cntxt_bytes
]
1639 shr cx, 1 ; move word
1648 pop ax ; subfunction code
1652 mov bp, [_regp
] ; setup pushad frame first
1654 pop ds ; DS <-- DGROUP
1655 call MapHandleArray_Entry_2
; map it
1659 shl cx, 2 ; 4 bytes per mapping
1660 release_space_to_stack
CX
1662 ; saves CS:IP (BX:CX) on iretd stack frame
1665 pop ds ; DS <-- Client's Stack
1668 mov word ptr [bp.VTFOE
+VMTF_EIP
], ax
1670 mov word ptr [bp.VTFOE
+VMTF_CS
], ax
1672 mov word ptr [bp.VTFOE
+VMTF_EFLAGS
], ax
1673 mov word ptr [bp.VTFOE
+VMTF_EFLAGShi
], PFLAG_VM
1676 ; save client's new stack pointer
1678 mov dword ptr [bp.VTFOE
.VMTF_ESP
], esi
1683 add esp, 4 ; discard "error" code
1691 AMC_return_address endp
1694 ;******************************************************************************
1696 ; _MoveExchangeMemory
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.
1704 ; ENTRY: PROTECTED MODE ONLY
1705 ; AL = Subfunction -- 0 = Copy, 1 = Exchange
1707 ; REGS on STACK DS:SI = Move/Exchange structure
1708 ; SS:[BP] -> regp stack frame
1713 ; USES: AX, BX, CX, DX, SI, DI
1715 ;==============================================================================
1720 ; check/validate source/dest and overlay,etc
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
1726 ; * setup source and dest memory pointers
1728 ; if (source.type == conv.mem)
1729 ; DS:SI = source.initial.segment:source.initial.offset
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
1736 ; if (dest.type == conv.mem)
1737 ; ES:DI = dest.initial.segment:dest.initial.offset
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
1746 ; * DS:SI - addresses source data area
1747 ; * ES:DI - addresses dest buffer area
1751 ; for (total.byte.to.process != 0) {
1753 ; * find out how many bytes to process (least bytes to process)
1755 ; if (source.type == conv.mem)
1756 ; bytes.to.process = 0x4000 - dest.offset
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
1764 ; bytes.to.process = 0x4000 - max(source.offset, dest.offset)
1767 ; * adjust the total
1769 ; if (bytes.to.process > totol.bytes.to.process)
1770 ; bytes.to.process = totol.bytes.to.process
1772 ; total.bytes.to.process -= bytes.to.process
1775 ; * do the processing
1777 ; move/exchange bytes.to.process bytes
1780 ; * adjust memory pointers and map in new pages if necessary
1781 ; * for the next iternation
1783 ; if (total.bytes.to.process != 0)
1784 ; if (source.type == emm)
1787 ; * forward.copy's index expire
1789 ; map next emm source page into source.page.frame
1793 ; * backward.copy's index expire
1795 ; map prev emm source page into source.page.frame
1800 ; if (dest.type == emm)
1803 ; * forward.copy's index expire
1805 ; map next emm dest page into dest.page.frame
1809 ; * backward.copy's index expire
1811 ; map prev emm dest page into dest.page.frame
1817 ; restore first page frame's mapping context
1818 ; restore second page frame's mapping context
1821 ;==============================================================================
1824 _MoveExchangeMemory proc
near
1825 mov byte ptr [bp.rAX+1], OK
; Assume everything work OK
1826 cld ; Assume forward direction
1828 cmp al, 1 ; Q: Valid subfunction?
1829 ja mem_inv_sub
; N: Error
1832 pop fs ; fs <-- addresses MEMM's data group
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
1846 xor si, si ; DS:SI <-- Move/Exchange structure
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
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
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
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
1897 ; check validility of source
1899 lea di, [si.mem_source
]
1900 call validate_for_Move_or_Exchange
1904 ; check validility of dest
1906 lea di, [si.mem_dest
]
1907 call validate_for_Move_or_Exchange
1911 or edx, edx ; delayed test for exact move/xchg
1912 je mem_valid_overlap
; WEIRD!!! -- Move to same place!
1918 mov bx, si ; GS:BX <-- move/exchange structure
1920 ; save first 2 physical page frames' mapping and use those pages
1921 ; as source and dest physical pages
1924 pop ds ; DS <-- DGROUP
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
1933 cmp gs:[bx.mem_dest
.mem_memory_type
], 0 ; Q: conv mem ?
1934 jnz mem_map_dest
; N: map in emm page
1936 ; conv memory : setup starting address of dest (always forward)
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
1943 mov ax, cx ; AX:DX <-- first byte
1944 Set_EMM_GDT EMM2_GSEL
1946 xor di, di ; ES:DI <-- dest SelOff
1949 push 0ffffh ; fake a logical page#
1954 ; emm memory : find out starting address of dest
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
1959 test al, Backward_Copy_Flag
; Q: Backward copy ?
1960 jz SHORT mem_map_dest_forward
; N: forward
1963 ; backward move : calculate last logical page# and offset
1965 mov ecx, gs:[bx.mem_region_length
]
1966 movzx edi, gs:[bx.mem_dest
.mem_initial_offset
]
1971 mov edi, ecx ; new offset
1973 shr ecx, 14 ; / 16K = # of pages
1974 add dx, cx ; last emm page#
1976 mem_map_dest_forward:
1977 push dx ; put current dest logical page# on stack
1985 mov dx, gs:[bx.mem_dest
.mem_handle
]
1988 mov ax, 1 ; 2nd page frame
1990 jc mem_mapping_error_3_pop
; pop out dest seg_page
1992 ; contruct GDT entry for EMM2_GSEL for ES:0
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
2007 cmp gs:[bx.mem_source
.mem_memory_type
], 0 ; Q: conv mem ?
2008 jnz mem_map_source
; N: map in emm page
2010 ; conv memory : setup starting address of source (always forward)
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
2018 mov ax, cx ; AX:DX <-- first byte
2019 Set_EMM_GDT EMM1_GSEL
2025 push 0ffffh ; fake a logical page#
2026 jmp short mem_set_done
2030 ; emm memory : find out starting address of dest
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
2035 test al, Backward_Copy_Flag
; Q: Backward copy ?
2036 jz SHORT mem_map_source_forward
; N: forward
2039 ; backward move : calculate last logical page# and offset
2041 mov ecx, gs:[bx.mem_region_length
]
2042 movzx esi, gs:[bx.mem_source
.mem_initial_offset
]
2047 mov esi, ecx ; new offset
2049 shr ecx, 14 ; / 16K = # of pages
2050 add dx, cx ; last emm page#
2052 mem_map_source_forward:
2053 push dx ; put current source logical page# on stack
2061 mov dx, gs:[bx.mem_source
.mem_handle
]
2064 mov ax, 0 ; 1st page frame
2066 jc mem_mapping_error_4_pop
; pop out dest and source seg_page
2068 ; contruct GDT entry for EMM1_GSEL for DS:0
2070 mov ax, [PF_Base
] ; 1st page frame segment
2071 xor dx, dx ; offset 0
2073 Set_EMM_GDT EMM1_GSEL
2074 pop es ; ES:0 <-- GDT
2075 mov ds, bx ; ES:DI <-- dest address
2080 ; DS:SI <-- source address
2081 ; ES:DI <-- dest address
2084 mov edx, gs:[bx.mem_region_length
] ; total length to move/xchg
2087 ; main move/exchange loop
2091 mov cr3, ecx ; flush TLB after each map loop
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
2100 cmp gs:[bx.mem_dest
.mem_memory_type
], 0 ; Q: conv mem ?
2101 jnz mem_both_are_emm
; N: find out which
2104 sub cx, si ; CX <-- length to move/xchg
2105 jmp short mem_calculate_length
2107 test al, Backward_Copy_Flag
; Q:backward copy ?
2108 jz SHORT mem_2_emm_forward
; N:forward
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
2115 jmp short mem_calculate_length
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
2125 mem_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
2134 sub edx, ecx ; Adjust total first
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
2141 ; memory move backward
2146 ; memory move forward
2151 shr ecx, 2 ; ECX = # DWORDS to copy
2152 rep movsd ; Move the DWORDS
2154 and ecx, 00000003h ; ECX = # BYTES left to copy
2155 rep movsb ; Move the BYTES
2157 jmp short mem_next_round
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
2169 mem_xchg_dword_loop:
2176 loop mem_xchg_dword_loop
; Loop until all DWORDS exchanged
2179 and ecx, 00000003h ; ECX = # BYTES left to exchange
2180 jecxz mem_xchg_done
; Exit if no DWORDS left
2188 loop mem_xchg_byte_loop
; Loop until all BYTES exchanged
2195 ; prepare for next iteration
2199 ; get source and dest's current mapped logical page
2202 pop cx ; source logical page#
2203 shl ecx, 16 ; put in high word
2204 pop cx ; dest logical page#
2206 or edx, edx ; Q: all done ?
2207 jz mem_exit
; Y: restore context first
2209 ; fix dest addresses
2211 cmp gs:[bx.mem_dest
.mem_memory_type
], 0 ; Q: conv mem ?
2212 jnz mem_map_next_dest
; N: map next page
2214 jmp mem_check_source
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
2222 mov di, 3fffh
; set di for next round
2223 dec cx ; next logical page
2224 jmp SHORT mem_map_next_dest_do_map
2226 mem_map_next_dest_forward:
2227 xor di, di ; clear di for next round
2228 inc cx ; next logical page
2231 ; map in the next dest page
2233 mem_map_next_dest_do_map:
2241 mov dx, gs:[bx.mem_dest
.mem_handle
]
2243 mov ax, 1 ; 2nd page frame
2251 jc mem_mapping_error
2254 ; fix source addresses
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
2263 mem_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
2269 mov si, 3fffh
; set si for next round
2270 dec cx ; next logical page
2271 jmp SHORT mem_map_next_source_do_map
2273 mem_map_next_source_forward:
2274 xor si, si ; clear si for next round
2275 inc cx ; next logical page
2278 ; map in the next source page
2280 mem_map_next_source_do_map:
2288 mov dx, gs:[bx.mem_source
.mem_handle
]
2290 mov ax, 0 ; 1st page frame
2298 jc mem_mapping_error
2300 ; push back the logical pages on stack for
2301 ; next iternation : dest first, then source
2310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2314 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2317 ; check validility of source
2319 lea di, [si.mem_source
]
2320 call validate_for_Move_or_Exchange
2324 ; check validility of dest
2326 lea di, [si.mem_dest
]
2327 call validate_for_Move_or_Exchange
2331 push ax ; save subfunction
2332 push [si.mem_region_length
] ; save length
2334 movzx eax, [si.mem_dest
.mem_initial_seg_page
]
2335 movzx edx, [si.mem_dest
.mem_initial_offset
]
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
2343 movzx eax, [si.mem_source
.mem_initial_seg_page
]
2344 movzx edx, [si.mem_source
.mem_initial_offset
]
2347 add esi, edx ; ESI <-- source linear addr
2348 Set_EMM_GDT EMM1_GSEL
2349 Set_Page_Gran EMM1_GSEL
2352 pop es ; recover dest GDT sel
2353 pop ecx ; recover length
2354 pop ax ; recover subfunction
2356 ; test for overlapping transfer
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
2363 mem_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
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
2378 jmp short mem_conv_copy
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
2386 test al, 1 ; Q:copy ?
2387 jnz mem_conv_xchg
; N:go do exchange
2391 je mem_valid_overlap
; WEIRD!!! -- Move to same place!
2400 jnz mem_conv_copy_loop
2401 jmp mem_conv_done
; DONE!!!!
2413 jnz mem_conv_xchg_loop
; Loop until all BYTES exchanged
2415 Set_Byte_Gran EMM1_GSEL
; make sure EMM1_GSEL and
2416 Set_Byte_Gran EMM2_GSEL
; EMM2_GSEL are Byte Granulated
2421 mov byte ptr [bp.rAX+1], ah ; error code already set in ah
2424 mov byte ptr [bp.rAX+1], VALID_OVERLAP
2427 mov byte ptr [bp.rAX+1], OK
2431 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
2434 mov byte ptr [bp.rAX+1], INVALID_REGION_LENGTH
2436 mem_bad_memory_types:
2437 mov byte ptr [bp.rAX+1], INVALID_MEMORY_TYPE
2440 mov byte ptr [bp.rAX+1], OVERLAPPING_EXCHANGE
2443 ; discard old ax,bx,source seg_page#,dest seg_page#
2445 mem_mapping_error_4_pop:
2447 mem_mapping_error_3_pop:
2452 mov eax, cr3 ; Always clear TLB, we may have
2453 mov cr3, eax ; mapped pages before an error
2455 ; all done, need to restore context of physical page frames
2458 push fs ; get DGROUP back into DS
2463 cld ; string forward again
2464 jmp _set_windows
; remap all pages
2466 _MoveExchangeMemory endp
2469 ;******************************************************************************
2471 ; validate_for_Move_Or_Exchange
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.
2480 ; DS:DI = Move/Exchange memory descriptor data structure (source or dest)
2481 ; FS = MEMM's data segment
2483 ; AH = Status (0 = No error) -- AL is preserved
2487 ; AL and all other registers are preserved
2489 ;==============================================================================
2491 validate_for_Move_Or_Exchange PROC
NEAR
2493 push edx ; Used as temporary variable
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
2504 push ds ; validate_handle expect DS
2505 push fs ; points to dgroup
2507 Validate_Handle ME_Map_Inv_Handle
; check it
2511 mov ax, fs:[bx.ht_count
] ; EAX = # pages in handle
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
2518 movzx edx, [di.mem_initial_offset
]
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
2524 ja ME_Map_Not_Enough_EMM
;Q: Is last page in range
2525 jmp short ME_Map_OK
; N: error
2527 ME_Map_Conventional:
2528 movzx edx, word ptr [di.mem_initial_seg_page
]
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
2542 cmp edi, eax ; Q: Does move run into EMM area?
2543 ja SHORT ME_Map_Inv_Overlap
; Y: Error
2545 ; N: Everything is okie dokie
2555 mov ah, INVALID_MEMORY_TYPE
2562 mov ah, INVALID_HANDLE
2565 ME_Map_Invalid_log_page:
2568 mov ah, LOG_PAGE_RANGE
2571 ME_Map_Invalid_Offset:
2574 mov ah, INVALID_OFFSET
2577 ME_Map_Not_Enough_EMM:
2580 mov ah, INSUFFICIENT_EMM_PAGES
2586 mov ah, CONVENTIONAL_EMM_OVERLAP
2589 ME_Map_Inv_Wraparound:
2592 mov ah, INVALID_WRAPAROUND
2595 validate_for_Move_Or_Exchange ENDP
2599 ;***********************************************
2601 ; _AlternateMapRegisterSet - handle alternative register sets
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.
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
2622 ; EXIT: from individual sub-function or error with
2623 ; AH = INVALID_SUBFUNCTION
2627 ;***********************************************
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
2638 jmp CS:AMRS_map
[si] ; go to relevant sub-function
2639 ; Return directly or to AMRS_exit...
2640 AMRS_exit: ; Exit with AH already set
2644 mov byte ptr [bp.rAX+1], ACCESS_DENIED
2648 mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
2652 mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED
2656 mov byte ptr [bp.rAX+1], FRSET_NO_DMA
2660 AMRS_map dw _TEXT
:AMRS_get
2663 dw _TEXT
:AMRS_allocate
2664 dw _TEXT
:AMRS_deallocate
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
2672 ;***********************************************
2674 ; AMRS_get - get the current 'fast' register set
2677 ; SS:[EBP] -> regp stack frame
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
2688 ; DESCRIPTION: This function returns the current register set number.
2689 ; If it is zero, it returns the save area previously specified
2691 ;-----------------------------------------------
2694 mov al, [CurRegSetn
] ; Get current set number
2695 mov byte ptr [bp.rBX], al ; to be picked up later
2698 ret ; non-zero - all done
2699 AMRS_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
2705 jnz short AMRS_get2
; got dest addr
2707 jz short AMRS_get1
; not specified yet
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
2716 shr ecx, 1 ; convert to dwords
2717 rep movsd ; save the map
2722 ;***********************************************
2724 ; AMRS_set - set the current 'fast' register set
2726 ; ENTRY: BL = register set number
2729 ; ES:DI -> buffer containing mappings for register set 0
2730 ; SS:[EBP] -> regp stack frame
2733 ; EXIT: return code set on stack
2735 ; USED: EAX, EBX, ECX, EDX, ESI, EDI
2737 ; DESCRIPTION: This function sets the current register set number.
2738 ; If it is zero, it uses the save area specified in ES:DI.
2740 ;-----------------------------------------------
2743 cmp bl, FRS_COUNT
; Validate new Reg Set
2746 imul eax, size FRS_struc
2748 lea bx, FRS_array
[bx] ; Get pointer to the new Reg Set
2749 cmp [bx.FRS_alloc
], 0 ; Make sure it is allocated
2751 je AMRS_undef_FRS
; unallocated, go complain
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
2757 AMRS_set0: ; Now set up new reg set
2758 mov word ptr [CurRegSet
], ax ; Set Current reg. set Offset
2759 mov [CurRegSetn
], bl
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
2771 jz _set_windows
; AX:DX == 0:0 implies no save area
2773 ; construct GDT entry using EMM1_GSEL to access user's FRS buffer
2776 Set_EMM_GDT EMM1_GSEL
2779 mov fs, bx ; FS:SI <-- FRS buffer
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
2786 shr ecx, 1 ; size in dwords
2787 push ds ; xchg ds,fs
2790 pop fs ; use DS as default seg. reg.
2796 jmp _set_windows
; set up mappings
2799 ;***********************************************
2801 ; AMRS_size - get the size of the register set 0 save area
2804 ; SS:[EBP] -> regp stack frame
2807 ; EXIT: return code set on stack
2808 ; DX = size of the save area
2812 ; DESCRIPTION: This function returns the size of the save area used
2813 ; for register set 0.
2815 ;-----------------------------------------------
2817 movzx eax, [_cntxt_bytes
] ; Previously calculated value
2818 mov word ptr [bp.rDX], ax
2822 ;***********************************************
2824 ; AMRS_allocate - allocate a fast register set
2827 ; SS:[EBP] -> regp stack frame
2830 ; EXIT: return code set on stack
2831 ; BL = register set number
2835 ; DESCRIPTION: This function allocates a free register set.
2837 ;-----------------------------------------------
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
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
2850 cmp bl, FRS_COUNT
; Safety... should never fail
2851 jb short AMRS_search
2853 mov byte ptr [bp.rAX+1], EMM_SW_MALFUNCTION
; Honesty...
2857 mov [di.FRS_alloc
], 1 ; Allocate it
2859 lea di, [di.FRS_Window
]
2860 movzx ecx, [_cntxt_pages
]
2862 rep movsd ; Initialise to current mapping
2863 mov byte ptr [bp.rBX], bl ; Return the number
2866 AMRS_noRS: ; None free; return error
2867 mov byte ptr [bp.rAX+1], NO_MORE_FRSETS
2871 ;***********************************************
2873 ; AMRS_deallocate - deallocate a fast register set
2875 ; ENTRY: BL = register set to deallocate
2876 ; SS:[EBP] -> regp stack frame
2879 ; EXIT: return code set on stack
2883 ; DESCRIPTION: This function deallocates a register set.
2885 ;-----------------------------------------------
2888 jz AMRS_exit
; Deallocating 0 is ignored
2889 cmp bl, [CurRegSetn
] ; Can't deallocate current set
2890 je short AMRS_undef_FRS
2892 jae short AMRS_undef_FRS
; Invalid Register set
2894 imul eax, size FRS_struc
; Offset into array
2896 cmp FRS_array
[bx.FRS_alloc
], 0 ; Paranoid...
2898 je short AMRS_undef_FRS
; Not allocated, complain
2900 mov FRS_array
[bx.FRS_alloc
], 0 ; Mark it free
2902 inc [FRS_free
] ; one more set free
2907 mov byte ptr [bp.rAX+1], FRSET_UNDEFINED
2910 _AlternateMapRegisterSet endp
2914 ;******************************************************************************
2915 ; _Get_Key_Val - use the timer to get a random number for OSDisable Key
2917 ; ENTRY DS, ES = DGROUP selectors
2921 ; EXIT EAX has randomish number
2923 ; USES Flags, EAX, EDX
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!
2935 ;******************************************************************************
2941 ; Returns the current system timer counter value
2947 ; AX = Current counter value (High word of EAX NOT CHANGED)
2952 ;------------------------------------------------------------------------------
2954 Get_Counter_Value PROC
NEAR
2956 System_Clock_Port EQU 40h
2957 Sys_Clock_Ctrl_Port EQU 43h
2961 mov al, Latch_Counter
2962 out Sys_Clock_Ctrl_Port
, al ; Latch the timer counter
2964 in al, System_Clock_Port
; Read the LSB
2967 in al, System_Clock_Port
; Read the MSB
2968 xchg ah, al ; AX = Counter value
2971 Get_Counter_Value ENDP