Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-1


				page	58,132
				;******************************************************************************
					title	EMMP - EMM protected mode functions
				;******************************************************************************
				;
				;   (C) Copyright MICROSOFT Corp. 1986, 1987
				;
				;   Title:	CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver
				;		EMMLIB.LIB - Expanded Memory Manager Functions Library
				;
				;   Module:	EMMP - WIN386 EMM functions
				;
				;   Version:	0.04
				;
				;   Date:	July 7,1986
				;
				;******************************************************************************
				;
				;   Change log:
				;
				;     DATE    REVISION                  DESCRIPTION
				;   --------  --------  -------------------------------------------------------
				;   07/07/86  0.04	Moved here from version 0.04 EMMSUP.ASM
				;   07/08/86  0.04	Added Get/Set Page Map (SBP).
				;   05/13/88            Change to LIM 4.0 functionality (PC)
				;
				;******************************************************************************
				;
				;   Functional Description:
				;	This file contains the EMM functions which require greatest efficiency.
				;
				;******************************************************************************
				.lfcond					; list false conditionals
				.386p
				
				;	include	protseg.inc
					include vdmseg.inc
			     C	
			     C	
			     C	;******************************************************************************
			     C	;
			     C	;   (C) Copyright MICROSOFT Corp. 1986
			     C	;
			     C	;   Title:    MEMM - MICROSOFT Expanded Memory Manager 386
			     C	;
			     C	;   Module:   VDMSEG.INC - Segment Ordering and attributes for VDM
			     C	;
			     C	;   Version:  0.04
			     C	;
			     C	;   Date:     May 12, 1986
			     C	;
			     C	;   Author:
			     C	;
			     C	;******************************************************************************
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-2


			     C	;
			     C	;   Change log:
			     C	;
			     C	;     DATE    REVISION			DESCRIPTION
			     C	;   --------  --------	-------------------------------------------------------
			     C	;	      Original
			     C	;   05/12/86  A 	Cleanup and segment reorganization
			     C	;   06/03/86  C 	changed order and added STACK and STACK0,STACK0_SIZE
			     C	;   06/06/86  C 	changed CODE to _TEXT and DATA to _DATA
			     C	;   06/28/86  0.02	Name change from MEMM386 to MEMM
			     C	;   07/05/86  0.04	Re-organized to allow code seg move
			     C	;   06/03/88		add use16 to all segments
			     C	;
			     C	;******************************************************************************
			     C	ifndef INC_LIST
			     C	.list	; end of VDMSEG.INC
			     C	
					include page.inc
			     C	
			     C	
			     C	;******************************************************************************
			     C	;
			     C	;   (C) Copyright MICROSOFT Corp. 1986
			     C	;
			     C	;   Title:    MEMM - MICROSOFT Expanded Memory Manager 386
			     C	;
			     C	;   Module:   PAGE.INC - Definitions for paging on 386
			     C	;
			     C	;   Version:  0.02
			     C	;
			     C	;   Date:     January 31, 1986
			     C	;
			     C	;   Author:
			     C	;
			     C	;******************************************************************************
			     C	;
			     C	;   Change log:
			     C	;
			     C	;     DATE    REVISION			DESCRIPTION
			     C	;   --------  --------	-------------------------------------------------------
			     C	;   01/31/86  Original
			     C	;   05/12/86  A	Cleanup and segment reorganization
			     C	;   06/28/86  0.02	Name change from MEMM386 to MEMM
			     C	;
			     C	;******************************************************************************
			     C	;
			     C	;   Functional Description:
			     C	;
			     C	;******************************************************************************
			     C	ifndef INC_LIST
			     C	.list		; end of PAGE.INC
				;	include vdmm.inc
					include vm386.inc
			     C	
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-3


			     C	
			     C	;******************************************************************************
			     C	;
			     C	;   (C) Copyright MICROSOFT Corp. 1986
			     C	;
			     C	;   Title:    MEMM - MICROSOFT Expanded Memory Manager 386
			     C	;
			     C	;   Module:   VM386.INC
			     C	;
			     C	;   Version:  0.03
			     C	;
			     C	;   Date:     May 12, 1986
			     C	;
			     C	;   Author:
			     C	;
			     C	;******************************************************************************
			     C	;
			     C	;   Change log:
			     C	;
			     C	;     DATE    REVISION			DESCRIPTION
			     C	;   --------  --------	-------------------------------------------------------
			     C	;	      Original
			     C	;   05/12/86  A 	Cleanup and segment reorganization
			     C	;   06/08/86  B 	Added Disable A20 equates
			     C	;   06/14/86  C 	Added MOV_CDTR_FRAME, PROT_INS_FRAME, and changed
			     C	;			VTFO from 2 to 4 to reflect push of EBP from BP
			     C	;   06/15/86  D 	Added GPFAULT_FRAME
			     C	;   06/28/86  0.02	Name change from MEMM386 to MEMM
			     C	;   07/01/86  0.03	Added structures for accessing memory
			     C	;
			     C	;******************************************************************************
			     C	ifndef INC_LIST
			     C	.list	; end of VM386.INC
					include	vdmsel.inc
			     C	
			     C	
			     C	;******************************************************************************
			     C	;
			     C	;   (C) Copyright MICROSOFT Corp. 1986
			     C	;
			     C	;   Title:    MEMM - MICROSOFT Expanded Memory Manager 386
			     C	;
			     C	;   Module:   VDMSEL.INC - Selector Definitions for MEMM
			     C	;
			     C	;   Version:  0.05
			     C	;
			     C	;   Date:     May 12, 1986
			     C	;
			     C	;   Author:
			     C	;
			     C	;******************************************************************************
			     C	;
			     C	;   Change log:
			     C	;
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-4


			     C	;     DATE    REVISION			DESCRIPTION
			     C	;   --------  --------	-------------------------------------------------------
			     C	;	      Original
			     C	;   05/12/86  A 	Cleanup and segment reorganization
			     C	;   06/07/86  C 	merged with module from Rick
			     C	;   06/28/86  0.02	Name change from MEMM386 to MEMM
			     C	;   07/10/86  0.05	Changed CODE_GSEL to RCODEA_GSEL
			     C	;   07/20/88		Remove debugger selectors
			     C	;
			     C	;******************************************************************************
			     C	ifndef INC_LIST
			     C	.list	; end of VDMSEL.INC
			     C	
					include emmdef.inc
			     C	;******************************************************************************
			     C	;
			     C	;   (C) Copyright MICROSOFT Corp. 1986
			     C	;
			     C	;   Title:    CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver
			     C	;		EMMLIB.LIB - Expanded Memory Manager Library
			     C	;
			     C	;   Module:   EMMDEF.INC - defines for EMM code.
			     C	;
			     C	;   Version:  0.04
			     C	;
			     C	;   Date:     June 21, 1986
			     C	;
			     C	;******************************************************************************
			     C	;
			     C	;   Change log:
			     C	;
			     C	;     DATE    REVISION			DESCRIPTION
			     C	;   --------  --------	-------------------------------------------------------
			     C	;   06/21/86  Original
			     C	;   06/25/86  0.02	Changed HANDLE_CNT to 255 to match LIM spec (SBP).
			     C	;   06/28/86  0.02	Name change from CEMM386 to CEMM (SBP).
			     C	;   07/06/86  0.04	Changed save area struct (SBP).
			     C	;   05/25/88            Changed to meet LIM 4.0 Spec (PC)
			     C	;******************************************************************************
			     C	ifndef	INC_LIST
			     C	.list		; end of EMMDEF.INC
			     C	
			     C	
			     C	
			     C	
					include	desc.inc
			     C	
			     C	
			     C	;******************************************************************************
			     C	;
			     C	;   (C) Copyright MICROSOFT Corp. 1986
			     C	;
			     C	;   Title:    MEMM - MICROSOFT Expanded Memory Manager 386
			     C	;
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-5


			     C	;   Module:   DESC.INC - Descriptor Table Definitions for 286/386
			     C	;
			     C	;   Version:  0.02
			     C	;
			     C	;   Date:     January 31, 1986
			     C	;
			     C	;   Author:
			     C	;
			     C	;******************************************************************************
			     C	;
			     C	;   Change log:
			     C	;
			     C	;     DATE    REVISION			DESCRIPTION
			     C	;   --------  --------	-------------------------------------------------------
			     C	;   01/31/86  Original
			     C	;   04/07/86  A 	added bit map base to 386 TSS
			     C	;   05/12/86  B 	Cleanup and segment reorganization
			     C	;   06/25/86  0.02	removed A0 macros
			     C	;   06/28/86  0.02	Name change from MEMM386 to MEMM
			     C	;
			     C	;******************************************************************************
			     C	ifndef INC_LIST
			     C	.list	; end of DESC.INC
			     C	
				;	include vmdm.inc
				;	include vpicd.inc
				;	include vdmmmac.inc
				
				;******************************************************************************
				;	P U B L I C S
				;******************************************************************************
 0000				_TEXT	segment
					public	_MapHandlePage
					public	_SavePageMap
					public	_RestorePageMap
					public	_GetSetPageMap
					public	_GetSetPartial
					public	_MapHandleArray
					public	_AlterMapAndJump
					public	_AlterMapAndCall
				;	public	TS_VEMMD_MC_Ret
					public	_MoveExchangeMemory
					public	_AlternateMapRegisterSet
				;	public	VEMMD_Set_Map_Region
				;	public	VEMMD_Unset_Map_Region
				;	public	_VMpte_to_EMMpte
				;	public	_Remap_EMM
					public	_Get_Key_Val
 0000				_TEXT	ends
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-6


					page
				;******************************************************************************
				;	E X T E R N A L   R E F E R E N C E S
				;******************************************************************************
				
 0000				_TEXT	segment
				
				extrn	_source_addr:near
				extrn	_dest_addr:near
				
				extrn	SetDescInfoResident:near
				extrn	SegOffTo24Resident:near
				
				extrn	ErrHndlr:near
				
 0000				_TEXT	ends
				
 0000				_DATA	SEGMENT
				
				;extrn	_regp:dword				;  pointer to entry stack frame
				;extrn	VEMMD_pt:dword
				;extrn	Cur_VM_Handle:dword
				;extrn	Cur_VMID:dword
				;extrn	_VM_List:dword
				;extrn	_MaxEMMSize:dword
				;extrn	_VEMMD_PgFrame:word
				;extrn	_VEMMD_Last_Offset:word
				extrn	PF_Base:word
				extrn	_OSEnabled:dword
				;extrn	NullAvailPTE:dword
				;extrn	NullUnavailPTE:dword
				
				extrn	_total_pages:word			; total # of EMM pages in system
				
				;
				; table of offsets into in to the first page table
				; for user logical emm page map
				;
				extrn	_page_frame_base:dword
				
				extrn	_pft386:word
				
				extrn	_mappable_pages:word			; table of mappable pages
				extrn	_mappable_page_count:word		; how many in the table
				extrn	_page_frame_pages:word			; how many in the page frame
				extrn	_physical_page_count:word		; number of physical pages
				extrn	_VM1_EMM_Pages:word			; pages not in the page frame
				;extrn	_VM1_EMM_Offset:word			; offset of these in a context
				extrn	_cntxt_pages:byte			; number of pages in a context
				extrn	_cntxt_bytes:byte			; number of bytes in a context
				
				
				;
				; table of indexes into the above - maps segment to physical page
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-7


				;
				extrn	EMM_MPindex:byte
				
				;
				; ptr to table of emm page # for each handle's logical pages.
				;
				extrn	_emm_page:word
				
				;
				;  handle data structure
				;
				extrn	_handle_table:word
				extrn	_handle_table_size:word
				
				;
				;   save area for handles
				;
				extrn	_save_map:byte
				
				;
				; Save area and misc variables for 4.0 function 27
				;
				extrn	EMM_savES:word
				extrn	EMM_savDI:word
				
				extrn	CurRegSetn:byte
				extrn	FRS_free:byte
				extrn	CurRegSet:dword
				extrn	FRS_array:word
				
				extrn	_regp:word
 0000				_DATA	ENDS
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-8


					page
				;******************************************************************************
				;	C O D E
				;******************************************************************************
 0000				_TEXT	SEGMENT
				assume	cs:_TEXT, ds:DGROUP, ss:DGROUP
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-9


					page
				;***********************************************
				;
				; normalize
				;
				;	ENTRY:	Sel,Off - Selector:offset to be normalize
				;		protected mode only
				;
				;	EXIT:	Sel:Off normalized
				;
				;	USES:	Sel,Off
				;	NOTE:	Sel and Off should not be BX,DX,AX
				;
				;***********************************************
				normalize	MACRO	Sel,Off
				
					push	dx
					push	ax
					push	bx
					push	es
				
					push	Sel		; save for later reload
					mov	bx, Sel		; get Selector into BX
				
					push	GDTD_GSEL	; ES -> GDT
					pop	es
				
					and	bl,SEL_LOW_MASK	; mask off mode bits
					mov	dx,es:[bx+2]	; AL:DX <-- base address
					mov	al,es:[bx+4]
					add	dx,Off		; adjust base address
					adc	al,0
					mov	es:[bx+2],dx	; store it back
					mov	es:[bx+4],al
					xor	Off, Off	; new Offset
				
					pop	Sel		; reload Selector (flush cache)
				
					pop	es
					pop	bx
					pop	ax
					pop	dx
				
					ENDM
				
				;***********************************************
				;
				; get_space_from_stack
				;
				;	ENTRY:	Len - amount of space requested
				;
				;	EXIT:	Len space allocated on ES:DI (client's stack)
				;		ES:DI - points to First element on top of stack
				;
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-10


				;	USES:	DI
				;
				;***********************************************
				Get_space_from_stack	MACRO	Len
				
					sub	di, Len
					ENDM
				
				;***********************************************
				;
				; release_space_to_stack
				;
				;	ENTRY:	Len - amount of space to be release
				;
				;	EXIT:	Len space released from client's stack (DS:SI)
				;
				;	USES:	SI
				;
				;***********************************************
				release_space_to_stack	MACRO	Len
				
					add	si, Len
					ENDM
				
				;***********************************************
				;
				; Set_EMM_GDT - set GDT entry of selector with some fix infos
				;	like access and limit
				;
				;	ENTRY:	Handle - selector of GDT to modify
				;
				;	EXIT:	GDT entry set
				;		bx - selector
				;
				;	USES:	ax,bx,cx,dx,es
				;
				;***********************************************
				Set_EMM_GDT	MACRO	handle
				
					mov	bx, handle			; GDT selector
					call	SegOffTo24Resident		; AL:DX <-- 24 bit base address
					mov	cx, 0ffffh			; Limit
					mov	ah, D_DATA0			; Acess right
					push	GDTD_GSEL
					pop	es				; ES:0 <-- GDT
					call	SetDescInfoResident		; set GDT entry
					ENDM
				
				;***********************************************
				;
				; Set_Byte_Gran - set granularity of GDT entry to byte
				;
				;	ENTRY:	Handle - selector of GDT to modify
				;
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-11


				;	EXIT:	Granularity bit clear in GDT
				;		bx - Selector 
				;
				;	USES:	bx,es
				;
				;***********************************************
				Set_Byte_Gran	MACRO	handle
				
					mov	bx, handle			; GDT selector
					push	GDTD_GSEL
					pop	es				; ES:0 <-- GDT
					and	byte ptr es:[bx+6],NOT R_GRAN	; clear gran bit
					ENDM
				
				;***********************************************
				;
				; Set_Page_Gran - set granularity of GDT entry to page
				;
				;	ENTRY:	Handle - selector of GDT to modify
				;
				;	EXIT:	Granularity bit set in GDT
				;		bx - Selector 
				;
				;	USES:	bx,es
				;
				;***********************************************
				Set_Page_Gran	MACRO	handle
				
					mov	bx, handle			; GDT selector
					push	GDTD_GSEL
					pop	es				; ES:0 <-- GDT
					or	byte ptr es:[bx+6], R_GRAN	; set gran bit
					ENDM
				
				;***********************************************
				;
				; Get_FRS_window - get pointer to Fast Register Set window
				;
				;	ENTRY:	Reg - points to an FRS_struc
				;
				;	EXIT:	Reg - points to FRS_window entry in the structure
				;
				;	USES:	Reg
				;
				;***********************************************
				Get_FRS_window	MACRO	Reg
				
					mov	Reg, word ptr [CurRegSet]	; just offset (assume dgroup)
					add	Reg, FRS_window			; points to FRS window entries
					ENDM
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-12


					page
				;**********************************************************************
				;
				;   map_EMM_page - set page table entries for a page frame
				;
				;	ENTRY:	AX - physical page number to be mapped
				;		BX - EMM page number to map
				;	EXIT:	page table set up for EMM page # in this page frame
				;	DESTROY:EAX,BX
				;
				;***********************************************
 0000				map_EMM_page	proc	near
 0000  3B 06 0000 E			cmp	ax,[_physical_page_count]	;Q: valid physical page# ?
 0004  73 55				jae	short mEp_inv_page		;  N: invalid page number
										;  Y: continue with it
 0006  3B 1E 0000 E			cmp	bx,[_total_pages]		;Q: valid EMM page# ?
 000A  73 4F				jae	short mEp_inv_page		;  N: invalid page number
										;  Y: continue with it
 000C  06				push	es		; preserve es
 000D  51				push	cx		; preserve cx
 000E  57				push	di		; preserve di
 000F  50				push	ax		; save ax (phys page#)
				
					;
					; construct pointer to physical address of the first
					; 386 page and move it into eax
					;
 0010  8B CB				mov	cx,bx		; emm page# in cx to save in FRS later
 0012  C1 E3 02				shl	bx,2		; bx <-- pft index * 4
				
					;
					; continue calulation of pte
					;
 0015  03 1E 0000 E			add	bx,[_pft386]	; BX  = points into _pft386
 0019  66| 8B 07			mov	eax,[bx]	; EAX = physical address of EMM page #
 001C  25 F000				and	ax,0F000H	; clear the low 12 bits
 001F  0D 0007				or	ax,P_AVAIL	; page ctl bits <-- user,present,write
				
 0022  5B				pop	bx		; bx <-- physical page index
				
					;
					; save mapping (offset into _pft386 struct) into
					; current FRS's physical page entry
					;
				
					Get_FRS_Window	DI	; di <-- address of current FRS
 0023  8B 3E 0000 E          1		mov	DI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0027  83 C7 00              1		add	DI, FRS_window			; points to FRS window entries 
 002A  03 FB				add	di,bx		; di <-- address of physical page
 002C  03 FB				add	di,bx		;        entry in FRS
 002E  89 0D				mov	[di],cx		; save mapping (emm page#) into FRS
					;
					; construct pointer to physical address of
					; page frame
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-13


					;
				
 0030  C1 E3 02				shl	bx,2	 		; bx <-- index * 4
 0033  81 C3 0000 E			add	bx,offset DGROUP:_page_frame_base ; bx = offset for entry in _page_frame_base
 0037  C4 3F				les	di,[bx]			; es:di <-- page frame address
				
					;
					; now, 
					;	es:di points to the 1st entry in the page table 
					;             for this page frame
					;	eax contains the new value of the PTE
					; set up 4 entries
					;
				
 0039  9C				pushf			; preserve direction flag
 003A  FC				cld			; forward
				
 003B  66| AB				stosd			; store 1st page table entry
 003D  66| 05 00001000			add	eax,P_SIZE	; eax <-- next address
				
 0043  66| AB				stosd			; store 2nd page table entry
 0045  66| 05 00001000			add	eax,P_SIZE	; eax <-- next address
				
 004B  66| AB				stosd			; store 3rd page table entry
 004D  66| 05 00001000			add	eax,P_SIZE	; eax <-- next address
				
 0053  66| AB				stosd			; store 4th page table entry
				
 0055  9D				popf			; restore direction flag
 0056  5F				pop	di		; get DI back
 0057  59				pop	cx		; get CX back
 0058  07				pop	es		; get ES back
 0059  F8				clc
 005A  C3				ret
				
 005B				mEp_inv_page:
 005B  F9				stc
 005C  C3				ret
				
 005D				map_EMM_page	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-14


					page
				;**********************************************************************
				;
				;    unmap_page - unmap a physical page
				;
				;	ENTRY:	AX - physical page number to be unmapped
				;	DESTROY:EAX
				;
				;**********************************************************************
 005D				unmap_page	proc	near
					;
					; find FRS entry for the physical page and
					; update it as unmapped
					;
 005D  06				push	es
 005E  57				push	di
 005F  53				push	bx
 0060  51				push	cx
					Get_FRS_Window	DI		; di <-- address of current FRS
 0061  8B 3E 0000 E          1		mov	DI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0065  83 C7 00              1		add	DI, FRS_window			; points to FRS window entries 
 0068  03 F8				add	di, ax			; di <-- address of physical page
 006A  03 F8				add	di, ax			;        entry in FRS
 006C  C7 05 FFFF			mov	[di], NULL_PAGE		; unmap the entry
				
					;
					; find out the segment of the physical page
					;
 0070  8B 0E 0000 E			mov	cx, [_physical_page_count]
 0074  BF 0000 E			mov	di, offset DGROUP:_mappable_pages
 0077				unmap_page_loop:
 0077  3B 45 02				cmp	ax, [di].mappable_pg
 007A  0F 84 0085 R			je	unmap_page_found
 007E  83 C7 04				add	di, size Mappable_Page
 0081  E2 F4				loop	unmap_page_loop
				
 0083  EB 48				jmp	short unmap_page_exit	; non-found : just return
				
 0085				unmap_page_found:
 0085  8B 1D				mov	bx, [di].mappable_seg	; get segment into bx first
				
					;
					; construct pointer to physical address of
					; page frame
					;
 0087  93				xchg	ax,bx
 0088  C1 E3 02				shl	bx,2	 		; bx <-- index * 4
 008B  81 C3 0000 E			add	bx,offset DGROUP:_page_frame_base ; bx <-- points to PTE address of phys page#
 008F  C4 3F				les	di,[bx]			; es:di <-- points to PTE of page frame
 0091  93				xchg	ax,bx
				
					;
					; construct PTE
					;
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-15


 0092  66| 0F B7 C3			movzx	eax, bx		; EAX <-- segment of physical page
 0096  66| C1 E0 04			shl	eax, 4
 009A  25 F000				and	ax,0F000H	; clear the low 12 bits
 009D  0D 0007				or	ax,P_AVAIL	; page ctl bits <-- user,present,write
				
 00A0  66| 3D 000A0000			cmp	eax, 0A0000h	; Q:above 640K ?
 00A6  0F 8D 00B0 R			jge	unmap_page_ok	;  Y: go ahead, unmap it
 00AA  66| B8 00000000			mov	eax, 0		;  N: shouldn't unmap below 640K - make page NotPresent
				
 00B0				unmap_page_ok:
 00B0  9C				pushf
 00B1  FC				cld
 00B2  66| AB				stosd				; unmap pte of page frame
 00B4  66| 05 00001000			add	eax,P_SIZE
 00BA  66| AB				stosd
 00BC  66| 05 00001000			add	eax,P_SIZE
 00C2  66| AB				stosd
 00C4  66| 05 00001000			add	eax,P_SIZE
 00CA  66| AB				stosd
 00CC  9D				popf
				
 00CD				unmap_page_exit:
 00CD  59				pop	cx
 00CE  5B				pop	bx
 00CF  5F				pop	di
 00D0  07				pop	es
 00D1  C3				ret
 00D2				unmap_page	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-16


					page
				;**********************************************************************
				;
				;   map_page - map a logical page to a phyical page
				;
				;	ENTRY:	AX - physical page number to be mapped
				;		BX - logical page number to map
				;		DX - handle pointer (do not destroy)
				;	DESTROY:EAX,BX
				;
				;**********************************************************************
 00D2				map_page	proc	near
 00D2  3B 06 0000 E			cmp	ax,[_physical_page_count]	;Q: valid physical page# ?
 00D6  73 2D				jae	short mp_inv_phy		;  N: invalid page number
										;  Y: continue with it
 00D8  83 FB FF				cmp	bx,0FFFFh			;Q: unmap ?
 00DB  74 1D				je	short mp_unmap_page		;  Y: go ahead
				
 00DD  87 DA				xchg	bx, dx
 00DF  3B 57 02				cmp	dx,[bx.ht_count]		;Q: valid logical page# ?
 00E2  87 DA				xchg	bx, dx
 00E4  73 25				jae	short mp_inv_log		;  N: invalid page number
										;  Y: continue with it
				
 00E6  87 DA				xchg	bx, dx
 00E8  03 17				add	dx,[bx.ht_index]		; dx <-- index into _emm_page
 00EA  87 DA				xchg	bx, dx
 00EC  D1 E3				shl	bx,1				; bx <-- index * 2
 00EE  03 1E 0000 E			add	bx,[_emm_page]
 00F2  8B 1F				mov	bx,[bx]				; bx <-- emm page#
 00F4  E8 0000 R			call	map_EMM_page
 00F7  72 06				jc	short mp_inv_emm_page		; emm page range error
 00F9  C3				ret
				
 00FA				mp_unmap_page:
 00FA  E8 005D R			call	unmap_page
 00FD  F8				clc
 00FE  C3				ret
				
 00FF				mp_inv_emm_page:
 00FF  C6 46 1D A3			mov	byte ptr [bp.rAX+1],SOURCE_CORRUPTED
 0103  F9				stc
 0104  C3				ret
				
 0105				mp_inv_phy:
 0105  C6 46 1D 8B			mov	byte ptr [bp.rAX+1],PHYS_PAGE_RANGE
 0109  F9				stc
 010A  C3				ret
				
 010B				mp_inv_log:
 010B  C6 46 1D 8A			mov	byte ptr [bp.rAX+1],LOG_PAGE_RANGE
 010F  F9				stc
 0110  C3				ret
 0111				map_page	endp
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-17


				
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-18


					page
				;***********************************************
				;
				; _MapHandlePage - map a handle's page
				;
				; This routine maps 4 386 pages into the address
				; space.
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 AH = 44h = map handle page function # 
				;	 AL = window # (physical page #)
				;	 BX = logical page #
				;	 DX = EMM handle
				; 	REGS on STACK:	SI = not used by this function
				;	 SS:[EBP] -> regp stack frame
				;	 DS = DGROUP
				;
				; EXIT:	page table entries set up
				;	AH = status of this function
				;		= EMM_HW_MALFUNCTION if entry in real/virtual mode.
				;
				; USED: EAX, EBX, EDX, EDI
				;
				;***********************************************
				
				Dword_Align	_TEXT
 0111  90                    1		db	90h		     ; 
 0112  90                    2		db	90h		     ; 
 0113  90                    3		db	90h		     ; 
 0114				_MapHandlePage	proc	near
				
					Validate_Handle	<short mhp_inv_handle>
 0114  3B 16 0000 E          1		cmp	dx, [_handle_table_size]	;Q: handle in range ? 
 0118  73 28                 1		jae	short mhp_inv_handle			;  N: go to error label 
 011A  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 011D  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 0121  87 DA                 1		xchg	bx, dx 
 0123  83 3F FF              1		cmp	[bx.ht_index], NULL_PAGE	;Q: is this handle active ? 
 0126  87 DA                 1		xchg	bx, dx 
 0128  74 18                 1		je	short mhp_inv_handle			;  N: return error 
				
 012A  C6 46 1D 00			mov	byte ptr [bp.rAX+1],OK	; Assume success!
 012E  66| 0F B6 C0			movzx	eax, al			; Physical page
 0132  66| 0F B7 DB			movzx	ebx, bx			; Logical page
				
 0136  66| 50				push	eax
 0138  0F 20 D8				mov	eax, cr3
 013B  0F 22 D8				mov	cr3, eax		; Flush old mapping now
 013E  66| 58				pop	eax
				
 0140  EB 90				jmp	map_page		; Common page mapping code
				
 0142				mhp_inv_handle:
 0142  C6 46 1D 83			mov	byte ptr [bp.rAX+1], INVALID_HANDLE
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-19


 0146  C3				ret
				
 0147				_MapHandlePage	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-20


					page
				;***********************************************
				;
				; _SavePageMap	- save current page mapping
				;
				;	This routine save the current page mapping context for a handle.
				;
				; ENTRY: PROTECTED MODE
				;	 AH = 07h = save page map function # 
				;	 DX = EMM handle
				; 	REGS on STACK:	SI = not used by this function
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;
				; EXIT:	current state saved
				;	AH = status of this function
				;
				; USED: AX,BX,CX,DX,SI,DI
				;
				;***********************************************
				
				Dword_Align	_TEXT
 0147  90                    1		db	90h		     ; 
 0148				_SavePageMap	proc	near
 0148  83 3E 0000 E 04			cmp	[_page_frame_pages], 4
 014D  72 43				jb	short srpm_nopf		; no page frame
				
 014F  8B C2				mov	ax, dx			; Save for later
					Validate_Handle	<short srpm_inv_handle>
 0151  3B 16 0000 E          1		cmp	dx, [_handle_table_size]	;Q: handle in range ? 
 0155  73 36                 1		jae	short srpm_inv_handle			;  N: go to error label 
 0157  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 015A  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 015E  87 DA                 1		xchg	bx, dx 
 0160  83 3F FF              1		cmp	[bx.ht_index], NULL_PAGE	;Q: is this handle active ? 
 0163  87 DA                 1		xchg	bx, dx 
 0165  74 26                 1		je	short srpm_inv_handle			;  N: return error 
									; check state of handle's page area
 0167  6B D8 0A				imul	bx,ax,SIZE SaveMap_struc ; BX = offset within Save Area for
									;  this handle's save area
 016A  8D BF 0000 E			lea	di,_save_map[bx]	; DS:DI points to handle's save area
 016E  81 3D 0FFF			cmp	[di].s_handle,NULL_HANDLE
									;Q: save area in use ?
 0172  75 14				jne	short spm_prev_saved	; Y: return error
									; N: use it now
 0174  FC				cld
 0175  1E				push	ds
 0176  07				pop	es
 0177  AB				stosw					; store handle # in s_handle
					Get_FRS_window	SI			; Current FRS page mappings
 0178  8B 36 0000 E          1		mov	SI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 017C  83 C6 00              1		add	SI, FRS_window			; points to FRS window entries 
 017F  66| A5				movsd					; move to save area
 0181  66| A5				movsd					; Lim 3.2 has only 4 page frames
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-21


				
 0183  C6 46 1D 00			mov	byte ptr [bp.rAX+1],OK	; ok return
 0187  C3				ret
				
 0188				spm_prev_saved:
 0188  C6 46 1D 8D			mov	byte ptr [bp.rAX+1],MAP_PREV_SAVED
 018C  C3				ret
				
 018D				srpm_inv_handle:					; Shared error returns
 018D  C6 46 1D 83			mov	byte ptr [bp.rAX+1],INVALID_HANDLE
 0191  C3				ret
				
 0192				srpm_nopf:
 0192  C6 46 1D 81			mov	byte ptr [bp.rAX+1], EMM_HW_MALFUNCTION ; No page frame!!!
 0196  C3				ret
				
 0197				_SavePageMap	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-22


					page
				;***********************************************
				;
				; _RestorePageMap - restore handle's saved page mapping
				;
				;	This routine restores the current page mapping context 
				;	from a handle's save area.
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 AH = 08h = restore page map function # 
				;	 DX = EMM handle
				; 	REGS on STACK:	SI = not used by this function
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;
				; EXIT:	current state restored
				;	AH = status of this function
				;
				; USED: AX,BX,CX,DX,SI,DI
				;
				;***********************************************
				
				Dword_Align	_TEXT
 0197  90                    1		db	90h		     ; 
 0198				_RestorePageMap	proc	near
 0198  83 3E 0000 E 04			cmp	[_page_frame_pages], 4
 019D  72 F3				jb	short srpm_nopf		; no page frame
				
 019F  8B C2				mov	ax, dx			; Save for later
					Validate_Handle	srpm_inv_handle
 01A1  3B 16 0000 E          1		cmp	dx, [_handle_table_size]	;Q: handle in range ? 
 01A5  73 E6                 1		jae	srpm_inv_handle			;  N: go to error label 
 01A7  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 01AA  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 01AE  87 DA                 1		xchg	bx, dx 
 01B0  83 3F FF              1		cmp	[bx.ht_index], NULL_PAGE	;Q: is this handle active ? 
 01B3  87 DA                 1		xchg	bx, dx 
 01B5  74 D6                 1		je	srpm_inv_handle			;  N: return error 
									; check state of handle's page area
 01B7  6B D8 0A				imul	bx,ax,SIZE SaveMap_struc ; BX = offset within Save Area for
									;  this handle's save area
 01BA  8D B7 0000 E			lea	si,_save_map[bx]	; DS:SI points to handle's save area
 01BE  81 3C 0FFF			cmp	[si].s_handle,NULL_HANDLE
									;Q: save area in use ?
 01C2  74 1C				je	short rpm_no_map_saved	; N: return error
									; Y: restore it
				
 01C4  C6 46 1D 00			mov	byte ptr [bp.rAX+1],OK		; Assume success
 01C8  C7 04 0FFF			mov	[si].s_handle,NULL_HANDLE	; null handle's save area
				
 01CC  8D 74 02				lea	si,[si].s_map			; SI -> handle's save area
					Get_FRS_window	DI			; Get pointer to current window
 01CF  8B 3E 0000 E          1		mov	DI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 01D3  83 C7 00              1		add	DI, FRS_window			; points to FRS window entries 
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-23


 01D6  1E				push	ds
 01D7  07				pop	es				; ES <-- DGROUP
 01D8  FC				cld
 01D9  66| A5				movsd					; restore 4 words
 01DB  66| A5				movsd					; Lim 3.2 has only 4 page frames
 01DD  E9 026C R			jmp	_set_windows			; Restore mapping
				
 01E0				rpm_no_map_saved:
 01E0  C6 46 1D 8E			mov	byte ptr [bp.rAX+1],NO_MAP_SAVED
 01E4  C3				ret
				
 01E5				_RestorePageMap	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-24


					page
				;***********************************************
				;
				; _GetSetPageMap - get/set page map to/from external save area
				;
				;	This routine stores the current page mapping context (Intel
				; compatible form for now) to an external save area and/or restores
				; the current page mapping context from an external save area.
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 AH = 4Eh = Get/Set page map function number
				;     or AH = 5Ch = Get/Set large page map function number
				;	 AL = SUBFUNCTION CODE
				;		AL = 0  => Get page map
				;		AL = 1  => Set page map
				;		AL = 2  => Get and Set page map
				;		AL = 3  => return size of page map
				; 	REGS on STACK:	SI = not used by this function
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;
				; EXIT:	current state saved / restored
				;	AH = status of this function
				;
				; USED: BX,CX,DX,SI,DI
				;
				;***********************************************
				Dword_Align	_TEXT
 01E5  90                    1		db	90h		     ; 
 01E6  90                    2		db	90h		     ; 
 01E7  90                    3		db	90h		     ; 
 01E8				_GetSetPageMap	proc	near
				
 01E8  3C 00				cmp	al,GSPM_GET	   	;Q: get page map subfunction ?
 01EA  74 28				je	short _get_map		;  Y: get it
				
 01EC  3C 01				cmp	al,GSPM_SET		;Q: set page map subfunction ?
 01EE  0F 84 0238 R			je	_set_map		;  Y: set it
				
 01F2  3C 02				cmp	al,GSPM_GETSET		;Q: get & set page map subfunction ?
 01F4  75 05				jne	short gspm_chk_size	;  N: check for size function
 01F6  E8 0214 R			call	_get_map		;  Y: get current map first
 01F9  EB 3D				jmp	short _set_map		;     set new one
				
 01FB				gspm_chk_size:
 01FB  3C 03				cmp	al, GSPM_SIZE		;Q: return map size subfunction ?
 01FD  75 09				jne	short gspm_inv_subfun	;  N: return invalid subfunction
				
 01FF  A0 0000 E			mov	al, [_cntxt_bytes]		; size of map
 0202  B4 00				mov	ah, OK				; ok return
 0204  89 46 1C				mov	word ptr [bp.rAX], ax
 0207  C3				ret
				
 0208				gspm_inv_subfun:
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-25


 0208  C6 46 1D 8F			mov	byte ptr [bp.rAX+1],INVALID_SUBFUNCTION
 020C  C3				ret
				
 020D				gspm_inv_fun:
 020D  C6 46 1D 84			mov	byte ptr [bp.rAX+1],INVALID_FUNCTION
 0211  C3				ret
				
 0212				_GetSetPageMap	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-26


					page
				;***********************************************
				;
				; _get_map - save current mapping register state to external area
				;
				;	ENTRY: on stack
				;		clients ES:DI -> client's buffer for state
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;
				;	EXIT:  state stored in client's buffer
				;		return code set on stack
				;
				;	USED: AX,BX,CX,DX,SI,DI,ES
				;
				;  DESCRIPTION:	This function saves the current mapping
				;		into the save area specified.
				;
				;***********************************************
				Dword_Align	_TEXT
 0212  90                    1		db	90h		     ; 
 0213  90                    2		db	90h		     ; 
 0214				_get_map	proc
				
 0214  FC				cld
 0215  E8 0000 E			call	_dest_addr			; DX:AX ptr for client's buff
 0218  8E C2				mov	es,dx
 021A  8B F8				mov	di,ax				; ES:DI pts to clients buffer
				
					Get_FRS_window	SI			; Get pointer to current window
 021C  8B 36 0000 E          1		mov	SI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0220  83 C6 00              1		add	SI, FRS_window			; points to FRS window entries 
 0223  66| 0F B6 0E 0000 E		movzx	ecx, [_cntxt_pages]
 0229  8B C1				mov	ax, cx
 022B  AB				stosw					; save # pages
 022C  D1 E9				shr	cx, 1				; now dwords
 022E  F3/ 66| A5			rep movsd				; mov bytes to current map area
 0231  C6 46 1D 00			mov	byte ptr [bp.rAX+1],OK		; ok return
 0235  C3				ret
				
 0236				_get_map	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-27


					page
				;***********************************************
				;
				; _set_map - restore mapping register state
				;
				;	ENTRY: on stack
				;		clients DS:SI -> client's buffer containing state to restore
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;
				;	EXIT:  state restored from client's buffer
				;		return code set on stack
				;		CLC => no errors
				;		STC => error occurred
				;
				;	USED: EAX,BX,CX,DX,SI,DI,ES
				;
				;
				;  DESCRIPTION:	This function restores the mapping from the state info input.
				;		The mapping is assumed to be the same as in the
				;		save_current_map function.  The count in the saved
				;		state is verified.
				;		
				;***********************************************
				Dword_Align	_TEXT
 0236  90                    1		db	90h		     ; 
 0237  90                    2		db	90h		     ; 
 0238				_set_map	proc	near
				
 0238  C6 46 1D 00			mov	byte ptr [bp.rAX+1],OK		; Assume success
					Get_FRS_window	DI			; Get pointer to current window
 023C  8B 3E 0000 E          1		mov	DI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0240  83 C7 00              1		add	DI, FRS_window			; points to FRS window entries 
										; before DS gets trashed
 0243  1E				push	ds
 0244  07				pop	es				; use ES to address data
 0245  52				push	dx
 0246  8B F0				mov	si, ax
 0248  E8 0000 E			call	_source_addr			; DX:AX ptr for client's buff
 024B  8E DA				mov	ds,dx
 024D  96				xchg	si,ax				; DS:SI pts to clients buffer
 024E  5A				pop	dx
				
 024F  FC				cld
 0250  26: 66| 0F B6 0E 0000		movzx	ecx, es:[_cntxt_pages]		; number of words in mapping
	E			
 0257  AD				lodsw					; saved size
 0258  3B C1				cmp	ax, cx				; should be this
 025A  75 0A				jne	short sm_inv_source		; Wrong, saved data corrupted
 025C  D1 E9				shr	cx, 1				; now a word count
 025E  F3/ 66| A5			rep movsd
 0261  06				push	es
 0262  1F				pop	ds				; DS <-- DGROUP
 0263  EB 07 90				jmp	_set_windows			; make it effective
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-28


				
 0266				sm_inv_source:
 0266  C6 46 1D A3			mov	byte ptr [bp.rAX+1], SOURCE_CORRUPTED
 026A  C3				ret
				
 026B				sm_exit:
 026B  C3				ret
				
 026C				_set_map	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-29


					page
				;***********************************************
				;
				; _set_windows - re-map all mapped physical pages
				;
				; This routine maps all mapped 386 pages of the EMM page frame into the
				; linear address space for the page frame.
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 DS = DGROUP
				;	 SS:[BP] -> regp stack frame
				;
				; EXIT:	page tables changed to map these pages.
				;	_current_map contents initialized.
				;
				; uses:
				;	FLAGS, EAX, EBX, ECX, ESI, EDI
				;
				;***********************************************
				;
 026C				_set_windows	proc	near
				;
 026C  33 C0				xor	ax, ax			; start from PHYS page 0
					Get_FRS_Window	SI		; SI <-- current FRS map
 026E  8B 36 0000 E          1		mov	SI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0272  83 C6 00              1		add	SI, FRS_window			; points to FRS window entries 
 0275				sw_loop:
 0275  8B 1C				mov	bx, word ptr [si]	; BX <-- emm page #
 0277  83 C6 02				add	si, 2		  	; prepare for next PHYS page
 027A  83 FB FF				cmp	bx, 0FFFFh	  	; not mapped ?
 027D  0F 84 02AF R			je	sw_unmap_page		;  Y: unmap it
 0281  3B 1E 0000 E			cmp	bx, [_total_pages]	; emm page out of range ?
 0285  0F 87 02B8 R			ja	sw_corrupt		;  Y: error
 0289  8B FB				mov	di, bx
 028B  C1 E7 02				shl	di, 2			; SI <-- _pft386 offset of emm page
 028E  03 3E 0000 E			add	di, [_pft386]
 0292  66| 83 3D 00			cmp	dword ptr [di], 0	; pte not mapped ?
 0296  0F 84 02B8 R			je	sw_corrupt		;  Y: error
 029A  66| 50				push	eax
 029C  E8 0000 R			call	map_EMM_page		; map a page
 029F  66| 58				pop	eax
 02A1				sw_done_page:
 02A1  40				inc	ax
 02A2  3B 06 0000 E			cmp	ax, [_physical_page_count]
 02A6  72 CD				jb	sw_loop			; next page
				
 02A8  0F 20 D8				mov	eax, cr3
 02AB  0F 22 D8				mov	cr3, eax		; flush TLB
 02AE  C3				ret
				
 02AF				sw_unmap_page:
 02AF  66| 50				push	eax
 02B1  E8 005D R			call	unmap_Page
 02B4  66| 58				pop	eax
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-30


 02B6  EB E9				jmp	short sw_done_page
				
 02B8				sw_corrupt:
 02B8  C6 46 1D A3			mov	byte ptr [bp.rAX+1], SOURCE_CORRUPTED
 02BC  5A				pop	dx
 02BD  C3				ret
				
 02BE				_set_windows	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-31


					page
				;*******************************************************************************
				;
				;	LIM 4.0 EXTRAS for Windows
				;
				;*******************************************************************************
				
				;***********************************************
				;
				; _GetSetPartial - get/set partial page map to/from external save area
				;
				;	This routine stores the current page mapping context
				; to an external save area and/or restores the current page
				; mapping context from an external save area.
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 AH = 4Fh = Get/Set page map function number
				;	 AL = SUBFUNCTION CODE
				;		AL = 0  => Get page map
				;		AL = 1  => Set page map
				;		AL = 2  => return size of page map
				; 	REGS on STACK:	SI = not used by this function
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;
				; EXIT:	current state saved / restored
				;	AH = status of this function
				;
				; USED: BX,CX,DX,SI,DI
				;
				;***********************************************
 02BE				_GetSetPartial	proc	near
 02BE  3C 00				cmp	al, 0			; Get...?
 02C0  0F 85 033C R			jne	gsppm_not0
				
 02C4  E8 0000 E			call	_source_addr		; uses AX, DX
 02C7  8E E2				mov	fs, dx
 02C9  8B F0				mov	si, ax
 02CB  E8 0000 E			call	_dest_addr		; uses AX, DX
 02CE  8E C2				mov	es, dx
 02D0  8B F8				mov	di, ax
 02D2  FC				cld
 02D3  64: AD				lods	word ptr fs:[si]
 02D5  AB				stosw				; Save count in save area
 02D6  0B C0				or	ax, ax
 02D8  0F 84 0337 R			jz	gsppm_ok		; nothing to do
 02DC  66| 0F B7 C8			movzx	ecx, ax
				
 02E0  8B 16 0000 E			mov	dx, [_mappable_page_count]
 02E4  3B CA				cmp	cx, dx
 02E6  0F 87 03C7 R			ja	gsppm_inv_phys
 02EA				gsppm_get_loop:
 02EA  64: AD				lods	word ptr fs:[si]		; Get segment
 02EC  C1 E8 0A				shr	ax, 10				; 16k page number
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-32


 02EF  2D 0010				sub	ax, CONV_STRT_PG		; first page in emm_mpindex arr
 02F2  0F 82 03C7 R			jb	gsppm_inv_seg			; only pages above 256k
 02F6  8B D8				mov	bx, ax
 02F8  8A 87 0000 E			mov	al, EMM_MPindex[bx]		; convert to physical page
 02FC  3C FF				cmp	al, -1				; does it exist
 02FE  0F 84 03C7 R			je	gsppm_inv_seg
 0302  8B D8				mov	bx, ax
 0304  C1 E3 02				shl	bx, 2
 0307  8D 87 0000 E			lea	ax, _mappable_pages[bx]
 030B  8B D8				mov	bx, ax
 030D  8B 1F				mov	bx, [bx.mappable_seg]		; segment for this page
 030F  64: 3B 5C FE			cmp	bx, fs:[si-2]
 0313  0F 85 03C7 R			jne	gsppm_inv_seg			; must match exactly
 0317  8B D8				mov	bx, ax
 0319  66| 0F B7 5F 02			movzx	ebx, [bx.mappable_pg]		; the physical page
 031E  3B DA				cmp	bx, dx
 0320  0F 87 03C7 R			ja	gsppm_inv_seg
 0324  8B C3				mov	ax, bx
 0326  AB				stosw					; Save physical page
					Get_FRS_window	BX			; Get pointer to current window
 0327  8B 1E 0000 E          1		mov	BX, word ptr [CurRegSet]	; just offset (assume dgroup) 
 032B  83 C3 00              1		add	BX, FRS_window			; points to FRS window entries 
 032E  03 D8				add	bx, ax				; get ptr to emm page# in FRS
 0330  03 D8				add	bx, ax
 0332  8B 07				mov	ax, [bx]
 0334  AB				stosw					; and current mapping
 0335  E2 B3				loop	gsppm_get_loop
				
 0337				gsppm_ok:
 0337  C6 46 1D 00			mov	byte ptr [bp.rAX+1], OK
 033B  C3				ret
					
 033C				gsppm_not0:
 033C  3C 01				cmp	al, 1				; Set...?
 033E  0F 85 03AA R			jne	gsppm_not1
										; Set Partial Page Map
 0342  E8 0000 E			call	_source_addr			; uses AX, DX
 0345  8E E2				mov	fs, dx
 0347  8B F0				mov	si, ax
 0349  64: 66| 0F B7 0C			movzx	ecx, word ptr fs:[si]		; Get count from save area
 034E  83 C6 02				add	si, 2
 0351  67| E3 E3			jecxz	gsppm_ok			; Zero count, do nothing
				
					Get_FRS_window	DX			; Get pointer to current window
 0354  8B 16 0000 E          1		mov	DX, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0358  83 C2 00              1		add	DX, FRS_window			; points to FRS window entries 
 035B  3B 0E 0000 E			cmp	cx, [_mappable_page_count]
 035F  77 44				ja	short gsppm_corrupt		; can't be more than phys pages
 0361				gsppm_set_loop:
 0361  66| 56				push	esi
 0363  64: 66| 0F B7 04			movzx	eax, word ptr fs:[si]		; Get Physical page
 0368  3B 06 0000 E			cmp	ax, [_mappable_page_count]
 036C  0F 83 03A3 R			jae	gsppm_sl_bad
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-33


 0370  64: 66| 0F B7 74 02		movzx	esi, word ptr fs:[si+2]		; Get mapping (emm page#)
 0376  8B FA				mov	di,dx
 0378  03 F8				add	di,ax
 037A  03 F8				add	di,ax				; di <-- current FRS phy page
 037C  89 35				mov	[di], si			; Save new mapping
				
 037E  83 FE FF				cmp	si, 0FFFFh			; Unmapped?
 0381  74 1B				je	short gsppm_unmap		;   yes, go unmap it
 0383  3B 36 0000 E			cmp	si, [_total_pages]		; valid page?
 0387  73 1A				jae	short gsppm_sl_bad		;   no, fail
				
 0389  8B DE				mov	bx, si				; bx <-- emm page#
										; ax <-- phys page#
 038B  E8 0000 R			call	map_EMM_page
				
 038E				gsppm_set_done:
 038E  66| 5E				pop	esi
 0390  66| 83 C6 04			add	esi, 4				; Next page to map
 0394  E2 CB				loop	gsppm_set_loop
 0396  0F 20 D8				mov	eax, cr3			; Flush TLB
 0399  0F 22 D8				mov	cr3, eax
 039C  EB 99				jmp	gsppm_ok
				
 039E				gsppm_unmap:
 039E  E8 005D R			call	unmap_page			; with ax <-- phys page#
 03A1  EB EB				jmp	gsppm_set_done			; On to next page
				
 03A3				gsppm_sl_bad:
 03A3  66| 5E				pop	esi
 03A5				gsppm_corrupt:
 03A5  C6 46 1D A3			mov	byte ptr [bp.rAX+1], SOURCE_CORRUPTED
 03A9  C3				ret
				
 03AA				gsppm_not1:
 03AA  3C 02				cmp	al, 2				; Size?
 03AC  0F 85 0208 R			jne	gspm_inv_subfun
 03B0  3B 1E 0000 E			cmp	bx, [_mappable_page_count]	; # of page frames
 03B4  77 11				ja	short gsppm_inv_phys
 03B6  C1 E3 02				shl	bx, 2				; Size = pages * 4 + 2
 03B9  83 C3 02				add	bx, 2
 03BC  88 5E 1C				mov	byte ptr [bp.rAX], bl
 03BF  E9 0337 R			jmp	gsppm_ok
				
 03C2				gsppm_inv_subfun:
 03C2  C6 46 1D 8F			mov	byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
 03C6  C3				ret
				
 03C7				gsppm_inv_phys:
 03C7				gsppm_inv_seg:
 03C7  C6 46 1D 8B			mov	byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
 03CB  C3				ret
				
 03CC				_GetSetPartial	endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-34


					page
				;***********************************************
				;
				; _MapHandleArray - map an array of a handle's pages
				;
				; This routine maps the physical pages according to
				; an array of mappings.
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 AH = 50h = map handle page function # 
				;	 AL = Subfunction: 0)	Physical pages described by their number
				;			   1)	Physical pages described by segment
				;	 CX = number of pages to be mapped
				;	 DX = EMM handle
				; 	REGS on STACK	DS:SI = array of mappings
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;   NOTE:
				;	There is a second entry point for this procedure at the label
				;	MapHandleArray_Entry_2.  The entry conditions for this are identical
				;	to those specified above except that ESI points to the mapping array--
				;	the DS:SI on the stack are ignored.  Also, the value in AH is undefined.
				;	This entry point is used by the AlterMapAndJump and AlterMapAndCall
				;	functions.
				;
				; EXIT:	context block ve_window set up
				;	page table entries set up
				;	AH = status of this function
				;		= EMM_HW_MALFUNCTION if entry in real/virtual mode.
				;
				; USED: AX,BX,DX,SI,DI,FS
				;
				;***********************************************
				Dword_Align	_TEXT
 03CC				_MapHandleArray	proc	near
 03CC  8B F0				mov	si, ax
 03CE  52				push	dx
 03CF  E8 0000 E			call	_source_addr			; DX:AX <-- mapping array
 03D2  96				xchg	si, ax
 03D3  8E E2				mov	fs, dx
 03D5  5A				pop	dx				; FS:SI <-- mapping array
				
 03D6				MapHandleArray_Entry_2:
 03D6  3C 01				cmp	al, 1			; Q: Is subfunction 0 or 1?
 03D8  0F 87 0461 R			ja	mha_inv_sub		;    N: Invalid subfunction
				
					Validate_Handle <mha_inv_handle>
 03DC  3B 16 0000 E          1		cmp	dx, [_handle_table_size]	;Q: handle in range ? 
 03E0  0F 83 045C R          1		jae	mha_inv_handle			;  N: go to error label 
 03E4  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 03E7  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 03EB  87 DA                 1		xchg	bx, dx 
 03ED  83 3F FF              1		cmp	[bx.ht_index], NULL_PAGE	;Q: is this handle active ? 
 03F0  87 DA                 1		xchg	bx, dx 
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-35


 03F2  0F 84 045C R          1		je	mha_inv_handle			;  N: return error 
				
 03F6  C6 46 1D 00			mov	byte ptr [bp.rAX+1], OK		; Assume success
 03FA  66| 0F B7 C9			movzx	ecx, cx
 03FE  67| E3 54			jecxz	short mha_exit			;   none to do, just return
				
 0401  0A C0				or	al, al				; which subfunction?
 0403  75 17				jnz	short mha_sub1			; subfunction 1?
				
						;
						; Subfunction 0:  array contains logical and physical
						; 		  page numbers.
						;
 0405				mha_sub0:
 0405  64: 66| 0F B7 44 02		movzx	eax, fs:[si.mha0_phys_pg]	; physical page number
 040B  64: 66| 0F B7 1C			movzx	ebx, fs:[si.mha0_log_pg]	; logical page number
 0410  E8 00D2 R			call	map_page			; map it if possible
 0413  72 40				jc	short mha_exit			; Error code already set
 0415  83 C6 04				add	si, size mha_array0
 0418  E2 EB				loop	mha_sub0
 041A  EB 39				jmp	short mha_exit
				
						;
						; Subfunction 1:  array contains logical page number and
						; 		  segment numbers corresponding to the
						; 		  desired physical pages.
						;
 041C				mha_sub1:
 041C  64: 8B 7C 02			mov	di, fs:[si.mha1_seg]		; segment to map
 0420  8B C7				mov	ax, di				; save for later
 0422  C1 EF 0A				shr	di, 10				; 16k page number
 0425  83 EF 10				sub	di, CONV_STRT_PG		; first page in emm_mpindex arr
 0428  72 3C				jb	short mha_inv_seg		; only pages above 256k
 042A  66| 0F BE BD 0000 E		movsx	edi, EMM_MPindex[di]		; convert to physical page
 0430  66| 83 FF FF			cmp	edi, -1				; does it exist
 0434  74 30				je	short mha_inv_seg
 0436  C1 E7 02				shl	di, 2				; index * 4
 0439  8D BD 0000 E			lea	di, _mappable_pages[di]
 043D  3B 05				cmp	ax, [di.mappable_seg]		; segment for this page
 043F  75 25				jne	short mha_inv_seg		; must match exactly
 0441  66| 0F B7 45 02			movzx	eax, [di.mappable_pg]		; the physical page
 0446  64: 66| 0F B7 1C			movzx	ebx, fs:[si.mha1_log_pg]	; the logical page
 044B  E8 00D2 R			call	map_page			; try to map it
 044E  72 05				jc	short mha_exit			; error code already set
 0450  83 C6 04				add	si, size mha_array1
 0453  E2 C7				loop	mha_sub1			; back for next segment to map
				
 0455				mha_exit:
 0455  0F 20 D8				mov	eax, cr3			; Always clear TLB, we may have
 0458  0F 22 D8				mov	cr3, eax			; mapped pages before an error
 045B  C3				ret
										; ERRORS...
 045C				mha_inv_handle:
 045C  C6 46 1D 83			mov	byte ptr [bp.rAX+1], INVALID_HANDLE
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-36


 0460  C3				ret
 0461				mha_inv_sub:
 0461  C6 46 1D 8F			mov	byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
 0465  C3				ret
 0466				mha_inv_seg:
 0466  C6 46 1D 8B			mov	byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
 046A  EB E9				jmp	mha_exit
				
 046C				_MapHandleArray	endp
				
				
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-37


					page
				;***********************************************
				;
				; _AlterMapAndJump - map an array of a handle's pages and Jump to a
				;		     a specified address
				;
				; This routine maps pages using the MapHandleArray procedure and jumps
				; to the specified address
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 AL = Mapping method -- 0 = Physical pages, 1 = Segments
				;	 DX = EMM handle
				;	REGS on STACK
				;	REGS on STACK -- DS:SI -> Map and Jump structure
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;
				; EXIT: context block ve_window set up
				;	page table entries set up
				;	AH = status of this function
				;		= EMM_HW_MALFUNCTION if entry in real/virtual mode.
				;	Address specified in Map and Jump structure will be new return address
				;
				; USED: AX,BX,CX,SI,DI,FS,GS
				;
				;**********************************************
				
 046C				_AlterMapAndJump    PROC    NEAR
				
 046C  52				push	dx
 046D  8B F0				mov	si, ax
 046F  E8 0000 E			call	_source_addr		; DX:AX <-- map & jump struct
 0472  8E EA				mov	gs, dx
 0474  96				xchg	si, ax			; GS:SI <-- map & jump struct
 0475  5A				pop	dx
 0476  56				push	si
 0477  50				push	ax
 0478  52				push	dx					; save EMM handle
 0479  65: 8B 54 05			mov	dx, WORD PTR gs:[si.maj_map_address]	; AX:DX <-- map array
 047D  65: 8B 44 07			mov	ax, WORD PTR gs:[si.maj_map_address+2]
					Set_EMM_GDT	EMM2_GSEL
 0481  BB 0108               1		mov	bx, EMM2_GSEL			; GDT selector 
 0484  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 0487  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 048A  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 048C  6A 08                 1		push	GDTD_GSEL 
 048E  07                    1		pop	es				; ES:0 <-- GDT 
 048F  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 0492  8E E3				mov	fs, bx					; FS:0 <-- map array
 0494  5A				pop	dx					; restore handle
 0495  58				pop	ax					; restore subfunction
 0496  65: 66| 0F B6 4C 04		movzx	ecx, byte ptr gs:[si.maj_log_phys_map_len] ; Length of map
 049C  33 F6				xor	si, si					; FS:SI <-- map array
 049E  E8 03D6 R			call	MapHandleArray_Entry_2	    ; Map the array
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-38


 04A1  5E				pop	si
				
 04A2  8A 66 1D				mov	ah, byte ptr [bp.rAX+1]
 04A5  0A E4				or	ah, ah
 04A7  75 1E				jnz	SHORT AMJ_Error
 04A9  65: 66| 8B 04			mov	eax, dword ptr gs:[si.maj_target_address]
 04AD  89 46 20				mov	word ptr [bp.retaddr], ax  ; Put jump address in place of
 04B0  66| C1 E8 10			shr	eax, 16 		   ; old IRET return address
 04B4  89 46 22				mov	word ptr [bp.rCS], ax
					;
					; now, pop 5 words from client's stack because we are not
					; going to go back. (See AlterMapAndCall for client's
					; Stack frame structure)
					;
 04B7  66| 8B 7E 3E			mov	edi, dword ptr [bp.rFS+2+VTFO.VMTF_ESP]	; clients's ESP
 04BB  66| 83 C7 0A			add	edi, 5 * 2				; "pop" 5 words
 04BF  66| 89 7E 3E			mov	dword ptr [bp.rFS+2+VTFO.VMTF_ESP], edi	; save it
					;
					; tell EMMpEntry to patch CS:IP onto its' iretd stack frame
					;
 04C3  83 4E 24 08			or	word ptr [bp.PFlag], PFLAG_PATCH_CS_IP
 04C7				AMJ_Error:				    ; Do the jump
 04C7  C3				ret
				
 04C8				_AlterMapAndJump    ENDP
				
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-39


					page
				;***********************************************
				;
				; _AlterMapAndCall - map an array of a handle's pages and call a procedure
				;		     at a specified address (similar to a FAR call)
				;		     This function pushes the return address on the
				;		     client's stack and Jumps to the specified procedure.
				;		     The "Called" procedure will return to AMC_return_address
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 AL = Subfunction -- 0 = Map phys pages, 1 = Map segs, 2 = Frame size
				;	 DX = EMM handle
				;	REGS on STACK	DS:SI = Map and Call structure
				;	 SS:[BP] -> regp stack frame
				;	 DS = DGROUP
				;
				; EXIT: context block ve_window set up
				;	page table entries set up
				;	Transfer Space pushed on client's stack
				;	Return address CS and IP will point to called procedure
				;	AH = status of this function
				;		= EMM_HW_MALFUNCTION if entry in real/virtual mode.
				;
				; USED: AX,BX,CX,DX,SI,DI
				;
				;***********************************************
				
 04C8				_AlterMapAndCall    PROC    NEAR
				
 04C8  3C 02				cmp	al, 2			; Q: Which subfuction ?
 04CA  0F 87 0686 R			ja	AMC_inv_sub		;  >2: invalid subfunction
 04CE  0F 84 0669 R			je	AMC_Stack_Fram_Size	;  =2: Stack frame size subfuncion
									;  <2: map and call
 04D2  52				push	dx
 04D3  8B F0				mov	si, ax
 04D5  E8 0000 E			call	_source_addr		; DX:AX <-- map & call structure
 04D8  8E EA				mov	gs, dx
 04DA  96				xchg	si, ax			; GS:SI <-- map & call structure
 04DB  5A				pop	dx
					;
					; check new and old map's length
					;
 04DC  32 ED				xor	ch, ch
 04DE  65: 8A 4C 09			mov	cl, byte ptr gs:[si.mac_old_page_map_len] ; CX = Length of old map
 04E2  3B 0E 0000 E			cmp	cx, [_physical_page_count]
 04E6  0F 83 0681 R			jae	AMC_inv_phys_pages
 04EA  65: 8A 4C 04			mov	cl, byte ptr gs:[si.mac_new_page_map_len] ; CX = Length of new map
 04EE  3B 0E 0000 E			cmp	cx, [_physical_page_count]
 04F2  0F 83 0681 R			jae	AMC_inv_phys_pages
					;
					; get client's SS:ESP so we can push stuffs on it
					;
 04F6  50				push	ax
 04F7  52				push	dx
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-40


				
 04F8  66| 8B 7E 3E			mov	edi, dword ptr [bp.rFS+2+VTFO.VMTF_ESP]	; clients's ESP
 04FC  8B 46 42				mov	ax, word ptr [bp.rFS+2+VTFO.VMTF_SS]	; client's SS
 04FF  33 D2				xor	dx, dx					; AX:DX <-- Seg:Off of Client's Stack
				
 0501  50				push	ax				; client's Stack Segment
					Set_EMM_GDT	EMM2_GSEL
 0502  BB 0108               1		mov	bx, EMM2_GSEL			; GDT selector 
 0505  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 0508  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 050B  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 050D  6A 08                 1		push	GDTD_GSEL 
 050F  07                    1		pop	es				; ES:0 <-- GDT 
 0510  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 0513  53				push	bx				; client's Stack Selector
					;
					; get CS's Base to "push" on stack for later retf from client
					;
 0514  6A 08				push	GDTD_GSEL
 0516  07				pop	es				; ES:0 <-- GDT
 0517  8C CB				mov	bx, cs				; selector
 0519  80 E3 F8				and	bl, SEL_LOW_MASK
 051C  26: 8B 57 02			mov	dx, word ptr es:[bx + 2]	; get lower 16 bit of Base
 0520  26: 8A 47 04			mov	al, byte ptr es:[bx + 4]	; get upper 8 bit of Base
 0524  C1 EA 04				shr	dx, 4
 0527  C0 E0 04				shl	al, 4
 052A  0A F0				or	dh, al				; get the segment value
 052C  8B DA				mov	bx, dx				; into BX
				
 052E  07				pop	es				; ES:DI <-- client's SS
 052F  59				pop	cx				; CX <-- Client's stack Segment
				
 0530  5A				pop	dx
 0531  58				pop	ax
					;
					; save client's stack segment and target address on stack
					; cause they (CX and EMM1_GSEL) get destroy
					;
 0532  51				push	cx
 0533  65: FF 74 02			push	word ptr gs:[si].mac_target_address+2
 0537  65: FF 34			push	word ptr gs:[si].mac_target_address
					;
					; On the Client's stack :
					;
					; +-----------------+
					; | client's Flag   |
					; +-----------------+
					; | client's CS	    |
					; +-----------------+
					; | client's IP	    |
					; +-----------------+
					; | EMM_rEntry's CS |
					; +-----------------+
					; | EMM_rEntry's IP | <-- "SS:ESP" (ES:EDI)
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-41


					; +-----------------+
					;
					; "pop" EMM_rEntry's CS:IP off the stack, save it on Ring0 stack
					; in case thereis an error and need to restore state of stack.
					; keep the rest (client's FLAG, CS and IP)
					;
 053A  26: FF 75 02			push	es:[di+2]	; EMM_rEntry's CS
 053E  26: FF 35			push	es:[di]		; EMM_rEntry's IP
 0541  83 C7 04				add	di, 2 * 2	; "pop"
					;
					; save old map on stack
					;
 0544  65: 66| 0F B6 4C 09		movzx	ecx, byte ptr gs:[si.mac_old_page_map_len]  ; CX = Length of old map
 054A  C1 E1 02				shl	cx, 2				; CX * 4 (4 bytes each entry)
 054D  41				inc	cx				; one more for length
					get_space_from_stack	CX		; ES:DI <-- space on stack
 054E  2B F9                 1		sub	di, CX 
 0550  49				dec	cx
 0551  C1 E9 02				shr	cx, 2				; CX back to length in bytes
				
 0554  1E				push	ds
 0555  57				push	di				; save postion of stack
 0556  56				push	si
 0557  50				push	ax
 0558  53				push	bx
 0559  52				push	dx
 055A  51				push	cx				; save #pages
				
 055B  FC				cld
 055C  65: 8B 54 0A			mov	dx, word ptr gs:[si.mac_old_map_address]    ; AX:DX <-- map array
 0560  65: 8B 44 0C			mov	ax, word ptr gs:[si.mac_old_map_address+2]
 0564  06				push	es
					Set_EMM_GDT	USER1_GSEL
 0565  BB 0130               1		mov	bx, USER1_GSEL			; GDT selector 
 0568  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 056B  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 056E  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 0570  6A 08                 1		push	GDTD_GSEL 
 0572  07                    1		pop	es				; ES:0 <-- GDT 
 0573  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 0576  07				pop	es
 0577  8E DB				mov	ds, bx				; DS:0 <-- map array
 0579  33 F6				xor	si, si
 057B  59				pop	cx
 057C  8B C1				mov	ax, cx
 057E  AA				stosb					; store length of map
				
 057F  D1 E1				shl	cx, 1				; move word
 0581  F3/ A5				rep movsw
				
 0583  5A				pop	dx				; restore handle
 0584  5B				pop	bx				; restore Segment of client Stack
 0585  58				pop	ax				; restore subfunction
 0586  5E				pop	si
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-42


 0587  5F				pop	di
 0588  1F				pop	ds
					;
					; save FRS context on stack
					;
 0589  66| 0F B6 0E 0000 E		movzx	ecx, [_cntxt_bytes]
					get_space_from_stack	CX		; ES:DI <-- space on stack
 058F  2B F9                 1		sub	di, CX 
				
 0591  56				push	si
 0592  57				push	di
					get_FRS_Window		SI		; DS:SI <-- mapping context
 0593  8B 36 0000 E          1		mov	SI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0597  83 C6 00              1		add	SI, FRS_window			; points to FRS window entries 
 059A  66| D1 E9			shr	ecx, 1				; move words
 059D  F3/ A5				rep movsw
				
 059F  5F				pop	di
 05A0  5E				pop	si
					;
					; map new mapping
					;
 05A1  53				push	bx
 05A2  50				push	ax
 05A3  52				push	dx
				
 05A4  57				push	di					; save "stack pointer"
 05A5  56				push	si
 05A6  50				push	ax
 05A7  52				push	dx					; save EMM handle
 05A8  65: 8B 54 05			mov	dx, WORD PTR gs:[si.mac_new_map_address]; AX:DX <-- map array
 05AC  65: 8B 44 07			mov	ax, WORD PTR gs:[si.mac_new_map_address+2]
 05B0  06				push	es
					Set_EMM_GDT	USER1_GSEL
 05B1  BB 0130               1		mov	bx, USER1_GSEL			; GDT selector 
 05B4  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 05B7  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 05BA  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 05BC  6A 08                 1		push	GDTD_GSEL 
 05BE  07                    1		pop	es				; ES:0 <-- GDT 
 05BF  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 05C2  07				pop	es
 05C3  8E E3				mov	fs, bx					; FS:0 <-- map array
 05C5  33 F6				xor	si, si
 05C7  5A				pop	dx					; restore handle
 05C8  58				pop	ax					; restore subfunction
 05C9  65: 66| 0F B6 4C 04		movzx	ecx, byte ptr gs:[si.mac_new_page_map_len]
 05CF  E8 03D6 R			call	MapHandleArray_Entry_2	    ; Map the array
 05D2  5E				pop	si			    ; Restore structure pointer
 05D3  5F				pop	di			    ; restore "stack" pointer
 05D4  5A				pop	dx
 05D5  58				pop	ax
 05D6  8A 7E 1D				mov	bh, byte ptr [bp.rAX+1]
 05D9  0A FF				or	bh, bh
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-43


 05DB  5B				pop	bx
 05DC  0F 85 063F R			jnz	AMC_map_Error
					;
					; save needed registers, return address and call address
					; on client's stack
					;
 05E0  4F				dec	di
 05E1  4F				dec	di				; "pre-decrement" stack
 05E2  FD				std					; store backward
 05E3  AB				stosw					; subfunction code
 05E4  8B C2				mov	ax, dx				; EMM handle
 05E6  AB				stosw
 05E7  8C D8				mov	ax, ds				; DGROUP
 05E9  AB				stosw
 05EA  8B C3				mov	ax, bx				; CS for return from called code
 05EC  AB				stosw
 05ED  B8 068B R			mov	ax, offset AMC_return_address	; IP for return from called code
 05F0  26: 89 05			mov	es:[di], ax			; "push" without decrement "SP"
 05F3  FC				cld
					;
					; NOW build a iretd stack frame to go back to virtual mode
					;
 05F4  58				pop	ax				; no error : we can throw
 05F5  58				pop	ax				; away EMM-rEntry's CS:IP now
				
 05F6  58				pop	ax				; target address
 05F7  5A				pop	dx				; target address+2
 05F8  59				pop	cx				; Stack Segment
				
 05F9  6A 00				push	0
 05FB  FF 76 2A				push	word ptr [bp].rGS
 05FE  6A 00				push	0
 0600  FF 76 2C				push	word ptr [bp].rFS
 0603  6A 00				push	0
 0605  FF 76 26				push	word ptr [bp].rDS
 0608  6A 00				push	0
 060A  FF 76 28				push	word ptr [bp].rES
 060D  6A 00				push	0
 060F  51				push	cx				; client's SS
 0610  66| 57				push	edi				; client's ESP
 0612  6A 02				push	PFLAG_VM			; VM bit
 0614  8B 5E 24				mov	bx, word ptr [bp].PFlag
 0617  83 E3 DF				and	bx, not PFLAG_VIRTUAL		; clear fake bit
 061A  53				push	bx
 061B  6A 00				push	0
 061D  52				push	dx				; target address+2
 061E  6A 00				push	0
 0620  50				push	ax				; target address
					;
					; restore registers context from stack frame
					;
 0621  66| 8B 46 1C			mov	eax, dword ptr [bp].rAX
 0625  66| 8B 5E 10			mov	ebx, dword ptr [bp].rBX
 0629  66| 8B 4E 18			mov	ecx, dword ptr [bp].rCX
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-44


 062D  66| 8B 56 14			mov	edx, dword ptr [bp].rDX
 0631  66| 8B 76 04			mov	esi, dword ptr [bp].rSI
 0635  66| 8B 7E 00			mov	edi, dword ptr [bp].rDI
 0639  66| 8B 6E 2E			mov	ebp, dword ptr [bp].rFS+2	; clients's EBP
					;
					; return to virtual mode via iretd with calling address on stack
					;
 063D  66| CF				iretd
				
 063F				AMC_map_Error:
					;
					; mapping error occur : restore state and exit
					;
 063F  66| 0F B6 0E 0000 E		movzx	ecx, [_cntxt_bytes]
 0645  06				push	es
 0646  1F				pop	ds				; DS:SI <-- stack
 0647  87 F7				xchg	si, di
					release_space_to_stack	CX		; DS:SI <-- space on stack
 0649  03 F1                 1		add	si, CX 
					;
 064B  65: 66| 0F B6 4D 09		movzx	ecx, byte ptr gs:[di.mac_old_page_map_len]  ; CX = Length of old map
 0651  C1 E1 02				shl	cx, 2				; CX * 4 (4 bytes each entry)
 0654  41				inc	cx				; one more for length
					release_space_to_stack	CX		; DS:SI <-- space on stack
 0655  03 F1                 1		add	si, CX 
					;
 0657  8B FE				mov	di, si
 0659  B9 0004				mov	cx, 4
					get_space_from_stack	CX		; ES:DI <-- space on stack
 065C  2B F9                 1		sub	di, CX 
 065E  26: 8F 05			pop	es:[di]				; restore EMM_rEntry's CS:IP
 0661  26: 8F 45 02			pop	es:[di+2]
				
 0665  58				pop	ax				; discard target addr etc
 0666  58				pop	ax
 0667  58				pop	ax
				
 0668  C3				ret
				
 0669				AMC_Stack_Fram_Size:
 0669  C6 46 1D 00			mov	byte ptr [bp.rAX+1], OK		; No error
 066D  A1 0000 E			mov	ax, [_mappable_page_count]	; assume ALL mappable pages
 0670  C1 E0 02				shl	ax, 2				; 4 bytes per page
 0673  05 0011				add	ax, 1 + (3+5)*2		; map length
							       		; + 3 words already pushed by EMM_rEntry
							       		; + 5 registers pushed
 0676  02 06 0000 E			add	al, [_cntxt_bytes]		; FRS context
 067A  80 D4 00				adc	ah, 0
 067D  89 46 10				mov	word ptr [bp.rBX], ax
 0680  C3				ret
				
 0681				AMC_inv_phys_pages:
 0681  C6 46 1D 8B			mov	byte ptr [bp.rAX+1], PHYS_PAGE_RANGE
 0685  C3				ret
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-45


				
 0686				AMC_inv_sub:
 0686  C6 46 1D 8F			mov	byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
 068A  C3				ret
				
 068B				_AlterMapAndCall    ENDP
				
				
				;******************************************************************************
				;
				;	AMC_return_address -- Return from procedure called through a Map & Call
				;
				;	NOTE:	MapHandleArray will only access AH on the stack and so the
				;		TSTF stack frame will work properly for this procedure.
				;
				;	ENTRY:	VTFOE frame,EBP,EBX,ESI are on the stack
				;
				;******************************************************************************
				
 068B				AMC_return_address proc	far
				
				;
				; This will causes an illegal instruction trap and goes into protected
				; mode. The handler will return back to the point right after the
				; 2 bytes ARPL instruction with ring0 stack having and IRETD stack frame
				;
 068B  63 C0				arpl	ax, ax
					;
					; In Protected Mode Now
					;
 068D  66| 60				pushad				; saves all regs
 068F  8B C4				mov	ax, sp			; saves stack frame address
 0691  A3 0000 E			mov	[_regp], ax		; to _regp
				
 0694  66| 8B 76 14			mov	esi, dword ptr [bp.VTFOE.VMTF_ESP]	; clients's ESP
 0698  8B 46 18				mov	ax, word ptr [bp.VTFOE.VMTF_SS]		; client's SS
 069B  33 D2				xor	dx, dx					; AX:DX <-- Seg:Off of Client's Stack
				
					Set_EMM_GDT	EMM2_GSEL
 069D  BB 0108               1		mov	bx, EMM2_GSEL			; GDT selector 
 06A0  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 06A3  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 06A6  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 06A8  6A 08                 1		push	GDTD_GSEL 
 06AA  07                    1		pop	es				; ES:0 <-- GDT 
 06AB  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 06AE  8E E3				mov	fs, bx				; FS:SI <-- client's Stack
				
 06B0  FC				cld					; forward
					;
					; "pop" back registers on "stack" FS:SI
					;
 06B1  0F A0				push	fs
 06B3  1F				pop	ds
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-46


 06B4  AD				lodsw
 06B5  8E C0				mov	es, ax				; DGROUP
 06B7  AD				lodsw
 06B8  8B D0				mov	dx, ax				; EMM handle
 06BA  AD				lodsw					; subfunction code
					;
					; restore mapping context
					;
 06BB  50				push	ax
				
 06BC  06				push	es
 06BD  1F				pop	ds			; DGROUP
					get_FRS_Window	DI		; ES:DI <-- FRS mapping context regs
 06BE  8B 3E 0000 E          1		mov	DI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 06C2  83 C7 00              1		add	DI, FRS_window			; points to FRS window entries 
 06C5  0F A0				push	fs
 06C7  1F				pop	ds			; DS:SI <-- client's stack
 06C8  32 ED				xor	ch, ch
 06CA  26: 8A 0E 0000 E			mov	cl, ES:[_cntxt_bytes]
 06CF  D1 E9				shr	cx, 1			; move word
 06D1  FC				cld
 06D2  F3/ A5				rep movsw
					;
					; map old mapping
					;
 06D4  AC				lodsb
 06D5  B4 00				mov	ah, 0
 06D7  8B C8				mov	cx, ax			; length
 06D9  58				pop	ax			; subfunction code
 06DA  56				push	si
 06DB  51				push	cx
 06DC  55				push	bp
 06DD  8B 2E 0000 E			mov	bp, [_regp]		; setup pushad frame first
 06E1  06				push	es
 06E2  1F				pop	ds			; DS <-- DGROUP
 06E3  E8 03D6 R			call	MapHandleArray_Entry_2	; map it
 06E6  5D				pop	bp
 06E7  59				pop	cx
 06E8  5E				pop	si
 06E9  C1 E1 02				shl	cx, 2			; 4 bytes per mapping
					release_space_to_stack	CX
 06EC  03 F1                 1		add	si, CX 
					;
					; saves CS:IP (BX:CX) on iretd stack frame
					;
 06EE  0F A0				push	fs
 06F0  1F				pop	ds			; DS <-- Client's Stack
 06F1  50				push	ax
 06F2  AD				lodsw
 06F3  89 46 08				mov	word ptr [bp.VTFOE+VMTF_EIP], ax
 06F6  AD				lodsw
 06F7  89 46 0C				mov	word ptr [bp.VTFOE+VMTF_CS], ax
 06FA  AD				lodsw
 06FB  89 46 10				mov	word ptr [bp.VTFOE+VMTF_EFLAGS], ax
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-47


 06FE  C7 46 12 0002			mov	word ptr [bp.VTFOE+VMTF_EFLAGShi], PFLAG_VM
 0703  58				pop	ax
					;
					; save client's new stack pointer
					;
 0704  66| 89 76 14			mov	dword ptr [bp.VTFOE.VMTF_ESP], esi
 0708  66| 61				popad
 070A  66| 5E				pop	esi
 070C  66| 5B				pop	ebx
 070E  66| 5D				pop	ebp
 0710  66| 83 C4 04			add	esp, 4			; discard "error" code
					;
					; set return status
					;
 0714  B4 00				mov	ah, OK
				
 0716  66| CF				iretd
				
 0718				AMC_return_address endp
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-48


					page
				;******************************************************************************
				;
				;   _MoveExchangeMemory
				;
				;	This function (23) will copy or exchange memory between EMM and
				;	conventional memory or EMM to EMM.
				;	Subfunction 0 is memory copy.  Subfunction 1 is exchange.
				;	The current mapping context is preserved since the EMM pages are
				;	mapped into high memory using VM1s page table.
				;
				;   ENTRY: PROTECTED MODE ONLY
				;	AL = Subfunction -- 0 = Copy, 1 = Exchange
				;	DX = EMM handle
				;	REGS on STACK	DS:SI = Move/Exchange structure
				;	SS:[BP] -> regp stack frame
				;	DS = DGROUP
				;
				;   EXIT:   AL = Status
				;
				;   USES:   AX, BX, CX, DX, SI, DI
				;
				;==============================================================================
				;
				; ALGORITHM:
				;
				; BEGIN
				;   check/validate source/dest and overlay,etc
				;
				;   save mapping context of first  physical page frame as source page frame
				;   save mapping context of second physical page frame as dest   page frame
				;
				;   /*
				;    * setup source and dest memory pointers
				;    */
				;   if (source.type == conv.mem)
				;      DS:SI = source.initial.segment:source.initial.offset
				;   else
				;      if (backward.copy)
				;         calculate last source emm page and new offset
				;      map source.initial.page into source.page.frame
				;      DS:SI = segment.of.source.page.frame:source.initial.offset
				;
				;   if (dest.type == conv.mem)
				;      ES:DI = dest.initial.segment:dest.initial.offset
				;   else
				;      if (backward.copy)
				;         calculate last dest emm page and new offset
				;      map dest.initial.page into dest.page.frame
				;      ES:DI = segment.of.dest.page.frame:dest.initial.offset
				;
				;   /********
				;    *
				;    * DS:SI - addresses source data area
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-49


				;    * ES:DI - addresses dest buffer area
				;    *
				;    */
				;
				;   for (total.byte.to.process != 0) {
				;      /*
				;       * find out how many bytes to process (least bytes to process)
				;       */
				;      if (source.type == conv.mem)
				;         bytes.to.process = 0x4000 - dest.offset
				;      else
				;         if (dest.type == conv.mem)
				;            bytes.to.process = 0x4000 - source.offset
				;         else /* emm to emm */
				;            if (backward.copy)
				;               bytes.to.process = min(source.offset, dest.offset) + 1
				;            else
				;               bytes.to.process = 0x4000 - max(source.offset, dest.offset)
				;
				;      /*
				;       * adjust the total
				;       */
				;      if (bytes.to.process > totol.bytes.to.process)
				;         bytes.to.process = totol.bytes.to.process
				;
				;      total.bytes.to.process -= bytes.to.process
				;
				;      /*
				;       * do the processing
				;       */
				;      move/exchange bytes.to.process bytes
				;
				;      /*
				;       * adjust memory pointers and map in new pages if necessary
				;       * for the next iternation
				;       */
				;      if (total.bytes.to.process != 0)
				;         if (source.type == emm)
				;            if (SI == 0x4000)
				;               /*
				;                * forward.copy's index expire
				;                */
				;               map next emm source page into source.page.frame
				;               SI = 0
				;            if (SI == 0xffff)
				;               /*
				;                * backward.copy's index expire
				;                */
				;               map prev emm source page into source.page.frame
				;               SI = 0x3fff
				;         else
				;            normalize DS:SI
				;
				;         if (dest.type == emm)
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-50


				;            if (DI == 0x4000)
				;               /*
				;                * forward.copy's index expire
				;                */
				;               map next emm dest page into dest.page.frame
				;               DI = 0
				;            if (DI == 0xffff)
				;               /*
				;                * backward.copy's index expire
				;                */
				;               map prev emm dest page into dest.page.frame
				;               DI = 0x3fff
				;         else
				;            normalize ES:DI
				;   }
				;
				;   restore first  page frame's mapping context
				;   restore second page frame's mapping context
				; END
				;
				;==============================================================================
				
				
 0718				_MoveExchangeMemory proc near
 0718  C6 46 1D 00			mov	byte ptr [bp.rAX+1], OK     ; Assume everything work OK
 071C  FC				cld				    ; Assume forward direction
				
 071D  3C 01				cmp	al, 1			    ; Q: Valid subfunction?
 071F  0F 87 0C06 R			ja	mem_inv_sub		    ;	 N: Error
				
 0723  1E				push	ds
 0724  0F A1				pop	fs			    ; fs <-- addresses MEMM's data group
				
 0726  52				push	dx
 0727  51				push	cx
 0728  53				push	bx
 0729  50				push	ax
				
 072A  55				push	bp
 072B  8B 2E 0000 E			mov	bp,[_regp]
 072F  8B 46 26				mov	ax, word ptr [bp.rDS]	    ; DX:AX <-- move/xchg struct
 0732  8B 56 04				mov	dx, word ptr [bp.rSI]
					Set_EMM_GDT	USER1_GSEL	    ; use USER1_GSEL since both EMM1_GSEL
 0735  BB 0130               1		mov	bx, USER1_GSEL			; GDT selector 
 0738  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 073B  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 073E  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 0740  6A 08                 1		push	GDTD_GSEL 
 0742  07                    1		pop	es				; ES:0 <-- GDT 
 0743  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
									    ; and EMM2_GSEL will be used
 0746  8E DB				mov	ds, bx
 0748  33 F6				xor	si, si			    ; DS:SI <-- Move/Exchange structure
 074A  5D				pop	bp
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-51


 074B  58				pop	ax
 074C  5B				pop	bx
 074D  59				pop	cx
 074E  5A				pop	dx
				
 074F  66| 8B 0C			mov	ecx, [si.mem_region_length]; ECX = Length of memory region
 0752  66| 0B C9			or	ecx, ecx		    ; Q: Move 0 bytes?
 0755  0F 84 0C01 R			jz	mem_no_error		    ;	 Y: Silly! -- Just return
 0759  66| 81 F9 00100000		cmp	ecx, 0100000h		    ; Q: Move greater than 1 Meg?
 0760  0F 87 0C0B R			ja	mem_inv_region_len	    ;	 Y: Error
				
 0764  8A 5C 04				mov	bl, [si.mem_source.mem_memory_type]; Q: Is move Conventional
 0767  0A 5C 0B				or	bl, [si.mem_dest.mem_memory_type]  ;	 to Conven?
 076A  0F 84 0AD9 R			jz	mem_conv_to_conv		   ;	 Y: Go do it
				
 076E  8A 5C 04				mov	bl, [si.mem_source.mem_memory_type]; Q: Is move EMM
 0771  22 5C 0B				and	bl, [si.mem_dest.mem_memory_type]  ;	 to EMM
 0774  74 52				jz	SHORT mem_no_overlap		   ;	 N: No overlap
 0776  8B 5C 05				mov	bx, [si.mem_source.mem_handle]
 0779  3B 5C 0C				cmp	bx, [si.mem_dest.mem_handle]	; Q: Same handle?
 077C  75 4A				jnz	SHORT mem_no_overlap		;    N: No overlap
 077E  66| 0F B7 5C 09			movzx	ebx, [si.mem_source.mem_initial_seg_page]
 0783  66| 0F B7 54 07			movzx	edx, [si.mem_source.mem_initial_offset]
 0788  66| C1 E3 0E			shl	ebx, 14 		    ; * 4000h
 078C  66| 03 DA			add	ebx, edx		    ; EBX = Source offset within EMM
 078F  66| 53				push	ebx			    ; Save it temporarily
 0791  66| 0F B7 54 10			movzx	edx, [si.mem_dest.mem_initial_seg_page]
 0796  66| 0F B7 5C 0E			movzx	ebx, [si.mem_dest.mem_initial_offset]
 079B  66| C1 E2 0E			shl	edx, 14 		    ; * 4000h
 079F  66| 03 D3			add	edx, ebx		    ; EDX = Dest offset within EMM
 07A2  66| 5B				pop	ebx			    ; Source offset
 07A4  66| 2B D3			sub	edx, ebx		    ; EDX = Source - Destination
 07A7  7F 05				jg	SHORT mem_dest_gt_source    ; Don't negate if Dest > Source
 07A9  0C 80				or	al, Source_GT_Dest_Flag     ; Set flag to note Source > Dest
 07AB  66| F7 DA			neg	edx			    ; Absolute value of EDX
 07AE				mem_dest_gt_source:
 07AE  66| 3B D1			cmp	edx, ecx		    ; Q: Is there an overlap?
 07B1  73 15				jae	SHORT mem_no_overlap	    ;	 N: Continue
 07B3  A8 01				test	al, 1			    ; Q: Is this an exchange?
 07B5  0F 85 0C15 R			jnz	mem_inv_overlap 	    ;	 Y: Error -- Cant overlap xchg
 07B9  C6 46 1D 92			mov	byte ptr [bp.rAX+1], VALID_OVERLAP ; Assume everything OK but overlap
 07BD  0C 40				or	al, Overlap_Flag	    ;	 N: Note this for later
 07BF  A8 80				test	al, Source_GT_Dest_Flag	    ; Q: Is it gonna be backward copy
 07C1  0F 85 07C8 R			jnz	mem_no_overlap		    ;    N: Continue
 07C5  0C 20				or	al, Backward_Copy_Flag	    ;    Y: Note for later
 07C7  FD				std				    ; Set backword direction
				
 07C8				mem_no_overlap:
					;
					; check validility of source
					;
 07C8  8D 7C 04				lea	di, [si.mem_source]
 07CB  E8 0C37 R			call	validate_for_Move_or_Exchange
 07CE  0A E4				or	ah, ah
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-52


 07D0  0F 85 0BF7 R			jnz	mem_error_exit
					;
					; check validility of dest
					;
 07D4  8D 7C 0B				lea	di, [si.mem_dest]
 07D7  E8 0C37 R			call	validate_for_Move_or_Exchange
 07DA  0A E4				or	ah, ah
 07DC  0F 85 0BF7 R			jnz	mem_error_exit
				
 07E0  66| 0B D2			or	edx, edx		    ; delayed test for exact move/xchg
 07E3  0F 84 0BFC R			je	mem_valid_overlap	    ; WEIRD!!! -- Move to same place!
				;
				; initialize loop
				;
 07E7  1E				push	ds
 07E8  0F A9				pop	gs
 07EA  8B DE				mov	bx, si			    ; GS:BX <-- move/exchange structure
					;
					; save first 2 physical page frames' mapping and use those pages
					; as source and dest physical pages
					;
 07EC  0F A0				push	fs
 07EE  1F				pop	ds			; DS <-- DGROUP
					get_FRS_Window	SI
 07EF  8B 36 0000 E          1		mov	SI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 07F3  83 C6 00              1		add	SI, FRS_window			; points to FRS window entries 
 07F6  FF 34				push	word ptr [SI]	       ; save 1st pgae's mapping on stack
 07F8  FF 74 02				push	word ptr [SI+2]	       ; save 2st page's mapping on stack
				
					;
					; setup dest
					;
 07FB				mem_set_dest:
 07FB  65: 80 7F 0B 00			cmp	gs:[bx.mem_dest.mem_memory_type], 0	; Q: conv mem ?
 0800  0F 85 082C R			jnz	mem_map_dest				;  N: map in emm page
					;
					; conv memory : setup starting address of dest (always forward)
					;
 0804  65: 8B 4F 10			mov	cx, gs:[bx.mem_dest.mem_initial_seg_page]
 0808  65: 8B 57 0E			mov	dx, gs:[bx.mem_dest.mem_initial_offset] ; CX:DX <-- dest address
				
 080C  50				push	ax
 080D  53				push	bx
 080E  8B C1				mov	ax, cx					; AX:DX <-- first byte
					Set_EMM_GDT	EMM2_GSEL
 0810  BB 0108               1		mov	bx, EMM2_GSEL			; GDT selector 
 0813  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 0816  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 0819  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 081B  6A 08                 1		push	GDTD_GSEL 
 081D  07                    1		pop	es				; ES:0 <-- GDT 
 081E  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 0821  8E C3				mov	es, bx
 0823  33 FF				xor	di, di					; ES:DI <-- dest SelOff
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-53


 0825  5B				pop	bx
 0826  58				pop	ax
 0827  6A FF				push	0ffffh					; fake a logical page#
 0829  EB 67 90				jmp	mem_set_source
				
 082C				mem_map_dest:
					;
					; emm memory : find out starting address of dest
					;
 082C  65: 8B 57 10			mov	dx, gs:[bx.mem_dest.mem_initial_seg_page] ; initial logical page#
 0830  65: 8B 7F 0E			mov	di, gs:[bx.mem_dest.mem_initial_offset]   ; initial offset
				
 0834  A8 20				test	al, Backward_Copy_Flag			; Q: Backward copy ?
 0836  74 23				jz	SHORT mem_map_dest_forward		;  N: forward
				
					;
					; backward move : calculate last logical page# and offset
					;
 0838  65: 66| 8B 0F			mov	ecx, gs:[bx.mem_region_length]
 083C  65: 66| 0F B7 7F 0E		movzx	edi, gs:[bx.mem_dest.mem_initial_offset]
 0842  66| 4F				dec	edi
 0844  66| 03 CF			add	ecx, edi
 0847  66| 51				push	ecx
 0849  66| 81 E1 00003FFF		and	ecx, 00003fffh
 0850  66| 8B F9			mov	edi, ecx				; new offset
 0853  66| 59				pop	ecx
 0855  66| C1 E9 0E			shr	ecx, 14					; / 16K = # of pages
 0859  03 D1				add	dx, cx					; last emm page#
				
 085B				mem_map_dest_forward:
 085B  52				push	dx		; put current dest logical page# on stack
					;
					; prepare to map
					;
 085C  50				push	ax
 085D  53				push	bx
				
 085E  52				push	dx
 085F  65: 8B 57 0C			mov	dx, gs:[bx.mem_dest.mem_handle]
					Handle2HandlePtr
 0863  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 0866  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 086A  5B				pop	bx
 086B  B8 0001				mov	ax, 1					; 2nd page frame
 086E  E8 00D2 R			call	map_page
 0871  0F 82 0C1B R			jc	mem_mapping_error_3_pop			; pop out dest seg_page
				
					; contruct GDT entry for EMM2_GSEL for ES:0
					;
 0875  A1 0000 E			mov	ax, [PF_Base]
 0878  05 0400				add	ax, 0400h			; 2nd page frame segment
 087B  33 D2				xor	dx, dx				; offset 0
					Set_EMM_GDT	EMM2_GSEL
 087D  BB 0108               1		mov	bx, EMM2_GSEL			; GDT selector 
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-54


 0880  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 0883  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 0886  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 0888  6A 08                 1		push	GDTD_GSEL 
 088A  07                    1		pop	es				; ES:0 <-- GDT 
 088B  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 088E  8E C3				mov	es, bx				; ES:DI <-- dest address
				
 0890  5B				pop	bx
 0891  58				pop	ax
				
					;
					; setup source
					;
 0892				mem_set_source:
 0892  65: 80 7F 04 00			cmp	gs:[bx.mem_source.mem_memory_type], 0	; Q: conv mem ?
 0897  0F 85 08C4 R			jnz	mem_map_source				;  N: map in emm page
					;
					; conv memory : setup starting address of source (always forward)
					;
 089B  65: 8B 4F 09			mov	cx, gs:[bx.mem_source.mem_initial_seg_page]
 089F  65: 8B 57 07			mov	dx, gs:[bx.mem_source.mem_initial_offset] ; CX:DX <-- source address
				
 08A3  50				push	ax
 08A4  53				push	bx
 08A5  06				push	es
 08A6  8B C1				mov	ax, cx					; AX:DX <-- first byte
					Set_EMM_GDT	EMM1_GSEL
 08A8  BB 0100               1		mov	bx, EMM1_GSEL			; GDT selector 
 08AB  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 08AE  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 08B1  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 08B3  6A 08                 1		push	GDTD_GSEL 
 08B5  07                    1		pop	es				; ES:0 <-- GDT 
 08B6  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 08B9  8E DB				mov	ds, bx
 08BB  33 F6				xor	si, si
 08BD  07				pop	es
 08BE  5B				pop	bx
 08BF  58				pop	ax
 08C0  6A FF				push	0ffffh					; fake a logical page#
 08C2  EB 65				jmp	short mem_set_done
				
 08C4				mem_map_source:
					;
					; emm memory : find out starting address of dest
					;
 08C4  65: 8B 57 09			mov	dx, gs:[bx.mem_source.mem_initial_seg_page] ; initial logical page#
 08C8  65: 8B 77 07			mov	si, gs:[bx.mem_source.mem_initial_offset]   ; inital offset
				
 08CC  A8 20				test	al, Backward_Copy_Flag			; Q: Backward copy ?
 08CE  74 23				jz	SHORT mem_map_source_forward		;  N: forward
				
					;
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-55


					; backward move : calculate last logical page# and offset
					;
 08D0  65: 66| 8B 0F			mov	ecx, gs:[bx.mem_region_length]
 08D4  65: 66| 0F B7 77 07		movzx	esi, gs:[bx.mem_source.mem_initial_offset]
 08DA  66| 4E				dec	esi
 08DC  66| 03 CE			add	ecx, esi
 08DF  66| 51				push	ecx
 08E1  66| 81 E1 00003FFF		and	ecx, 00003fffh
 08E8  66| 8B F1			mov	esi, ecx				; new offset
 08EB  66| 59				pop	ecx
 08ED  66| C1 E9 0E			shr	ecx, 14					; / 16K = # of pages
 08F1  03 D1				add	dx, cx					; last emm page#
				
 08F3				mem_map_source_forward:
 08F3  52				push	dx		; put current source logical page# on stack
					;
					; prepare to map
					;
 08F4  50				push	ax
 08F5  53				push	bx
				
 08F6  52				push	dx
 08F7  65: 8B 57 05			mov	dx, gs:[bx.mem_source.mem_handle]
					Handle2HandlePtr
 08FB  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 08FE  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 0902  5B				pop	bx
 0903  B8 0000				mov	ax, 0					; 1st page frame
 0906  E8 00D2 R			call	map_page
 0909  0F 82 0C1A R			jc	mem_mapping_error_4_pop			; pop out dest and source seg_page
				
					; contruct GDT entry for EMM1_GSEL for DS:0
					;
 090D  A1 0000 E			mov	ax, [PF_Base]			; 1st page frame segment
 0910  33 D2				xor	dx, dx				; offset 0
 0912  06				push	es
					Set_EMM_GDT	EMM1_GSEL
 0913  BB 0100               1		mov	bx, EMM1_GSEL			; GDT selector 
 0916  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 0919  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 091C  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 091E  6A 08                 1		push	GDTD_GSEL 
 0920  07                    1		pop	es				; ES:0 <-- GDT 
 0921  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 0924  07				pop	es				; ES:0 <-- GDT
 0925  8E DB				mov	ds, bx				; ES:DI <-- dest address
				
 0927  5B				pop	bx
 0928  58				pop	ax
				
					; DS:SI <-- source address
					; ES:DI <-- dest address
				
 0929				mem_set_done:
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-56


 0929  65: 66| 8B 17			mov	edx, gs:[bx.mem_region_length]	; total length to move/xchg
				
				;
				; main move/exchange loop
				;
 092D				mem_loop:
 092D  0F 20 D9				mov	ecx, cr3
 0930  0F 22 D9				mov	cr3, ecx			; flush TLB after each map loop
				
 0933  66| B9 00004000			mov	ecx, 4000h			; maximum length to move/xchg
										; in one mapping (<16K)
 0939  65: 80 7F 04 00			cmp	gs:[bx.mem_source.mem_memory_type], 0	; Q: conv mem ?
 093E  0F 85 0946 R			jnz	mem_source_is_emm			;  N: check dest
 0942  2B CF				sub	cx, di				; CX <-- length to move/xchg
 0944  EB 29				jmp	short mem_calculate_length
 0946				mem_source_is_emm:
 0946  65: 80 7F 0B 00			cmp	gs:[bx.mem_dest.mem_memory_type], 0	; Q: conv mem ?
 094B  0F 85 0953 R			jnz	mem_both_are_emm			;  N: find out which
											;     emm has less
											;     to move/exchange
 094F  2B CE				sub	cx, si				; CX <-- length to move/xchg
 0951  EB 1C				jmp	short mem_calculate_length
 0953				mem_both_are_emm:
 0953  A8 20				test	al, Backward_Copy_Flag		; Q:backward copy ?
 0955  74 0C				jz	SHORT mem_2_emm_forward		;  N:forward
 0957  8B CE				mov	cx, si
 0959  41				inc	cx
 095A  3B F7				cmp	si, di				; Q:si<di ? (min(si,di))
 095C  72 11				jb	short mem_calculate_length	;  Y: use si
 095E  8B CF				mov	cx, di				;  N: use di
 0960  41				inc	cx
 0961  EB 0C				jmp	short mem_calculate_length
				
 0963				mem_2_emm_forward:
 0963  3B F7				cmp	si, di				; Q:si>di ? (max(si,di))
 0965  0F 87 096D R			ja	mem_si_gt_di			;  Y: use si
 0969  2B CF				sub	cx, di				;  N: use di
 096B  EB 02				jmp	short mem_calculate_length
 096D				mem_si_gt_di:
 096D  2B CE				sub	cx, si				; si>di
				
 096F				mem_calculate_length:
 096F  66| 3B CA			cmp	ecx, edx		    ; Q: bytes in this batch > total
 0972  0F 86 0979 R			jbe	mem_do_move_xchg	    ;  N: go ahead to move/xchg
 0976  66| 8B CA			mov	ecx, edx		    ;  Y: use total instead
				
				;
				; move/xchg loop
				;
 0979				mem_do_move_xchg:
 0979  66| 2B D1			sub	edx, ecx			; Adjust total first
				
 097C  A8 01				test	al, 1				; Q: Is this an exchange?
 097E  75 22				jnz	SHORT mem_exchange		;  Y: Do it
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-57


 0980  A8 20				test	al, Backward_Copy_Flag		;  N: Q:Is this backward copy ?
 0982  74 05				jz	SHORT mem_move_forward		;      N: forward
				;
				; memory move backward
				;
 0984  F3/ A4				rep movsb
 0986  EB 57 90				jmp	mem_next_round
				;
				; memory move forward
				;
 0989				mem_move_forward:
 0989  66| 50				push	eax
 098B  66| 8B C1			mov	eax, ecx
 098E  66| C1 E9 02			shr	ecx, 2			    ; ECX = # DWORDS to copy
 0992  F3/ 66| A5			rep movsd			    ; Move the DWORDS
 0995  66| 8B C8			mov	ecx, eax
 0998  66| 83 E1 03			and	ecx, 00000003h		    ; ECX = # BYTES left to copy
 099C  F3/ A4				rep movsb			    ; Move the BYTES
 099E  66| 58				pop	eax
 09A0  EB 3D				jmp	short mem_next_round
				;
				; momory exchange
				;
 09A2				mem_exchange:
 09A2  52				push	dx
 09A3  50				push	ax
 09A4  53				push	bx
 09A5  66| 51				push	ecx			    ; Save total # bytes on stack
 09A7  66| C1 E9 02			shr	ecx, 2			    ; ECX = # DWORDS to exchange
 09AB  67| E3 17			jecxz	mem_xchg_bytes		    ; Exit if no DWORDS left
 09AE  BA 0004				mov	dx, 4			    ; Size of DWORD
 09B1				mem_xchg_dword_loop:
 09B1  66| 8B 04			mov	eax, [si]
 09B4  26: 66| 8B 1D			mov	ebx, es:[di]
 09B8  26: 66| 89 05			mov	es:[di], eax
 09BC  66| 89 1C			mov	[si], ebx
 09BF  03 F2				add	si, dx
 09C1  03 FA				add	di, dx
 09C3  E2 EC				loop	mem_xchg_dword_loop	    ; Loop until all DWORDS exchanged
 09C5				mem_xchg_bytes:
 09C5  66| 59				pop	ecx
 09C7  66| 83 E1 03			and	ecx, 00000003h		    ; ECX = # BYTES left to exchange
 09CB  67| E3 0E			jecxz	mem_xchg_done		    ; Exit if no DWORDS left
 09CE				mem_xchg_byte_loop:
 09CE  8A 04				mov	al, [si]
 09D0  26: 8A 1D			mov	bl, es:[di]
 09D3  26: 88 05			mov	es:[di], al
 09D6  88 1C				mov	[si], bl
 09D8  46				inc	si
 09D9  47				inc	di
 09DA  E2 F2				loop	mem_xchg_byte_loop	    ; Loop until all BYTES exchanged
 09DC				mem_xchg_done:
 09DC  5B				pop	bx
 09DD  58				pop	ax
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-58


 09DE  5A				pop	dx			    ; DONE!!!!
				
				;
				; prepare for next iteration
				;
 09DF				mem_next_round:
					;
					; get source and dest's current mapped logical page
					; from stack
					;
 09DF  59				pop	cx		; source logical page#
 09E0  66| C1 E1 10			shl	ecx, 16		; put in high word
 09E4  59				pop	cx		; dest logical page#
				
 09E5  66| 0B D2			or	edx, edx			; Q: all done ?
 09E8  0F 84 0C24 R			jz	mem_exit			;  Y: restore context first
				
					; fix dest addresses
					;
 09EC  65: 80 7F 0B 00			cmp	gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ?
 09F1  0F 85 0A20 R			jnz	mem_map_next_dest	      	    ;  N: map next page
					normalize	ES,DI
 09F5  52                    1		push	dx 
 09F6  50                    1		push	ax 
 09F7  53                    1		push	bx 
 09F8  06                    1		push	es 
 09F9  06                    1		push	ES		; save for later reload 
 09FA  8C C3                 1		mov	bx, ES		; get Selector into BX 
 09FC  6A 08                 1		push	GDTD_GSEL	; ES -> GDT 
 09FE  07                    1		pop	es 
 09FF  80 E3 F8              1		and	bl,SEL_LOW_MASK	; mask off mode bits 
 0A02  26: 8B 57 02          1		mov	dx,es:[bx+2]	; AL:DX <-- base address 
 0A06  26: 8A 47 04          1		mov	al,es:[bx+4] 
 0A0A  03 D7                 1		add	dx,DI		; adjust base address 
 0A0C  14 00                 1		adc	al,0 
 0A0E  26: 89 57 02          1		mov	es:[bx+2],dx	; store it back 
 0A12  26: 88 47 04          1		mov	es:[bx+4],al 
 0A16  33 FF                 1		xor	DI, DI	; new Offset 
 0A18  07                    1		pop	ES		; reload Selector (flush cache) 
 0A19  07                    1		pop	es 
 0A1A  5B                    1		pop	bx 
 0A1B  58                    1		pop	ax 
 0A1C  5A                    1		pop	dx 
 0A1D  EB 3B 90				jmp	mem_check_source
				
 0A20				mem_map_next_dest:
 0A20  81 FF 4000			cmp	di, 4000h			; Q: di expires (forward)?
 0A24  74 0B				je	short mem_map_next_dest_forward	;  Y: 
 0A26  83 FF FF				cmp	di, 0ffffh			; Q: di expires (backward) ?
 0A29  75 2F				jne	short mem_check_source		;  N: go check source
				
 0A2B  BF 3FFF				mov	di, 3fffh			; set di for next round
 0A2E  49				dec	cx				; next logical page
 0A2F  EB 03				jmp	SHORT mem_map_next_dest_do_map
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-59


				
 0A31				mem_map_next_dest_forward:
 0A31  33 FF				xor	di, di				; clear di for next round
 0A33  41				inc	cx				; next logical page
				
					;
					; map in the next dest page
					;
 0A34				mem_map_next_dest_do_map:
 0A34  52				push	dx
 0A35  50				push	ax
 0A36  53				push	bx
 0A37  66| 51				push	ecx
 0A39  1E				push	ds
 0A3A  0F A0				push	fs
 0A3C  1F				pop	ds
 0A3D  65: 8B 57 0C			mov	dx, gs:[bx.mem_dest.mem_handle]
					Handle2HandlePtr
 0A41  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 0A44  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 0A48  B8 0001				mov	ax, 1				; 2nd page frame
 0A4B  8B D9				mov	bx, cx
 0A4D  E8 00D2 R			call	map_page
 0A50  1F				pop	ds
 0A51  66| 59				pop	ecx
 0A53  5B				pop	bx
 0A54  58				pop	ax
 0A55  5A				pop	dx
 0A56  0F 82 0C1E R			jc	mem_mapping_error
				
					;
					; fix source addresses
					;
 0A5A				mem_check_source:
 0A5A  66| C1 C9 10			ror	ecx, 16				      ; get source log page in low word
 0A5E  65: 80 7F 04 00			cmp	gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ?
 0A63  0F 85 0A92 R			jnz	mem_map_next_source		      ;  N: map next page
					normalize	DS,SI
 0A67  52                    1		push	dx 
 0A68  50                    1		push	ax 
 0A69  53                    1		push	bx 
 0A6A  06                    1		push	es 
 0A6B  1E                    1		push	DS		; save for later reload 
 0A6C  8C DB                 1		mov	bx, DS		; get Selector into BX 
 0A6E  6A 08                 1		push	GDTD_GSEL	; ES -> GDT 
 0A70  07                    1		pop	es 
 0A71  80 E3 F8              1		and	bl,SEL_LOW_MASK	; mask off mode bits 
 0A74  26: 8B 57 02          1		mov	dx,es:[bx+2]	; AL:DX <-- base address 
 0A78  26: 8A 47 04          1		mov	al,es:[bx+4] 
 0A7C  03 D6                 1		add	dx,SI		; adjust base address 
 0A7E  14 00                 1		adc	al,0 
 0A80  26: 89 57 02          1		mov	es:[bx+2],dx	; store it back 
 0A84  26: 88 47 04          1		mov	es:[bx+4],al 
 0A88  33 F6                 1		xor	SI, SI	; new Offset 
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-60


 0A8A  1F                    1		pop	DS		; reload Selector (flush cache) 
 0A8B  07                    1		pop	es 
 0A8C  5B                    1		pop	bx 
 0A8D  58                    1		pop	ax 
 0A8E  5A                    1		pop	dx 
 0A8F  EB 3B 90				jmp	mem_check_done
				
 0A92				mem_map_next_source:
 0A92  81 FE 4000			cmp	si, 4000h			; Q: si expires (forward)?
 0A96  74 0B				je	short mem_map_next_source_forward ;  Y:
 0A98  83 FE FF				cmp	si, 0ffffh			; Q: si expires (backward) ?
 0A9B  75 2F				jne	short mem_check_done		;  N: all done
				
 0A9D  BE 3FFF				mov	si, 3fffh			; set si for next round
 0AA0  49				dec	cx				; next logical page
 0AA1  EB 03				jmp	SHORT mem_map_next_source_do_map
				
 0AA3				mem_map_next_source_forward:
 0AA3  33 F6				xor	si, si				; clear si for next round
 0AA5  41				inc	cx				; next logical page
				
					;
					; map in the next source page
					;
 0AA6				mem_map_next_source_do_map:
 0AA6  52				push	dx
 0AA7  50				push	ax
 0AA8  53				push	bx
 0AA9  66| 51				push	ecx
 0AAB  1E				push	ds
 0AAC  0F A0				push	fs
 0AAE  1F				pop	ds
 0AAF  65: 8B 57 05			mov	dx, gs:[bx.mem_source.mem_handle]
					Handle2HandlePtr
 0AB3  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 0AB6  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 0ABA  B8 0000				mov	ax, 0				; 1st page frame
 0ABD  8B D9				mov	bx, cx
 0ABF  E8 00D2 R			call	map_page
 0AC2  1F				pop	ds
 0AC3  66| 59				pop	ecx
 0AC5  5B				pop	bx
 0AC6  58				pop	ax
 0AC7  5A				pop	dx
 0AC8  0F 82 0C1E R			jc	mem_mapping_error
					;
					; push back the logical pages on stack for
					; next iternation : dest first, then source
					;
 0ACC				mem_check_done:
 0ACC  66| C1 C9 10			ror	ecx, 16		
 0AD0  51				push	cx
 0AD1  66| C1 C9 10			ror	ecx, 16
 0AD5  51				push	cx
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-61


 0AD6  E9 092D R			jmp	mem_loop
				
				;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
				;
				; conv to conv
				;
				;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 0AD9				mem_conv_to_conv:
					;
					; check validility of source
					;
 0AD9  8D 7C 04				lea	di, [si.mem_source]
 0ADC  E8 0C37 R			call	validate_for_Move_or_Exchange
 0ADF  0A E4				or	ah, ah
 0AE1  0F 85 0BF7 R			jnz	mem_error_exit
					;
					; check validility of dest
					;
 0AE5  8D 7C 0B				lea	di, [si.mem_dest]
 0AE8  E8 0C37 R			call	validate_for_Move_or_Exchange
 0AEB  0A E4				or	ah, ah
 0AED  0F 85 0BF7 R			jnz	mem_error_exit
				
 0AF1  50				push	ax				; save subfunction
 0AF2  66| FF 34			push	[si.mem_region_length]		; save length
				
 0AF5  66| 0F B7 44 10			movzx	eax, [si.mem_dest.mem_initial_seg_page]
 0AFA  66| 0F B7 54 0E			movzx	edx, [si.mem_dest.mem_initial_offset]
 0AFF  66| 8B F8			mov	edi, eax
 0B02  66| C1 E7 04			shl	edi, 4
 0B06  66| 03 FA			add	edi, edx			; EDI <-- dest linear addr
					Set_EMM_GDT	EMM2_GSEL
 0B09  BB 0108               1		mov	bx, EMM2_GSEL			; GDT selector 
 0B0C  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 0B0F  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 0B12  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 0B14  6A 08                 1		push	GDTD_GSEL 
 0B16  07                    1		pop	es				; ES:0 <-- GDT 
 0B17  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
					Set_Page_Gran	EMM2_GSEL
 0B1A  BB 0108               1		mov	bx, EMM2_GSEL			; GDT selector 
 0B1D  6A 08                 1		push	GDTD_GSEL 
 0B1F  07                    1		pop	es				; ES:0 <-- GDT 
 0B20  26: 80 4F 06 80       1		or	byte ptr es:[bx+6], R_GRAN	; set gran bit 
 0B25  53				push	bx				; save dest GDT selector
				
 0B26  66| 0F B7 44 09			movzx	eax, [si.mem_source.mem_initial_seg_page]
 0B2B  66| 0F B7 54 07			movzx	edx, [si.mem_source.mem_initial_offset]
 0B30  66| 8B F0			mov	esi, eax
 0B33  66| C1 E6 04			shl	esi, 4
 0B37  66| 03 F2			add	esi, edx			; ESI <-- source linear addr
					Set_EMM_GDT	EMM1_GSEL
 0B3A  BB 0100               1		mov	bx, EMM1_GSEL			; GDT selector 
 0B3D  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-62


 0B40  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 0B43  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 0B45  6A 08                 1		push	GDTD_GSEL 
 0B47  07                    1		pop	es				; ES:0 <-- GDT 
 0B48  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
					Set_Page_Gran	EMM1_GSEL
 0B4B  BB 0100               1		mov	bx, EMM1_GSEL			; GDT selector 
 0B4E  6A 08                 1		push	GDTD_GSEL 
 0B50  07                    1		pop	es				; ES:0 <-- GDT 
 0B51  26: 80 4F 06 80       1		or	byte ptr es:[bx+6], R_GRAN	; set gran bit 
 0B56  8E DB				mov	ds, bx
				
 0B58  07				pop	es				; recover dest GDT sel
 0B59  66| 59				pop	ecx				; recover length
 0B5B  58				pop	ax				; recover subfunction
					;
					; test for overlapping transfer
					;
 0B5C  C6 46 1D 92			mov	byte ptr [bp.rAX+1], VALID_OVERLAP ; assume valid overlap
 0B60  66| 2B FE			sub	edi, esi		    ; EDI = Source - Destination
 0B63  7F 05				jg	SHORT mem_dest_gt_source_2  ; Don't negate if Dest > Source
 0B65  0C 80				or	al, Source_GT_Dest_Flag     ; Set flag to note Source > Dest
 0B67  66| F7 DF			neg	edi			    ; Absolute value of EDI
 0B6A				mem_dest_gt_source_2:
 0B6A  66| 8B DF			mov	ebx, edi		    ; Use EBX instead
 0B6D  66| 3B D9			cmp	ebx, ecx		    ; Q: Is there an overlap?
 0B70  73 20				jae	SHORT mem_no_overlap_2	    ;	 N: Continue
 0B72  A8 01				test	al, 1			    ; Q: Is this an exchange?
 0B74  0F 85 0C15 R			jnz	mem_inv_overlap 	    ;	 Y: Error -- Cant overlap xchg
 0B78  0C 40				or	al, Overlap_Flag	    ;	 N: Note this for later
 0B7A  A8 80				test	al, Source_GT_Dest_Flag	    ; Q: Is it gonna be backward copy
 0B7C  0F 85 0B92 R			jnz	mem_no_overlap_2	    ;    N: Continue
 0B80  0C 20				or	al, Backward_Copy_Flag	    ;    Y: Note for later
				
 0B82  66| BA FFFFFFFF			mov	edx, (not 1)+1		    ; increment value of -1 (2's compliment of 4)
 0B88  66| 8B F1			mov	esi, ecx		    ; Fix ESI and EDI for reverse copy
 0B8B  66| 4E				dec	esi
 0B8D  66| 8B FE			mov	edi, esi
 0B90  EB 17				jmp	short mem_conv_copy
				
 0B92				mem_no_overlap_2:
 0B92  67| C6 45 1D 00			mov	byte ptr [ebp.rAX+1], OK	; Everything worked OK
 0B97  66| BA 00000001			mov	edx, 1				; increment value of 1
 0B9D  66| 33 F6			xor	esi, esi			; DS:ESI <-- source addr
 0BA0  66| 33 FF			xor	edi, edi			; ES:EDI <-- dest addr
				
 0BA3  A8 01				test	al, 1				; Q:copy ?
 0BA5  0F 85 0BC7 R			jnz	mem_conv_xchg			;   N:go do exchange
				
 0BA9				mem_conv_copy:
 0BA9  66| 0B DB			or	ebx, ebx
 0BAC  0F 84 0BFC R			je	mem_valid_overlap	    ; WEIRD!!! -- Move to same place!
				
 0BB0  67| E3 2D			jecxz	mem_conv_done
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-63


 0BB3				mem_conv_copy_loop:
 0BB3  67| 8A 1E			mov	bl, [esi]
 0BB6  26: 67| 88 1F			mov	es:[edi], bl
 0BBA  66| 03 F2			add	esi, edx
 0BBD  66| 03 FA			add	edi, edx
 0BC0  66| 49				dec	ecx
 0BC2  75 EF				jnz	mem_conv_copy_loop
 0BC4  EB 1A 90				jmp	mem_conv_done		    ; DONE!!!!
				
 0BC7				mem_conv_xchg:
 0BC7  67| E3 16			jecxz	mem_conv_done
 0BCA				mem_conv_xchg_loop:
 0BCA  67| 8A 06			mov	al, [esi]
 0BCD  26: 67| 8A 1F			mov	bl, es:[edi]
 0BD1  26: 67| 88 07			mov	es:[edi], al
 0BD5  67| 88 1E			mov	[esi], bl
 0BD8  66| 46				inc	esi
 0BDA  66| 47				inc	edi
 0BDC  66| 49				dec	ecx
 0BDE  75 EA				jnz	mem_conv_xchg_loop	    ; Loop until all BYTES exchanged
 0BE0				mem_conv_done:
					Set_Byte_Gran	EMM1_GSEL		; make sure EMM1_GSEL and
 0BE0  BB 0100               1		mov	bx, EMM1_GSEL			; GDT selector 
 0BE3  6A 08                 1		push	GDTD_GSEL 
 0BE5  07                    1		pop	es				; ES:0 <-- GDT 
 0BE6  26: 80 67 06 7F       1		and	byte ptr es:[bx+6],NOT R_GRAN	; clear gran bit 
					Set_Byte_Gran	EMM2_GSEL		; EMM2_GSEL are Byte Granulated
 0BEB  BB 0108               1		mov	bx, EMM2_GSEL			; GDT selector 
 0BEE  6A 08                 1		push	GDTD_GSEL 
 0BF0  07                    1		pop	es				; ES:0 <-- GDT 
 0BF1  26: 80 67 06 7F       1		and	byte ptr es:[bx+6],NOT R_GRAN	; clear gran bit 
 0BF6  C3				ret
				
 0BF7				mem_error_exit:
 0BF7  FC				cld
 0BF8  88 66 1D				mov	byte ptr [bp.rAX+1], ah	; error code already set in ah
 0BFB  C3				ret
 0BFC				mem_valid_overlap:
 0BFC  C6 46 1D 92			mov	byte ptr [bp.rAX+1], VALID_OVERLAP
 0C00  C3				ret
 0C01				mem_no_error:
 0C01  C6 46 1D 00			mov	byte ptr [bp.rAX+1], OK
 0C05  C3				ret
				
 0C06				mem_inv_sub:
 0C06  C6 46 1D 8F			mov	byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
 0C0A  C3				ret
 0C0B				mem_inv_region_len:
 0C0B  C6 46 1D 96			mov	byte ptr [bp.rAX+1], INVALID_REGION_LENGTH
 0C0F  C3				ret
 0C10				mem_bad_memory_types:
 0C10  C6 46 1D 98			mov	byte ptr [bp.rAX+1], INVALID_MEMORY_TYPE
 0C14  C3				ret
 0C15				mem_inv_overlap:
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-64


 0C15  C6 46 1D 97			mov	byte ptr [bp.rAX+1], OVERLAPPING_EXCHANGE
 0C19  C3				ret
				;
				; discard old ax,bx,source seg_page#,dest seg_page#
				;
 0C1A				mem_mapping_error_4_pop:
 0C1A  5B				pop	bx
 0C1B				mem_mapping_error_3_pop:
 0C1B  5B				pop	bx
 0C1C  5B				pop	bx
 0C1D  5B				pop	bx
 0C1E				mem_mapping_error:
 0C1E  0F 20 D8				mov	eax, cr3  		    ; Always clear TLB, we may have
 0C21  0F 22 D8				mov	cr3, eax		    ; mapped pages before an error
				;
				; all done, need to restore context of physical page frames
				;
 0C24				mem_exit:
 0C24  0F A0				push	fs				; get DGROUP back into DS
 0C26  1F				pop	ds
					get_FRS_Window	BX
 0C27  8B 1E 0000 E          1		mov	BX, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0C2B  83 C3 00              1		add	BX, FRS_window			; points to FRS window entries 
 0C2E  8F 47 02				pop	word ptr [bx+2]
 0C31  8F 07				pop	word ptr [bx]
 0C33  FC				cld					; string forward again
 0C34  E9 026C R			jmp	_set_windows			; remap all pages
				
 0C37				_MoveExchangeMemory endp
				
				
				;******************************************************************************
				;
				;   validate_for_Move_Or_Exchange
				;
				;	This procedure is called by _MoveExchangeMemory to validate
				;	varies parameter on the memeory descriptor structure.
				;	It is called once for the source and once for the
				;	destination memory descriptor structures.
				;
				;   ENTRY:
				;	CX    = move length
				;	DS:DI = Move/Exchange memory descriptor data structure (source or dest)
				;	FS    = MEMM's data segment
				;   EXIT:
				;	AH = Status (0 = No error) -- AL is preserved
				;
				;   USES:
				;	DI, Flags
				;	AL and all other registers are preserved
				;
				;==============================================================================
				
 0C37				validate_for_Move_Or_Exchange    PROC NEAR
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-65


				
 0C37  66| 52				push	edx			    ; Used as temporary variable
 0C39  66| 50				push	eax
				
 0C3B  8A 15				mov	dl, [di.mem_memory_type]
 0C3D  0A D2				or	dl, dl			    ; Q: Conventional memory?
 0C3F  0F 84 0CA2 R			jz	ME_Map_Conventional	    ;	 Y: Nothing to map
 0C43  80 FA 01				cmp	dl, 1			    ; Q: Expanded memory?
 0C46  0F 85 0CEA R			jne	ME_Map_Inv_Mem		    ;	 N: Invalid memory type
									    ;	 Y: EMM memory -- Must map it
 0C4A  8B 55 01				mov	dx, [di.mem_handle]	    ; Get the handle
				
 0C4D  1E				push	ds				; validate_handle expect DS
 0C4E  0F A0				push	fs				; points to dgroup
 0C50  1F				pop	ds
					Validate_Handle	ME_Map_Inv_Handle	; check it
 0C51  3B 16 0000 E          1		cmp	dx, [_handle_table_size]	;Q: handle in range ? 
 0C55  0F 83 0CF1 R          1		jae	ME_Map_Inv_Handle			;  N: go to error label 
 0C59  C1 E2 02              1		shl	dx, 2				;  Y: convert handle to 
 0C5C  81 C2 0000 E          1		add	dx, offset _handle_table	;     pointer 
 0C60  87 DA                 1		xchg	bx, dx 
 0C62  83 3F FF              1		cmp	[bx.ht_index], NULL_PAGE	;Q: is this handle active ? 
 0C65  87 DA                 1		xchg	bx, dx 
 0C67  0F 84 0CF1 R          1		je	ME_Map_Inv_Handle			;  N: return error 
 0C6B  1F				pop	ds
				
 0C6C  87 DA				xchg	bx, dx
 0C6E  64: 8B 47 02			mov	ax, fs:[bx.ht_count]	    ; EAX = # pages in handle
 0C72  87 DA				xchg	bx, dx
 0C74  3B 45 05				cmp	ax,[di.mem_initial_seg_page];Q: Is initial page in range
 0C77  0F 86 0CF9 R			jbe	ME_Map_Invalid_log_page     ;	 N: Error
 0C7B  81 7D 03 4000			cmp	[di.mem_initial_offset], 04000h; Q: Is offset unreasonable?
 0C80  0F 83 0D00 R			jae	ME_Map_Invalid_Offset	       ;    Y: Error
				
 0C84  66| 0F B7 55 03			movzx	edx, [di.mem_initial_offset]
 0C89  66| 03 D1			add	edx, ecx
 0C8C  66| 81 C2 00003FFF		add	edx, 16 * 1024 - 1		; round up to nearest emm page boundary
 0C93  66| C1 EA 0E			shr	edx, 14				; / 16K = # of emm pages
 0C97  03 55 05				add	dx, [di.mem_initial_seg_page]	; last emm page of move/exchange
 0C9A  3B D0				cmp	dx, ax
 0C9C  0F 87 0D07 R			ja	ME_Map_Not_Enough_EMM		;Q: Is last page in range
 0CA0  EB 41				jmp	short ME_Map_OK			;  N: error
				
 0CA2				ME_Map_Conventional:
 0CA2  66| 0F B7 55 05			movzx	edx, word ptr [di.mem_initial_seg_page]
 0CA7  66| C1 E2 04			shl	edx, 4
 0CAB  66| 0F B7 7D 03			movzx	edi, word ptr [di.mem_initial_offset]
 0CB0  66| 03 D7			add	edx, edi		    ; EDX --> Conven mem to move/exch
 0CB3  66| 8B FA			mov	edi, edx		    ; Use EDI for test
 0CB6  66| 03 F9			add	edi, ecx		    ; EDI = Base + Move length
 0CB9  66| 81 FF 00100000		cmp	edi, 100000h		    ; Q: Is there wraparound?
 0CC0  73 53				jae	SHORT ME_Map_Inv_Wraparound ;	 Y: Error
 0CC2  64: 83 3E 0000 E 00		cmp	fs:[_page_frame_pages], 0   ; Is there a page frame?
 0CC8  74 19				je	short No_EMM_Overlap	    ;	 no, no problem
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-66


 0CCA  66| 81 FF 000E0000		cmp	edi, 0E0000h		    ; Q: Is move ABOVE EMM area?
 0CD1  73 10				jae	SHORT No_EMM_Overlap	    ;	 Y: That's not a problem
 0CD3  64: 66| 0F B7 06 0000		movzx	eax, fs:[PF_Base]	    ; Where page frame starts
	E			
 0CDA  66| C1 E0 04			shl	eax, 4
 0CDE  66| 3B F8			cmp	edi, eax		    ; Q: Does move run into EMM area?
 0CE1  77 2B				ja	SHORT ME_Map_Inv_Overlap    ;	 Y: Error
 0CE3				No_EMM_Overlap:
									    ;	 N: Everything is okie dokie
 0CE3				ME_Map_OK:
 0CE3  66| 58				pop	eax
 0CE5  66| 5A				pop	edx
 0CE7  B4 00				mov	ah, OK
 0CE9  C3				ret
				
 0CEA				ME_Map_Inv_Mem:
 0CEA  66| 58				pop	eax
 0CEC  66| 5A				pop	edx
 0CEE  B4 98				mov	ah, INVALID_MEMORY_TYPE
 0CF0  C3				ret
				
 0CF1				ME_Map_Inv_Handle:
 0CF1  1F				pop	ds
 0CF2  66| 58				pop	eax
 0CF4  66| 5A				pop	edx
 0CF6  B4 83				mov	ah, INVALID_HANDLE
 0CF8  C3				ret
				
 0CF9				ME_Map_Invalid_log_page:
 0CF9  66| 58				pop	eax
 0CFB  66| 5A				pop	edx
 0CFD  B4 8A				mov	ah, LOG_PAGE_RANGE
 0CFF  C3				ret
				
 0D00				ME_Map_Invalid_Offset:
 0D00  66| 58				pop	eax
 0D02  66| 5A				pop	edx
 0D04  B4 95				mov	ah, INVALID_OFFSET
 0D06  C3				ret
				
 0D07				ME_Map_Not_Enough_EMM:
 0D07  66| 58				pop	eax
 0D09  66| 5A				pop	edx
 0D0B  B4 93				mov	ah, INSUFFICIENT_EMM_PAGES
 0D0D  C3				ret
				
 0D0E				ME_Map_Inv_Overlap:
 0D0E  66| 58				pop	eax
 0D10  66| 5A				pop	edx
 0D12  B4 94				mov	ah, CONVENTIONAL_EMM_OVERLAP
 0D14  C3				ret
				
 0D15				ME_Map_Inv_Wraparound:
 0D15  66| 58				pop	eax
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-67


 0D17  66| 5A				pop	edx
 0D19  B4 A2				mov	ah, INVALID_WRAPAROUND
 0D1B  C3				ret
				
 0D1C				validate_for_Move_Or_Exchange    ENDP
				
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-68


					page
				;***********************************************
				;
				; _AlternateMapRegisterSet - handle alternative register sets
				;
				;	This routine switches the current register set or stores
				; the current page mapping context to an external save area and/or
				; restores the current page mapping context from an external save area.
				;
				; ENTRY: PROTECTED MODE ONLY
				;	 AH = 5Bh = Alternate Map Register Set function
				;	 AL = SUBFUNCTION CODE
				;		AL = 0  => Get Alternate Map Register Set
				;		AL = 1  => Set Alternate Map Register Set
				;		AL = 2  => Get and Set Alternate Map Register Set
				;		AL = 3  => Get Alternate Map Save Array size
				;		AL = 4  => Allocate Alternate Map Register Set
				;		AL = 5  => Deallocate Alternate Map Register Set
				;		AL = 6  => Enable DMA on Alternate Map Register Set
				;		AL = 7  => Disable DMA on Alternate Map Register Set
				; 	See sub-functions for individual ENTRY registers
				;	 SS:[EBP] -> regp stack frame
				;	 DS = DGROUP
				;
				; EXIT:	from individual sub-function or error with
				;	AH = INVALID_SUBFUNCTION
				;
				; USED:	EAX,ESI
				;
				;***********************************************
				Dword_Align	_TEXT
 0D1C				_AlternateMapRegisterSet	proc	near
 0D1C  66| 83 3E 0000 E 02		cmp	[_OSEnabled], OS_DISABLED
 0D22  73 15				jae	short AMRS_NotAllowed	; Disabled by OS
 0D24  3C 08				cmp	al, 08h			; Valid sub-function?
 0D26  77 16				ja	short AMRS_invalid
 0D28  FC				cld				; Done for all sub-functions
 0D29  C6 46 1D 00			mov	byte ptr [bp.rAX+1], OK ; Assume success!
 0D2D  66| 0F B6 F0			movzx	esi, al			; get offset to function dispatch
 0D31  D1 E6				shl	si, 1
 0D33  2E: FF A4 0D50 R			jmp	CS:AMRS_map[si]		; go to relevant sub-function
									; Return directly or to AMRS_exit...
 0D38				AMRS_exit:				; Exit with AH already set
 0D38  C3				ret
				
 0D39				AMRS_NotAllowed:
 0D39  C6 46 1D A4			mov	byte ptr [bp.rAX+1], ACCESS_DENIED
 0D3D  C3				ret
				
 0D3E				AMRS_invalid:
 0D3E  C6 46 1D 8F			mov	byte ptr [bp.rAX+1], INVALID_SUBFUNCTION
 0D42  C3				ret				; Error return!
				
 0D43				AMRS_bad_src:
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-69


 0D43  C6 46 1D A3			mov	byte ptr [bp.rAX+1], SOURCE_CORRUPTED
 0D47  C3				ret				; Error return!
				
 0D48				AMRS_noDMA:
 0D48  C6 46 1D 9E			mov	byte ptr [bp.rAX+1], FRSET_NO_DMA
 0D4C  C3				ret				; Error return!
				
				Dword_Align	_TEXT
 0D4D  90                    1		db	90h		     ; 
 0D4E  90                    2		db	90h		     ; 
 0D4F  90                    3		db	90h		     ; 
 0D50  0D64 R			AMRS_map	dw	_TEXT:AMRS_get
 0D52  0DB8 R					dw	_TEXT:AMRS_set
 0D54  0E45 R					dw	_TEXT:AMRS_size
 0D56  0E4F R					dw	_TEXT:AMRS_allocate
 0D58  0E98 R					dw	_TEXT:AMRS_deallocate
											; For now...
 0D5A  0D48 R					dw	_TEXT:AMRS_noDMA		; AMRS_DMAallocate
 0D5C  0D48 R					dw	_TEXT:AMRS_noDMA		; AMRS_DMAassign
 0D5E  0D48 R					dw	_TEXT:AMRS_noDMA		; AMRS_DMAdeassign
 0D60  0D48 R					dw	_TEXT:AMRS_noDMA		; AMRS_DMAfree
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-70


					page
				;***********************************************
				;
				; AMRS_get - get the current 'fast' register set
				;
				;	ENTRY: on stack
				;	 SS:[EBP] -> regp stack frame
				;	 DS = DGROUP
				;
				;	EXIT:	on stack
				;		BL = register set number,
				;		state stored in client's buffer if BL == 0
				;		ES:SI set to point to client's buffer
				;		return code set on stack
				;
				;	USED: EAX, EBX
				;
				;  DESCRIPTION: This function returns the current register set number.
				;		If it is zero, it returns the save area previously specified
				;
				;-----------------------------------------------
				Dword_Align	_TEXT
 0D62  90                    1		db	90h		     ; 
 0D63  90                    2		db	90h		     ; 
 0D64				AMRS_get:
 0D64  A0 0000 E			mov	al, [CurRegSetn]		; Get current set number
 0D67  88 46 10				mov	byte ptr [bp.rBX], al		; to be picked up later
 0D6A  0A C0				or	al, al
 0D6C  74 01				jz	short AMRS_get0
 0D6E  C3				ret					; non-zero - all done
 0D6F				AMRS_get0:					; Echo save area address
 0D6F  66| 0F B7 06 0000 E		movzx	eax, [EMM_savES]		; saved ES for reg set 0
 0D75  89 46 28				mov	word ptr [bp.rES], ax
 0D78  66| 0F B7 3E 0000 E		movzx	edi, [EMM_savDI]		; saved DI for reg set 0
 0D7E  89 7E 00				mov	word ptr [bp.rDI], di
 0D81  0B C0				or	ax, ax
 0D83  75 04				jnz	short AMRS_get2			; got dest addr
 0D85  0B FF				or	di, di
 0D87  74 2C				jz	short AMRS_get1			; not specified yet
 0D89				AMRS_get2:
 0D89  33 D2				xor	dx, dx
					Set_EMM_GDT	EMM1_GSEL
 0D8B  BB 0100               1		mov	bx, EMM1_GSEL			; GDT selector 
 0D8E  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 0D91  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 0D94  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 0D96  6A 08                 1		push	GDTD_GSEL 
 0D98  07                    1		pop	es				; ES:0 <-- GDT 
 0D99  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 0D9C  8E C3				mov	es, bx				; ES:DI <-- temp store
					Get_FRS_window	SI			; Get pointer to current window
 0D9E  8B 36 0000 E          1		mov	SI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0DA2  83 C6 00              1		add	SI, FRS_window			; points to FRS window entries 
 0DA5  66| 0F B6 06 0000 E		movzx	eax, [_cntxt_pages]		; how many pages
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-71


 0DAB  AB				stosw					; save size
 0DAC  66| 8B C8			mov	ecx, eax
 0DAF  66| D1 E9			shr	ecx, 1				; convert to dwords
 0DB2  F3/ 66| A5			rep movsd				; save the map
 0DB5				AMRS_get1:
 0DB5  C3				ret
					
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-72


					page
				;***********************************************
				;
				; AMRS_set - set the current 'fast' register set
				;
				;	ENTRY:  BL = register set number
				;		on stack
				;		if BL == 0
				;			ES:DI -> buffer containing mappings for register set 0
				;	 SS:[EBP] -> regp stack frame
				;	 DS = DGROUP
				;
				;	EXIT:	return code set on stack
				;
				;	USED:	EAX, EBX, ECX, EDX, ESI, EDI
				;
				;  DESCRIPTION: This function sets the current register set number.
				;		If it is zero, it uses the save area specified in ES:DI.
				;
				;-----------------------------------------------
				Dword_Align	_TEXT
 0DB6  90                    1		db	90h		     ; 
 0DB7  90                    2		db	90h		     ; 
 0DB8				AMRS_set:
 0DB8  80 FB 10				cmp	bl, FRS_COUNT			; Validate new Reg Set
 0DBB  0F 83 0EC7 R			jae	AMRS_inv_FRS
 0DBF  66| 0F B6 C3			movzx	eax, bl
 0DC3  66| 6B C0 52			imul	eax, size FRS_struc
 0DC7  93				xchg	ax, bx
 0DC8  8D 9F 0000 E			lea	bx, FRS_array[bx]		; Get pointer to the new Reg Set
 0DCC  83 7F 50 00			cmp	[bx.FRS_alloc], 0		; Make sure it is allocated
 0DD0  93				xchg	ax, bx
 0DD1  0F 84 0EC7 R			je	AMRS_undef_FRS			;   unallocated, go complain
				
 0DD5  80 FB 00				cmp	bl, 0				; New reg set 0?
 0DD8  74 08				je	short AMRS_set0			;   yes, always set context
 0DDA  3A 1E 0000 E			cmp	bl, [CurRegSetn]		; Setting the same reg set?
 0DDE  0F 84 0D38 R			je	AMRS_exit			;   yes, just return
 0DE2				AMRS_set0:					; Now set up new reg set
 0DE2  A3 0000 E			mov	word ptr [CurRegSet], ax	; Set Current reg. set Offset
 0DE5  88 1E 0000 E			mov	[CurRegSetn], bl
				
 0DE9  0A DB				or	bl, bl				; Real register set?
 0DEB  0F 85 026C R			jne	_set_windows			;   yes, go deal with it
										;   no, deal with reg set 0
 0DEF  8B 46 28				mov	ax, word ptr [bp.rES]		; Pick up user's pointer
 0DF2  A3 0000 E			mov	[EMM_savES], ax			; and save for AMRS_get
 0DF5  8B 56 00				mov	dx, word ptr [bp.rDI]
 0DF8  89 16 0000 E			mov	[EMM_savDI], dx			; AX:DX <-- regs cntxt restore area
 0DFC  50				push	ax
 0DFD  0B C2				or	ax, dx
 0DFF  58				pop	ax
 0E00  0F 84 026C R			jz	_set_windows			; AX:DX == 0:0 implies no save area
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-73


					; construct GDT entry using EMM1_GSEL to access user's FRS buffer
					;
 0E04  06				push	es
					Set_EMM_GDT	EMM1_GSEL
 0E05  BB 0100               1		mov	bx, EMM1_GSEL			; GDT selector 
 0E08  E8 0000 E             1		call	SegOffTo24Resident		; AL:DX <-- 24 bit base address 
 0E0B  B9 FFFF               1		mov	cx, 0ffffh			; Limit 
 0E0E  B4 92                 1		mov	ah, D_DATA0			; Acess right 
 0E10  6A 08                 1		push	GDTD_GSEL 
 0E12  07                    1		pop	es				; ES:0 <-- GDT 
 0E13  E8 0000 E             1		call	SetDescInfoResident		; set GDT entry 
 0E16  07				pop	es
				
 0E17  8E E3				mov	fs, bx				; FS:SI <-- FRS buffer
 0E19  33 F6				xor	si, si
 0E1B  64: AD				lods	word ptr fs:[si]		; get saved count
 0E1D  66| 0F B6 0E 0000 E		movzx	ecx, [_cntxt_pages]		; what it should be
 0E23  3B C1				cmp	ax, cx				; Sensible count?
 0E25  0F 85 026C R			jne	_set_windows			;   no, restore last context
					Get_FRS_window	DI
 0E29  8B 3E 0000 E          1		mov	DI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0E2D  83 C7 00              1		add	DI, FRS_window			; points to FRS window entries 
 0E30  66| D1 E9			shr	ecx, 1				; size in dwords
 0E33  1E				push	ds				; xchg ds,fs
 0E34  0F A0				push	fs
 0E36  1F				pop	ds
 0E37  0F A1				pop	fs				; use DS as default seg. reg.
 0E39  F3/ 66| A5			rep movsd
 0E3C  1E				push	ds
 0E3D  0F A0				push	fs
 0E3F  1F				pop	ds
 0E40  0F A1				pop	fs
 0E42  E9 026C R			jmp	_set_windows			; set up mappings
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-74


					page
				;***********************************************
				;
				; AMRS_size - get the size of the register set 0 save area
				;
				;	ENTRY:
				;	 SS:[EBP] -> regp stack frame
				;	 DS = DGROUP
				;
				;	EXIT:	return code set on stack
				;		DX = size of the save area
				;
				;	USED:	none
				;
				;  DESCRIPTION: This function returns the size of the save area used
				;		for register set 0.
				;
				;-----------------------------------------------
 0E45				AMRS_size:
 0E45  66| 0F B6 06 0000 E		movzx	eax, [_cntxt_bytes]		; Previously calculated value
 0E4B  89 46 14				mov	word ptr [bp.rDX], ax
 0E4E  C3				ret
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-75


					page
				;***********************************************
				;
				; AMRS_allocate - allocate a fast register set
				;
				;	ENTRY:
				;	 SS:[EBP] -> regp stack frame
				;	 DS = DGROUP
				;
				;	EXIT:	return code set on stack
				;		BL = register set number
				;
				;	USED:	EBX, ESI
				;
				;  DESCRIPTION: This function allocates a free register set.
				;
				;-----------------------------------------------
 0E4F				AMRS_allocate:
 0E4F  80 3E 0000 E 00			cmp	[FRS_free], 0			; See if any are free
 0E54  74 3D				je	short AMRS_noRS			;   no, none available
										; Search for first free set
 0E56  FE 0E 0000 E			dec	[FRS_free]			; We are going to take one
 0E5A  8D 3E 0000 E			lea	di, [FRS_array]			; Start of FRS structures
 0E5E  32 DB				xor	bl, bl				; FRS number
 0E60				AMRS_search:
 0E60  83 7D 50 00			cmp	[di.FRS_alloc], 0		; This one free?
 0E64  74 0F				je	short AMRS_foundRS		;   yes, bl has the number
 0E66  83 C7 52				add	di, size FRS_struc		; on to the next one
 0E69  FE C3				inc	bl
 0E6B  80 FB 10				cmp	bl, FRS_COUNT			; Safety... should never fail
 0E6E  72 F0				jb	short AMRS_search
				
 0E70  C6 46 1D 80			mov	byte ptr [bp.rAX+1], EMM_SW_MALFUNCTION	; Honesty...
 0E74  C3				ret
				
 0E75				AMRS_foundRS:
 0E75  C7 45 50 0001			mov	[di.FRS_alloc], 1		; Allocate it
					Get_FRS_Window	SI
 0E7A  8B 36 0000 E          1		mov	SI, word ptr [CurRegSet]	; just offset (assume dgroup) 
 0E7E  83 C6 00              1		add	SI, FRS_window			; points to FRS window entries 
 0E81  8D 3D				lea	di, [di.FRS_Window]
 0E83  66| 0F B6 0E 0000 E		movzx	ecx, [_cntxt_pages]
 0E89  66| D1 E9			shr	ecx, 1
 0E8C  F3/ 66| A5			rep movsd				; Initialise to current mapping
 0E8F  88 5E 10				mov	byte ptr [bp.rBX], bl		; Return the number
 0E92  C3				ret
				
 0E93				AMRS_noRS:					; None free; return error
 0E93  C6 46 1D 9B			mov	byte ptr [bp.rAX+1], NO_MORE_FRSETS
 0E97  C3				ret
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-76


					page
				;***********************************************
				;
				; AMRS_deallocate - deallocate a fast register set
				;
				;	ENTRY:	BL = register set to deallocate
				;	 SS:[EBP] -> regp stack frame
				;	 DS = DGROUP
				;
				;	EXIT:	return code set on stack
				;
				;	USED:	EAX
				;
				;  DESCRIPTION: This function deallocates a register set.
				;
				;-----------------------------------------------
 0E98				AMRS_deallocate:
 0E98  0A DB				or	bl, bl
 0E9A  0F 84 0D38 R			jz	AMRS_exit			; Deallocating 0 is ignored
 0E9E  3A 1E 0000 E			cmp	bl, [CurRegSetn]		; Can't deallocate current set
 0EA2  74 23				je	short AMRS_undef_FRS
 0EA4  80 FB 10				cmp	bl, FRS_COUNT
 0EA7  73 1E				jae	short AMRS_undef_FRS		; Invalid Register set
 0EA9  66| 0F B6 C3			movzx	eax, bl
 0EAD  66| 6B C0 52			imul	eax, size FRS_struc		; Offset into array
 0EB1  93				xchg	ax, bx
 0EB2  83 BF 0050 E 00			cmp	FRS_array[bx.FRS_alloc], 0	; Paranoid...
 0EB7  93				xchg	ax, bx
 0EB8  74 0D				je	short AMRS_undef_FRS		;   Not allocated, complain
 0EBA  93				xchg	ax, bx
 0EBB  C7 87 0050 E 0000		mov	FRS_array[bx.FRS_alloc], 0	; Mark it free
 0EC1  93				xchg	ax, bx
 0EC2  FE 06 0000 E			inc	[FRS_free]			; one more set free
 0EC6  C3				ret
				
 0EC7				AMRS_Inv_FRS:
 0EC7				AMRS_undef_FRS:
 0EC7  C6 46 1D 9D			mov	byte ptr [bp.rAX+1], FRSET_UNDEFINED
 0ECB  C3				ret
				
 0ECC				_AlternateMapRegisterSet	endp
				
				
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-77


					page
				;******************************************************************************
				;   _Get_Key_Val - use the timer to get a random number for OSDisable Key
				;
				;   ENTRY   DS, ES = DGROUP selectors
				;
				;   STACK
				;
				;   EXIT    EAX has randomish number
				;
				;   USES    Flags, EAX, EDX
				;
				;------------------------------------------------------------------------------
 0ECC				_Get_Key_Val	proc	near
 0ECC  E8 0ED8 R			call	Get_Counter_Value		; (Who cares about the junk in
 0ECF  8B D0				mov	dx, ax				; the high words...?)
 0ED1  E8 0ED8 R			call	Get_Counter_Value		; Likely to be very close
 0ED4  66| F7 E2			mul	edx				; Mess it all up!
 0ED7  C3				ret
					
 0ED8				_Get_Key_Val	endp
				
				;******************************************************************************
				;
				;   NAME:
				;	Get_Counter_Value
				;
				;   DESCRIPTION:
				;	Returns the current system timer counter value
				;
				;   ENTRY:
				;	Assumes nothing
				;
				;   EXIT:
				;	AX = Current counter value (High word of EAX NOT CHANGED)
				;
				;   USES:
				;	Flags
				;
				;------------------------------------------------------------------------------
				
 0ED8				Get_Counter_Value	PROC NEAR
				
 = 0040				System_Clock_Port   EQU 40h
 = 0043				Sys_Clock_Ctrl_Port EQU 43h
				
 = 0000				Latch_Counter	    EQU 0
				
 0ED8  B0 00				mov	al, Latch_Counter
 0EDA  E6 43				out	Sys_Clock_Ctrl_Port, al 	; Latch the timer counter
 0EDC  EB 00				jmp	$+2
 0EDE  E4 40				in	al, System_Clock_Port		; Read the LSB
 0EE0  8A E0				mov	ah, al
 0EE2  EB 00				jmp	$+2
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Page     1-78


 0EE4  E4 40				in	al, System_Clock_Port		; Read the MSB
 0EE6  86 E0				xchg	ah, al				; AX = Counter value
 0EE8  C3				ret
				
 0EE9				Get_Counter_Value	ENDP
				
				
 0EE9				_TEXT	ENDS
				END

Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-1


Macros:

		N a m e			Lines

DWORD_ALIGN  . . . . . . . . . .  	   4
GDT_ENTRY  . . . . . . . . . . .  	   5
GET_FRS_WINDOW . . . . . . . . .  	   2
GET_SPACE_FROM_STACK . . . . . .  	   1
HANDLE2HANDLEPTR . . . . . . . .  	   2
IDT_ENTRY  . . . . . . . . . . .  	   5
LDT_ENTRY  . . . . . . . . . . .  	   5
NORMALIZE  . . . . . . . . . . .  	  21
PAGE_ENTRY . . . . . . . . . . .  	   2
RELEASE_SPACE_TO_STACK . . . . .  	   1
SET_BYTE_GRAN  . . . . . . . . .  	   4
SET_EMM_GDT  . . . . . . . . . .  	   7
SET_PAGE_GRAN  . . . . . . . . .  	   4
VALIDATE_HANDLE  . . . . . . . .  	   8

Structures and Records:

                N a m e                 Width   # fields
                                        Shift   Width   Mask    Initial

DESC . . . . . . . . . . . . . .  	0008	0006
  LIMIT  . . . . . . . . . . . .  	0000
  BASE_LOW . . . . . . . . . . .  	0002
  BASE_HIGH  . . . . . . . . . .  	0004
  RIGHTS . . . . . . . . . . . .  	0005
  RES386 . . . . . . . . . . . .  	0006
  BASE_XHI . . . . . . . . . . .  	0007
DWORDS . . . . . . . . . . . . .  	0004	0002
  LOWWORD  . . . . . . . . . . .  	0000
  HIGHWORD . . . . . . . . . . .  	0002
FRS_STRUC  . . . . . . . . . . .  	0052	0002
  FRS_WINDOW . . . . . . . . . .  	0000
  FRS_ALLOC  . . . . . . . . . .  	0050
GPFAULT_FRAME  . . . . . . . . .  	000C	0006
  GPF_ESI  . . . . . . . . . . .  	0000
  GPF_EBX  . . . . . . . . . . .  	0004
  GPF_EBP  . . . . . . . . . . .  	0008
GPPM_STRUC . . . . . . . . . . .  	0004	0002
  GPPM_COUNT . . . . . . . . . .  	0000
  GPPM_SEGS  . . . . . . . . . .  	0002
HANDLETABLE_STRUC  . . . . . . .  	0004	0002
  HT_INDEX . . . . . . . . . . .  	0000
  HT_COUNT . . . . . . . . . . .  	0002
LOG_PHYS_MAP_STRUCT  . . . . . .  	0004	0002
  LOG_PAGE_NUMBER  . . . . . . .  	0000
  PHYS_PAGE_NUMBER_SEG . . . . .  	0002
MAC_STRUCT . . . . . . . . . . .  	0016	0006
  MAC_TARGET_ADDRESS . . . . . .  	0000
  MAC_NEW_PAGE_MAP_LEN . . . . .  	0004
  MAC_NEW_MAP_ADDRESS  . . . . .  	0005
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-2


  MAC_OLD_PAGE_MAP_LEN . . . . .  	0009
  MAC_OLD_MAP_ADDRESS  . . . . .  	000A
  MAC_RESERVED . . . . . . . . .  	000E
MAJ_STRUCT . . . . . . . . . . .  	0009	0003
  MAJ_TARGET_ADDRESS . . . . . .  	0000
  MAJ_LOG_PHYS_MAP_LEN . . . . .  	0004
  MAJ_MAP_ADDRESS  . . . . . . .  	0005
MAPPABLE_PAGE  . . . . . . . . .  	0004	0002
  MAPPABLE_SEG . . . . . . . . .  	0000
  MAPPABLE_PG  . . . . . . . . .  	0002
MEM_MEMORY_DESCRIPTOR_STRUCT . .  	0007	0004
  MEM_MEMORY_TYPE  . . . . . . .  	0000
  MEM_HANDLE . . . . . . . . . .  	0001
  MEM_INITIAL_OFFSET . . . . . .  	0003
  MEM_INITIAL_SEG_PAGE . . . . .  	0005
MEM_STRUCT . . . . . . . . . . .  	0012	0003
  MEM_REGION_LENGTH  . . . . . .  	0000
  MEM_SOURCE . . . . . . . . . .  	0004
  MEM_DEST . . . . . . . . . . .  	000B
MHA_ARRAY0 . . . . . . . . . . .  	0004	0002
  MHA0_LOG_PG  . . . . . . . . .  	0000
  MHA0_PHYS_PG . . . . . . . . .  	0002
MHA_ARRAY1 . . . . . . . . . . .  	0004	0002
  MHA1_LOG_PG  . . . . . . . . .  	0000
  MHA1_SEG . . . . . . . . . . .  	0002
MOV_CDTR_FRAME . . . . . . . . .  	003C	001E
  MCF_WBP  . . . . . . . . . . .  	0000
  MCF_WES  . . . . . . . . . . .  	0002
  MCF_EAX  . . . . . . . . . . .  	0004
  MCF_ESI  . . . . . . . . . . .  	0008
  MCF_EBX  . . . . . . . . . . .  	000C
  MCF_EBP  . . . . . . . . . . .  	0010
  MCF_VMERR  . . . . . . . . . .  	0014
  MCF_VMEIP  . . . . . . . . . .  	0018
  MCF_VMCS . . . . . . . . . . .  	001C
  MCF_VMEFLAGS . . . . . . . . .  	0020
  MCF_VMEFLAGSHI . . . . . . . .  	0022
  MCF_VMESP  . . . . . . . . . .  	0024
  MCF_VMSS . . . . . . . . . . .  	0028
  MCF_VMES . . . . . . . . . . .  	002C
  MCF_VMDS . . . . . . . . . . .  	0030
  MCF_VMFS . . . . . . . . . . .  	0034
  MCF_VMGS . . . . . . . . . . .  	0038
PROT_INS_FRAME . . . . . . . . .  	003C	001E
  PIF_WBP  . . . . . . . . . . .  	0000
  PIF_WES  . . . . . . . . . . .  	0002
  PIF_AX . . . . . . . . . . . .  	0004
  PIF_DX . . . . . . . . . . . .  	0006
  PIF_ESI  . . . . . . . . . . .  	0008
  PIF_EBX  . . . . . . . . . . .  	000C
  PIF_EBP  . . . . . . . . . . .  	0010
  PIF_VMERR  . . . . . . . . . .  	0014
  PIF_VMEIP  . . . . . . . . . .  	0018
  PIF_VMCS . . . . . . . . . . .  	001C
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-3


  PIF_VMEFLAGS . . . . . . . . .  	0020
  PIF_VMEFLAGSHI . . . . . . . .  	0022
  PIF_VMESP  . . . . . . . . . .  	0024
  PIF_VMSS . . . . . . . . . . .  	0028
  PIF_VMES . . . . . . . . . . .  	002C
  PIF_VMDS . . . . . . . . . . .  	0030
  PIF_VMFS . . . . . . . . . . .  	0034
  PIF_VMGS . . . . . . . . . . .  	0038
R67_FRAME  . . . . . . . . . . .  	002E	000F
  RDI  . . . . . . . . . . . . .  	0000
  RSI  . . . . . . . . . . . . .  	0004
  RBP  . . . . . . . . . . . . .  	0008
  RSP  . . . . . . . . . . . . .  	000C
  RBX  . . . . . . . . . . . . .  	0010
  RDX  . . . . . . . . . . . . .  	0014
  RCX  . . . . . . . . . . . . .  	0018
  RAX  . . . . . . . . . . . . .  	001C
  RETADDR  . . . . . . . . . . .  	0020
  RCS  . . . . . . . . . . . . .  	0022
  PFLAG  . . . . . . . . . . . .  	0024
  RDS  . . . . . . . . . . . . .  	0026
  RES  . . . . . . . . . . . . .  	0028
  RGS  . . . . . . . . . . . . .  	002A
  RFS  . . . . . . . . . . . . .  	002C
SAVEMAP_STRUC  . . . . . . . . .  	000A	0002
  S_HANDLE . . . . . . . . . . .  	0000
  S_MAP  . . . . . . . . . . . .  	0002
TSS286STRUC  . . . . . . . . . .  	002C	0016
  TSS286_BACKLINK  . . . . . . .  	0000
  TSS286_SP0 . . . . . . . . . .  	0002
  TSS286_SS0 . . . . . . . . . .  	0004
  TSS286_SP1 . . . . . . . . . .  	0006
  TSS286_SS1 . . . . . . . . . .  	0008
  TSS286_SP2 . . . . . . . . . .  	000A
  TSS286_SS2 . . . . . . . . . .  	000C
  TSS286_IP  . . . . . . . . . .  	000E
  TSS286_FLAGS . . . . . . . . .  	0010
  TSS286_AX  . . . . . . . . . .  	0012
  TSS286_CX  . . . . . . . . . .  	0014
  TSS286_DX  . . . . . . . . . .  	0016
  TSS286_BX  . . . . . . . . . .  	0018
  TSS286_SP  . . . . . . . . . .  	001A
  TSS286_BP  . . . . . . . . . .  	001C
  TSS286_SI  . . . . . . . . . .  	001E
  TSS286_DI  . . . . . . . . . .  	0020
  TSS286_ES  . . . . . . . . . .  	0022
  TSS286_CS  . . . . . . . . . .  	0024
  TSS286_SS  . . . . . . . . . .  	0026
  TSS286_DS  . . . . . . . . . .  	0028
  TSS286_LDT . . . . . . . . . .  	002A
TSS386STRUC  . . . . . . . . . .  	0068	0027
  TSS386_BACKLINK  . . . . . . .  	0000
  TSS386_UNUSED1 . . . . . . . .  	0002
  TSS386_ESP0LO  . . . . . . . .  	0004
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-4


  TSS386_ESP0HI  . . . . . . . .  	0006
  TSS386_SS0 . . . . . . . . . .  	0008
  TSS386_UNUSED2 . . . . . . . .  	000A
  TSS386_ESP1  . . . . . . . . .  	000C
  TSS386_SS1 . . . . . . . . . .  	0010
  TSS386_UNUSED3 . . . . . . . .  	0012
  TSS386_ESP2  . . . . . . . . .  	0014
  TSS386_SS2 . . . . . . . . . .  	0018
  TSS386_UNUSED4 . . . . . . . .  	001A
  TSS386_CR3 . . . . . . . . . .  	001C
  TSS386_EIP . . . . . . . . . .  	0020
  TSS386_EFLAGS  . . . . . . . .  	0024
  TSS386_EAX . . . . . . . . . .  	0028
  TSS386_ECX . . . . . . . . . .  	002C
  TSS386_EDX . . . . . . . . . .  	0030
  TSS386_EBX . . . . . . . . . .  	0034
  TSS386_ESP . . . . . . . . . .  	0038
  TSS386_EBP . . . . . . . . . .  	003C
  TSS386_ESI . . . . . . . . . .  	0040
  TSS386_EDI . . . . . . . . . .  	0044
  TSS386_ES  . . . . . . . . . .  	0048
  TSS386_UNUSED5 . . . . . . . .  	004A
  TSS386_CS  . . . . . . . . . .  	004C
  TSS386_UNUSED6 . . . . . . . .  	004E
  TSS386_SS  . . . . . . . . . .  	0050
  TSS386_UNUSED7 . . . . . . . .  	0052
  TSS386_DS  . . . . . . . . . .  	0054
  TSS386_UNUSED8 . . . . . . . .  	0056
  TSS386_FS  . . . . . . . . . .  	0058
  TSS386_UNUSED9 . . . . . . . .  	005A
  TSS386_GS  . . . . . . . . . .  	005C
  TSS386_UNUSED10  . . . . . . .  	005E
  TSS386_LDT . . . . . . . . . .  	0060
  TSS386_UNUSED11  . . . . . . .  	0062
  TASKATTRIBUTES . . . . . . . .  	0064
  BITMAPBASE . . . . . . . . . .  	0066
VM_TRAP_FRAME  . . . . . . . . .  	0024	0012
  VMTF_EIP . . . . . . . . . . .  	0000
  VMTF_CS  . . . . . . . . . . .  	0004
  VMTF_EFLAGS  . . . . . . . . .  	0008
  VMTF_EFLAGSHI  . . . . . . . .  	000A
  VMTF_ESP . . . . . . . . . . .  	000C
  VMTF_SS  . . . . . . . . . . .  	0010
  VMTF_ES  . . . . . . . . . . .  	0014
  VMTF_DS  . . . . . . . . . . .  	0018
  VMTF_FS  . . . . . . . . . . .  	001C
  VMTF_GS  . . . . . . . . . . .  	0020
WORDS  . . . . . . . . . . . . .  	0002	0002
  LOWBYTE  . . . . . . . . . . .  	0000
  HIGHBYTE . . . . . . . . . . .  	0001
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-5


Segments and Groups:

                N a m e         	Size	Length	 Align	Combine Class

DGROUP . . . . . . . . . . . . .  	GROUP
  _DATA  . . . . . . . . . . . .  	16 Bit	0000	WORD	PUBLIC	'DATA'
  CONST  . . . . . . . . . . . .  	16 Bit	0000	WORD	PUBLIC	'CONST'
  _BSS . . . . . . . . . . . . .  	16 Bit	0000	WORD	PUBLIC	'BSS'
GDT  . . . . . . . . . . . . . .  	16 Bit	0000	PARA	COMMON	
IDT  . . . . . . . . . . . . . .  	16 Bit	0000	PARA	COMMON	
LAST . . . . . . . . . . . . . .  	16 Bit	0000	PARA	PUBLIC	'LAST'
LDT  . . . . . . . . . . . . . .  	16 Bit	0000	PARA	COMMON	
PAGESEG  . . . . . . . . . . . .  	16 Bit	0000	PARA	PUBLIC	'PAGES'
R_CODE . . . . . . . . . . . . .  	16 Bit	0000	PARA	PUBLIC	'R_CODE'
STACK  . . . . . . . . . . . . .  	16 Bit	0000	PARA	STACK	'STACK'
TSS  . . . . . . . . . . . . . .  	16 Bit	0000	PARA	COMMON	
VDATA  . . . . . . . . . . . . .  	16 Bit	0000	WORD	PUBLIC	'VDATA'
_TEXT  . . . . . . . . . . . . .  	16 Bit	0EE9	BYTE	PUBLIC	'CODE'

Symbols:            

                N a m e         	Type	 Value	 Attr

ABOVE_CONV_END_PG  . . . . . . .  	NUMBER	0037	
ABOVE_CONV_END_SEG . . . . . . .  	NUMBER	DC00	
ABOVE_CONV_STRT_PG . . . . . . .  	NUMBER	0030	
ABOVE_CONV_STRT_SEG  . . . . . .  	NUMBER	C000	
ACCESS_DENIED  . . . . . . . . .  	NUMBER	00A4	
AMC_INV_PHYS_PAGES . . . . . . .  	L NEAR	0681	_TEXT
AMC_INV_SUB  . . . . . . . . . .  	L NEAR	0686	_TEXT
AMC_MAP_ERROR  . . . . . . . . .  	L NEAR	063F	_TEXT
AMC_RETURN_ADDRESS . . . . . . .  	F PROC	068B	_TEXT	Length = 008D
AMC_STACK_FRAM_SIZE  . . . . . .  	L NEAR	0669	_TEXT
AMJ_ERROR  . . . . . . . . . . .  	L NEAR	04C7	_TEXT
AMRS_ALLOCATE  . . . . . . . . .  	L NEAR	0E4F	_TEXT
AMRS_BAD_SRC . . . . . . . . . .  	L NEAR	0D43	_TEXT
AMRS_DEALLOCATE  . . . . . . . .  	L NEAR	0E98	_TEXT
AMRS_EXIT  . . . . . . . . . . .  	L NEAR	0D38	_TEXT
AMRS_FOUNDRS . . . . . . . . . .  	L NEAR	0E75	_TEXT
AMRS_GET . . . . . . . . . . . .  	L NEAR	0D64	_TEXT
AMRS_GET0  . . . . . . . . . . .  	L NEAR	0D6F	_TEXT
AMRS_GET1  . . . . . . . . . . .  	L NEAR	0DB5	_TEXT
AMRS_GET2  . . . . . . . . . . .  	L NEAR	0D89	_TEXT
AMRS_INVALID . . . . . . . . . .  	L NEAR	0D3E	_TEXT
AMRS_INV_FRS . . . . . . . . . .  	L NEAR	0EC7	_TEXT
AMRS_MAP . . . . . . . . . . . .  	L 0002	0D50	_TEXT
AMRS_NODMA . . . . . . . . . . .  	L NEAR	0D48	_TEXT
AMRS_NORS  . . . . . . . . . . .  	L NEAR	0E93	_TEXT
AMRS_NOTALLOWED  . . . . . . . .  	L NEAR	0D39	_TEXT
AMRS_SEARCH  . . . . . . . . . .  	L NEAR	0E60	_TEXT
AMRS_SET . . . . . . . . . . . .  	L NEAR	0DB8	_TEXT
AMRS_SET0  . . . . . . . . . . .  	L NEAR	0DE2	_TEXT
AMRS_SIZE  . . . . . . . . . . .  	L NEAR	0E45	_TEXT
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-6


AMRS_UNDEF_FRS . . . . . . . . .  	L NEAR	0EC7	_TEXT

BACKWARD_COPY_FLAG . . . . . . .  	NUMBER	0020	

CLEAR_IOPL . . . . . . . . . . .  	NUMBER	CFFF	
COLOUR_GSEL  . . . . . . . . . .  	NUMBER	0068	
CONVENTIONAL_EMM_OVERLAP . . . .  	NUMBER	0094	
CONV_STRT_PG . . . . . . . . . .  	NUMBER	0010	
CONV_STRT_SEG  . . . . . . . . .  	NUMBER	4000	
CurRegSet  . . . . . . . . . . .  	V DWORD	0000	_DATA	External
CurRegSetn . . . . . . . . . . .  	V BYTE	0000	_DATA	External

DEB1_GSEL  . . . . . . . . . . .  	NUMBER	0088	
DEB2_GSEL  . . . . . . . . . . .  	NUMBER	0090	
DEB3_GSEL  . . . . . . . . . . .  	NUMBER	0098	
DEB4_GSEL  . . . . . . . . . . .  	NUMBER	00A0	
DEB5_GSEL  . . . . . . . . . . .  	NUMBER	00A8	
DEBX_GSEL  . . . . . . . . . . .  	NUMBER	00B0	
DUPLICATE_HANDLE_NAME  . . . . .  	NUMBER	00A1	
D_386CALL_GATE . . . . . . . . .  	NUMBER	000C	
D_386INT0  . . . . . . . . . . .  	NUMBER	008E	
D_386INT3  . . . . . . . . . . .  	NUMBER	00EE	
D_386INT_GATE  . . . . . . . . .  	NUMBER	000E	
D_386TRAP_GATE . . . . . . . . .  	NUMBER	000F	
D_386TSS . . . . . . . . . . . .  	NUMBER	0009	
D_386TSS0  . . . . . . . . . . .  	NUMBER	0089	
D_ACCESSED . . . . . . . . . . .  	NUMBER	0001	
D_BUSY386TSS . . . . . . . . . .  	NUMBER	000B	
D_B_BIT  . . . . . . . . . . . .  	NUMBER	0040	
D_CALLGATE . . . . . . . . . . .  	NUMBER	0004	
D_CODE . . . . . . . . . . . . .  	NUMBER	0008	
D_CODE0  . . . . . . . . . . . .  	NUMBER	009A	
D_CODE3  . . . . . . . . . . . .  	NUMBER	00FA	
D_CONFORM  . . . . . . . . . . .  	NUMBER	0004	
D_CTRL . . . . . . . . . . . . .  	NUMBER	0000	
D_DATA . . . . . . . . . . . . .  	NUMBER	0000	
D_DATA0  . . . . . . . . . . . .  	NUMBER	0092	
D_DATA3  . . . . . . . . . . . .  	NUMBER	00F2	
D_DPL0 . . . . . . . . . . . . .  	NUMBER	0000	
D_DPL1 . . . . . . . . . . . . .  	NUMBER	0020	
D_DPL2 . . . . . . . . . . . . .  	NUMBER	0040	
D_DPL3 . . . . . . . . . . . . .  	NUMBER	0060	
D_EXPDN  . . . . . . . . . . . .  	NUMBER	0004	
D_GATE3  . . . . . . . . . . . .  	NUMBER	00E4	
D_INT0 . . . . . . . . . . . . .  	NUMBER	0086	
D_INT3 . . . . . . . . . . . . .  	NUMBER	00E6	
D_INTGATE  . . . . . . . . . . .  	NUMBER	0006	
D_LDT  . . . . . . . . . . . . .  	NUMBER	0002	
D_LDT0 . . . . . . . . . . . . .  	NUMBER	0082	
D_NOTPRES  . . . . . . . . . . .  	NUMBER	0000	
D_PRES . . . . . . . . . . . . .  	NUMBER	0080	
D_R  . . . . . . . . . . . . . .  	NUMBER	0000	
D_RX . . . . . . . . . . . . . .  	NUMBER	0002	
D_SEG  . . . . . . . . . . . . .  	NUMBER	0010	
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-7


D_TASKGATE . . . . . . . . . . .  	NUMBER	0005	
D_TRAP0  . . . . . . . . . . . .  	NUMBER	0087	
D_TRAPGATE . . . . . . . . . . .  	NUMBER	0007	
D_TSS  . . . . . . . . . . . . .  	NUMBER	0001	
D_TSS0 . . . . . . . . . . . . .  	NUMBER	0081	
D_TSS_BUSY . . . . . . . . . . .  	NUMBER	0003	
D_W  . . . . . . . . . . . . . .  	NUMBER	0002	
D_X  . . . . . . . . . . . . . .  	NUMBER	0000	

EGA1_GSEL  . . . . . . . . . . .  	NUMBER	0070	
EGA2_GSEL  . . . . . . . . . . .  	NUMBER	0078	
EMM1_GSEL  . . . . . . . . . . .  	NUMBER	0100	
EMM2_GSEL  . . . . . . . . . . .  	NUMBER	0108	
EMM32_PHYS_PAGES . . . . . . . .  	NUMBER	0004	
EMM_HW_MALFUNCTION . . . . . . .  	NUMBER	0081	
EMM_MPindex  . . . . . . . . . .  	V BYTE	0000	_DATA	External
EMM_PAGE_CNT . . . . . . . . . .  	NUMBER	0800	
EMM_savDI  . . . . . . . . . . .  	V WORD	0000	_DATA	External
EMM_savES  . . . . . . . . . . .  	V WORD	0000	_DATA	External
EMM_SW_MALFUNCTION . . . . . . .  	NUMBER	0080	
ERR2LL . . . . . . . . . . . . .  	NUMBER	0003	
ERR3LL . . . . . . . . . . . . .  	NUMBER	0004	
ERRBOUNDS  . . . . . . . . . . .  	NUMBER	0005	
ERRCOPERR  . . . . . . . . . . .  	NUMBER	0010	
ERRCOPNA . . . . . . . . . . . .  	NUMBER	0007	
ERRCOPSEG  . . . . . . . . . . .  	NUMBER	0009	
ERRDIV . . . . . . . . . . . . .  	NUMBER	0000	
ERRDMA . . . . . . . . . . . . .  	NUMBER	0021	
ERRDOUBLE  . . . . . . . . . . .  	NUMBER	0008	
ERRGP  . . . . . . . . . . . . .  	NUMBER	000D	
ErrHndlr . . . . . . . . . . . .  	L NEAR	0000	_TEXT	External
ERRINT1  . . . . . . . . . . . .  	NUMBER	0001	
ERRINT3  . . . . . . . . . . . .  	NUMBER	0003	
ERRINTO  . . . . . . . . . . . .  	NUMBER	0004	
ERRINTPROT . . . . . . . . . . .  	NUMBER	0022	
ERRLGDT  . . . . . . . . . . . .  	NUMBER	0000	
ERRLIDT  . . . . . . . . . . . .  	NUMBER	0001	
ERRLMSW  . . . . . . . . . . . .  	NUMBER	0002	
ERRMOVCR . . . . . . . . . . . .  	NUMBER	0005	
ERRMOVDR . . . . . . . . . . . .  	NUMBER	0006	
ERRMOVTR . . . . . . . . . . . .  	NUMBER	0007	
ERRNMI . . . . . . . . . . . . .  	NUMBER	0002	
ERROPCODE  . . . . . . . . . . .  	NUMBER	0006	
ERRPAGE  . . . . . . . . . . . .  	NUMBER	000E	
ERRSEGNP . . . . . . . . . . . .  	NUMBER	000B	
ERRSTACK . . . . . . . . . . . .  	NUMBER	000C	
ERRTSS . . . . . . . . . . . . .  	NUMBER	000A	
ERRWRITE . . . . . . . . . . . .  	NUMBER	0020	
EXCPERR  . . . . . . . . . . . .  	NUMBER	0001	

FRSETS_UNSUPPORTED . . . . . . .  	NUMBER	0099	
FRSET_INVALID_DMA  . . . . . . .  	NUMBER	009F	
FRSET_NON_ZERO . . . . . . . . .  	NUMBER	009C	
FRSET_NO_DMA . . . . . . . . . .  	NUMBER	009E	
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-8


FRSET_UNDEFINED  . . . . . . . .  	NUMBER	009D	
FRS_array  . . . . . . . . . . .  	V WORD	0000	_DATA	External
FRS_COUNT  . . . . . . . . . . .  	NUMBER	0010	
FRS_free . . . . . . . . . . . .  	V BYTE	0000	_DATA	External

GDTD_GSEL  . . . . . . . . . . .  	NUMBER	0008	
GET_COUNTER_VALUE  . . . . . . .  	N PROC	0ED8	_TEXT	Length = 0011
GSPM_CHK_SIZE  . . . . . . . . .  	L NEAR	01FB	_TEXT
GSPM_GET . . . . . . . . . . . .  	NUMBER	0000	
GSPM_GETSET  . . . . . . . . . .  	NUMBER	0002	
GSPM_INV_FUN . . . . . . . . . .  	L NEAR	020D	_TEXT
GSPM_INV_SUBFUN  . . . . . . . .  	L NEAR	0208	_TEXT
GSPM_SET . . . . . . . . . . . .  	NUMBER	0001	
GSPM_SIZE  . . . . . . . . . . .  	NUMBER	0003	
GSPPM_CORRUPT  . . . . . . . . .  	L NEAR	03A5	_TEXT
GSPPM_GET_LOOP . . . . . . . . .  	L NEAR	02EA	_TEXT
GSPPM_INV_PHYS . . . . . . . . .  	L NEAR	03C7	_TEXT
GSPPM_INV_SEG  . . . . . . . . .  	L NEAR	03C7	_TEXT
GSPPM_INV_SUBFUN . . . . . . . .  	L NEAR	03C2	_TEXT
GSPPM_NOT0 . . . . . . . . . . .  	L NEAR	033C	_TEXT
GSPPM_NOT1 . . . . . . . . . . .  	L NEAR	03AA	_TEXT
GSPPM_OK . . . . . . . . . . . .  	L NEAR	0337	_TEXT
GSPPM_SET_DONE . . . . . . . . .  	L NEAR	038E	_TEXT
GSPPM_SET_LOOP . . . . . . . . .  	L NEAR	0361	_TEXT
GSPPM_SL_BAD . . . . . . . . . .  	L NEAR	03A3	_TEXT
GSPPM_UNMAP  . . . . . . . . . .  	L NEAR	039E	_TEXT

HANDLE_CNT . . . . . . . . . . .  	NUMBER	00FF	
HANDLE_NAME_NOT_FOUND  . . . . .  	NUMBER	00A0	

I386 . . . . . . . . . . . . . .  	TEXT  		
IDTD_GSEL  . . . . . . . . . . .  	NUMBER	0010	
INSUFFICIENT_EMM_PAGES . . . . .  	NUMBER	0093	
INVALID_FRSET  . . . . . . . . .  	NUMBER	009A	
INVALID_FUNCTION . . . . . . . .  	NUMBER	0084	
INVALID_HANDLE . . . . . . . . .  	NUMBER	0083	
INVALID_MEMORY_TYPE  . . . . . .  	NUMBER	0098	
INVALID_OFFSET . . . . . . . . .  	NUMBER	0095	
INVALID_REGION_LENGTH  . . . . .  	NUMBER	0096	
INVALID_SUBFUNCTION  . . . . . .  	NUMBER	008F	
INVALID_WRAPAROUND . . . . . . .  	NUMBER	00A2	

kstack_top . . . . . . . . . . .  	V BYTE	0000	STACK	External
K_GETC286  . . . . . . . . . . .  	NUMBER	00C0	
K_PUTC286  . . . . . . . . . . .  	NUMBER	00B8	

LATCH_COUNTER  . . . . . . . . .  	NUMBER	0000	
LDTD_GSEL  . . . . . . . . . . .  	NUMBER	0020	
LDT_GSEL . . . . . . . . . . . .  	NUMBER	0018	
LOADALL_GSEL . . . . . . . . . .  	NUMBER	0080	
LOG_PAGE_RANGE . . . . . . . . .  	NUMBER	008A	

MAPHANDLEARRAY_ENTRY_2 . . . . .  	L NEAR	03D6	_TEXT
MAP_EMM_PAGE . . . . . . . . . .  	N PROC	0000	_TEXT	Length = 005D
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-9


MAP_PAGE . . . . . . . . . . . .  	N PROC	00D2	_TEXT	Length = 003F
MAP_PREV_SAVED . . . . . . . . .  	NUMBER	008D	
MAX_ABOVE_CONV_PAGES . . . . . .  	NUMBER	0008	
MAX_PHYS_PAGES . . . . . . . . .  	NUMBER	0028	
MBSRC_GSEL . . . . . . . . . . .  	NUMBER	00E0	
MBTAR_GSEL . . . . . . . . . . .  	NUMBER	00E8	
MEM_2_EMM_FORWARD  . . . . . . .  	L NEAR	0963	_TEXT
MEM_BAD_MEMORY_TYPES . . . . . .  	L NEAR	0C10	_TEXT
MEM_BOTH_ARE_EMM . . . . . . . .  	L NEAR	0953	_TEXT
MEM_CALCULATE_LENGTH . . . . . .  	L NEAR	096F	_TEXT
MEM_CHECK_DONE . . . . . . . . .  	L NEAR	0ACC	_TEXT
MEM_CHECK_SOURCE . . . . . . . .  	L NEAR	0A5A	_TEXT
MEM_CONV_COPY  . . . . . . . . .  	L NEAR	0BA9	_TEXT
MEM_CONV_COPY_LOOP . . . . . . .  	L NEAR	0BB3	_TEXT
MEM_CONV_DONE  . . . . . . . . .  	L NEAR	0BE0	_TEXT
MEM_CONV_TO_CONV . . . . . . . .  	L NEAR	0AD9	_TEXT
MEM_CONV_XCHG  . . . . . . . . .  	L NEAR	0BC7	_TEXT
MEM_CONV_XCHG_LOOP . . . . . . .  	L NEAR	0BCA	_TEXT
MEM_DEST_GT_SOURCE . . . . . . .  	L NEAR	07AE	_TEXT
MEM_DEST_GT_SOURCE_2 . . . . . .  	L NEAR	0B6A	_TEXT
MEM_DO_MOVE_XCHG . . . . . . . .  	L NEAR	0979	_TEXT
MEM_ERROR_EXIT . . . . . . . . .  	L NEAR	0BF7	_TEXT
MEM_EXCHANGE . . . . . . . . . .  	L NEAR	09A2	_TEXT
MEM_EXIT . . . . . . . . . . . .  	L NEAR	0C24	_TEXT
MEM_INV_OVERLAP  . . . . . . . .  	L NEAR	0C15	_TEXT
MEM_INV_REGION_LEN . . . . . . .  	L NEAR	0C0B	_TEXT
MEM_INV_SUB  . . . . . . . . . .  	L NEAR	0C06	_TEXT
MEM_LOOP . . . . . . . . . . . .  	L NEAR	092D	_TEXT
MEM_MAPPING_ERROR  . . . . . . .  	L NEAR	0C1E	_TEXT
MEM_MAPPING_ERROR_3_POP  . . . .  	L NEAR	0C1B	_TEXT
MEM_MAPPING_ERROR_4_POP  . . . .  	L NEAR	0C1A	_TEXT
MEM_MAP_DEST . . . . . . . . . .  	L NEAR	082C	_TEXT
MEM_MAP_DEST_FORWARD . . . . . .  	L NEAR	085B	_TEXT
MEM_MAP_NEXT_DEST  . . . . . . .  	L NEAR	0A20	_TEXT
MEM_MAP_NEXT_DEST_DO_MAP . . . .  	L NEAR	0A34	_TEXT
MEM_MAP_NEXT_DEST_FORWARD  . . .  	L NEAR	0A31	_TEXT
MEM_MAP_NEXT_SOURCE  . . . . . .  	L NEAR	0A92	_TEXT
MEM_MAP_NEXT_SOURCE_DO_MAP . . .  	L NEAR	0AA6	_TEXT
MEM_MAP_NEXT_SOURCE_FORWARD  . .  	L NEAR	0AA3	_TEXT
MEM_MAP_SOURCE . . . . . . . . .  	L NEAR	08C4	_TEXT
MEM_MAP_SOURCE_FORWARD . . . . .  	L NEAR	08F3	_TEXT
MEM_MOVE_FORWARD . . . . . . . .  	L NEAR	0989	_TEXT
MEM_NEXT_ROUND . . . . . . . . .  	L NEAR	09DF	_TEXT
MEM_NO_ERROR . . . . . . . . . .  	L NEAR	0C01	_TEXT
MEM_NO_OVERLAP . . . . . . . . .  	L NEAR	07C8	_TEXT
MEM_NO_OVERLAP_2 . . . . . . . .  	L NEAR	0B92	_TEXT
MEM_SET_DEST . . . . . . . . . .  	L NEAR	07FB	_TEXT
MEM_SET_DONE . . . . . . . . . .  	L NEAR	0929	_TEXT
MEM_SET_SOURCE . . . . . . . . .  	L NEAR	0892	_TEXT
MEM_SI_GT_DI . . . . . . . . . .  	L NEAR	096D	_TEXT
MEM_SOURCE_IS_EMM  . . . . . . .  	L NEAR	0946	_TEXT
MEM_VALID_OVERLAP  . . . . . . .  	L NEAR	0BFC	_TEXT
MEM_XCHG_BYTES . . . . . . . . .  	L NEAR	09C5	_TEXT
MEM_XCHG_BYTE_LOOP . . . . . . .  	L NEAR	09CE	_TEXT
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-10


MEM_XCHG_DONE  . . . . . . . . .  	L NEAR	09DC	_TEXT
MEM_XCHG_DWORD_LOOP  . . . . . .  	L NEAR	09B1	_TEXT
MEP_INV_PAGE . . . . . . . . . .  	L NEAR	005B	_TEXT
ME_MAP_CONVENTIONAL  . . . . . .  	L NEAR	0CA2	_TEXT
ME_MAP_INVALID_LOG_PAGE  . . . .  	L NEAR	0CF9	_TEXT
ME_MAP_INVALID_OFFSET  . . . . .  	L NEAR	0D00	_TEXT
ME_MAP_INV_HANDLE  . . . . . . .  	L NEAR	0CF1	_TEXT
ME_MAP_INV_MEM . . . . . . . . .  	L NEAR	0CEA	_TEXT
ME_MAP_INV_OVERLAP . . . . . . .  	L NEAR	0D0E	_TEXT
ME_MAP_INV_WRAPAROUND  . . . . .  	L NEAR	0D15	_TEXT
ME_MAP_NOT_ENOUGH_EMM  . . . . .  	L NEAR	0D07	_TEXT
ME_MAP_OK  . . . . . . . . . . .  	L NEAR	0CE3	_TEXT
MHA_EXIT . . . . . . . . . . . .  	L NEAR	0455	_TEXT
MHA_INV_HANDLE . . . . . . . . .  	L NEAR	045C	_TEXT
MHA_INV_SEG  . . . . . . . . . .  	L NEAR	0466	_TEXT
MHA_INV_SUB  . . . . . . . . . .  	L NEAR	0461	_TEXT
MHA_SUB0 . . . . . . . . . . . .  	L NEAR	0405	_TEXT
MHA_SUB1 . . . . . . . . . . . .  	L NEAR	041C	_TEXT
MHP_INV_HANDLE . . . . . . . . .  	L NEAR	0142	_TEXT
MONO_GSEL  . . . . . . . . . . .  	NUMBER	0060	
MP_INV_EMM_PAGE  . . . . . . . .  	L NEAR	00FF	_TEXT
MP_INV_LOG . . . . . . . . . . .  	L NEAR	010B	_TEXT
MP_INV_PHY . . . . . . . . . . .  	L NEAR	0105	_TEXT
MP_UNMAP_PAGE  . . . . . . . . .  	L NEAR	00FA	_TEXT
MSW_PROTECT  . . . . . . . . . .  	NUMBER	0001	

NOHIMEM  . . . . . . . . . . . .  	TEXT  		
NOT_ENOUGH_EXT_MEM . . . . . . .  	NUMBER	0087	
NOT_ENOUGH_FREE_MEM  . . . . . .  	NUMBER	0088	
NO_EMM_OVERLAP . . . . . . . . .  	L NEAR	0CE3	_TEXT
NO_MAP_SAVED . . . . . . . . . .  	NUMBER	008E	
NO_MORE_FRSETS . . . . . . . . .  	NUMBER	009B	
NO_MORE_HANDLES  . . . . . . . .  	NUMBER	0085	
NULL_HANDLE  . . . . . . . . . .  	NUMBER	0FFF	
NULL_PAGE  . . . . . . . . . . .  	NUMBER	FFFF	
NUM_CONV_PGS . . . . . . . . . .  	NUMBER	0018	

OEM0_GSEL  . . . . . . . . . . .  	NUMBER	0110	
OEM1_GSEL  . . . . . . . . . . .  	NUMBER	0118	
OEM2_GSEL  . . . . . . . . . . .  	NUMBER	0120	
OEM3_GSEL  . . . . . . . . . . .  	NUMBER	0128	
OK . . . . . . . . . . . . . . .  	NUMBER	0000	
OS_DISABLED  . . . . . . . . . .  	NUMBER	0002	
OS_ENABLED . . . . . . . . . . .  	NUMBER	0001	
OS_IDLE  . . . . . . . . . . . .  	NUMBER	0000	
OVERLAPPING_EXCHANGE . . . . . .  	NUMBER	0097	
OVERLAP_FLAG . . . . . . . . . .  	NUMBER	0040	

PAGET_GSEL . . . . . . . . . . .  	NUMBER	00F0	
PAGE_MAPPABLE  . . . . . . . . .  	NUMBER	00FF	
PAGE_NOT_MAPPABLE  . . . . . . .  	NUMBER	0000	
PAGE_SIZE  . . . . . . . . . . .  	NUMBER	1000	
PFLAG_PATCH_CS_IP  . . . . . . .  	NUMBER	0008	
PFLAG_VIRTUAL  . . . . . . . . .  	NUMBER	0020	
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-11


PFLAG_VM . . . . . . . . . . . .  	NUMBER	0002	
PF_Base  . . . . . . . . . . . .  	V WORD	0000	_DATA	External
PHYS_PAGE_RANGE  . . . . . . . .  	NUMBER	008B	
PRIVERR  . . . . . . . . . . . .  	NUMBER	0000	
P_ACC  . . . . . . . . . . . . .  	NUMBER	0010	
P_AVAIL  . . . . . . . . . . . .  	NUMBER	0007	
P_DIRTY  . . . . . . . . . . . .  	NUMBER	0020	
P_PRES . . . . . . . . . . . . .  	NUMBER	0001	
P_SIZE . . . . . . . . . . . . .  	NUMBER	1000	
P_USER . . . . . . . . . . . . .  	NUMBER	0004	
P_WRITE  . . . . . . . . . . . .  	NUMBER	0002	

RCODEA_GSEL  . . . . . . . . . .  	NUMBER	00C8	
RM_IDT_GSEL  . . . . . . . . . .  	NUMBER	0038	
ROMDATA_GSEL . . . . . . . . . .  	NUMBER	0040	
RPL_CLR  . . . . . . . . . . . .  	NUMBER	FFFFFFFC 
RPL_MASK . . . . . . . . . . . .  	NUMBER	0003	
RPM_NO_MAP_SAVED . . . . . . . .  	L NEAR	01E0	_TEXT
R_AVL  . . . . . . . . . . . . .  	NUMBER	0010	
R_GRAN . . . . . . . . . . . . .  	NUMBER	0080	
R_LIMIT_XHI  . . . . . . . . . .  	NUMBER	000F	

SAVED_PAGE_DEALLOC . . . . . . .  	NUMBER	0086	
SAVE_AREA_FULL . . . . . . . . .  	NUMBER	008C	
SegOffTo24Resident . . . . . . .  	L NEAR	0000	_TEXT	External
SELECTOR_MASK  . . . . . . . . .  	NUMBER	FFF8	
SEL_LOW_MASK . . . . . . . . . .  	NUMBER	00F8	
SetDescInfoResident  . . . . . .  	L NEAR	0000	_TEXT	External
SM_EXIT  . . . . . . . . . . . .  	L NEAR	026B	_TEXT
SM_INV_SOURCE  . . . . . . . . .  	L NEAR	0266	_TEXT
SOURCE_CORRUPTED . . . . . . . .  	NUMBER	00A3	
SOURCE_GT_DEST_FLAG  . . . . . .  	NUMBER	0080	
SPM_PREV_SAVED . . . . . . . . .  	L NEAR	0188	_TEXT
SRPM_INV_HANDLE  . . . . . . . .  	L NEAR	018D	_TEXT
SRPM_NOPF  . . . . . . . . . . .  	L NEAR	0192	_TEXT
STACK0_SIZE  . . . . . . . . . .  	NUMBER	0200	
STK_SIZE . . . . . . . . . . . .  	NUMBER	4000	
SW_CORRUPT . . . . . . . . . . .  	L NEAR	02B8	_TEXT
SW_DONE_PAGE . . . . . . . . . .  	L NEAR	02A1	_TEXT
SW_LOOP  . . . . . . . . . . . .  	L NEAR	0275	_TEXT
SW_UNMAP_PAGE  . . . . . . . . .  	L NEAR	02AF	_TEXT
SYSTEM_CLOCK_PORT  . . . . . . .  	NUMBER	0040	
SYS_CLOCK_CTRL_PORT  . . . . . .  	NUMBER	0043	
SYS_IOPL . . . . . . . . . . . .  	NUMBER	3000	

TABLE_MASK . . . . . . . . . . .  	NUMBER	0004	
TAB_GDT  . . . . . . . . . . . .  	NUMBER	0000	
TAB_LDT  . . . . . . . . . . . .  	NUMBER	0004	
TOT_PHYS_PAGES . . . . . . . . .  	NUMBER	0040	
TSSD_GSEL  . . . . . . . . . . .  	NUMBER	0030	
TSS_GSEL . . . . . . . . . . . .  	NUMBER	0028	

UNMAP_PAGE . . . . . . . . . . .  	N PROC	005D	_TEXT	Length = 0075
UNMAP_PAGE_EXIT  . . . . . . . .  	L NEAR	00CD	_TEXT
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-12


UNMAP_PAGE_FOUND . . . . . . . .  	L NEAR	0085	_TEXT
UNMAP_PAGE_LOOP  . . . . . . . .  	L NEAR	0077	_TEXT
UNMAP_PAGE_OK  . . . . . . . . .  	L NEAR	00B0	_TEXT
USER1_GSEL . . . . . . . . . . .  	NUMBER	0130	

VALIDATE_FOR_MOVE_OR_EXCHANGE  .  	N PROC	0C37	_TEXT	Length = 00E5
VALID_OVERLAP  . . . . . . . . .  	NUMBER	0092	
VDMCA_GSEL . . . . . . . . . . .  	NUMBER	00F8	
VDMC_GSEL  . . . . . . . . . . .  	NUMBER	0048	
VDMD_GSEL  . . . . . . . . . . .  	NUMBER	0050	
VDMS_GSEL  . . . . . . . . . . .  	NUMBER	0058	
VM1_GSEL . . . . . . . . . . . .  	NUMBER	00D0	
VM2_GSEL . . . . . . . . . . . .  	NUMBER	00D8	
VMTERR_STACK . . . . . . . . . .  	TEXT  offset STACK:kstack_top - size VM_TRAP_FRAME - VTFOE		
VMT_STACK  . . . . . . . . . . .  	TEXT  offset STACK:kstack_top - size VM_TRAP_FRAME - VTFO		
VTFO . . . . . . . . . . . . . .  	NUMBER	0004	
VTFOE  . . . . . . . . . . . . .  	NUMBER	0008	

ZERO_PAGES . . . . . . . . . . .  	NUMBER	0089	

@CPU . . . . . . . . . . . . . .  	TEXT  3471		
@FILENAME  . . . . . . . . . . .  	TEXT  emmp		
@VERSION . . . . . . . . . . . .  	TEXT  510		
_AlterMapAndCall . . . . . . . .  	N PROC	04C8	_TEXT	Global	Length = 01C3
_AlterMapAndJump . . . . . . . .  	N PROC	046C	_TEXT	Global	Length = 005C
_AlternateMapRegisterSet . . . .  	N PROC	0D1C	_TEXT	Global	Length = 01B0
_cntxt_bytes . . . . . . . . . .  	V BYTE	0000	_DATA	External
_cntxt_pages . . . . . . . . . .  	V BYTE	0000	_DATA	External
_dest_addr . . . . . . . . . . .  	L NEAR	0000	_TEXT	External
_emm_page  . . . . . . . . . . .  	V WORD	0000	_DATA	External
_GetSetPageMap . . . . . . . . .  	N PROC	01E8	_TEXT	Global	Length = 002A
_GetSetPartial . . . . . . . . .  	N PROC	02BE	_TEXT	Global	Length = 010E
_Get_Key_Val . . . . . . . . . .  	N PROC	0ECC	_TEXT	Global	Length = 000C
_GET_MAP . . . . . . . . . . . .  	N PROC	0214	_TEXT	Length = 0022
_handle_table  . . . . . . . . .  	V WORD	0000	_DATA	External
_handle_table_size . . . . . . .  	V WORD	0000	_DATA	External
_MapHandleArray  . . . . . . . .  	N PROC	03CC	_TEXT	Global	Length = 00A0
_MapHandlePage . . . . . . . . .  	N PROC	0114	_TEXT	Global	Length = 0033
_mappable_pages  . . . . . . . .  	V WORD	0000	_DATA	External
_mappable_page_count . . . . . .  	V WORD	0000	_DATA	External
_MoveExchangeMemory  . . . . . .  	N PROC	0718	_TEXT	Global	Length = 051F
_OSEnabled . . . . . . . . . . .  	V DWORD	0000	_DATA	External
_page_frame_base . . . . . . . .  	V DWORD	0000	_DATA	External
_page_frame_pages  . . . . . . .  	V WORD	0000	_DATA	External
_pft386  . . . . . . . . . . . .  	V WORD	0000	_DATA	External
_physical_page_count . . . . . .  	V WORD	0000	_DATA	External
_regp  . . . . . . . . . . . . .  	V WORD	0000	_DATA	External
_RestorePageMap  . . . . . . . .  	N PROC	0198	_TEXT	Global	Length = 004D
_SavePageMap . . . . . . . . . .  	N PROC	0148	_TEXT	Global	Length = 004F
_save_map  . . . . . . . . . . .  	V BYTE	0000	_DATA	External
_SET_MAP . . . . . . . . . . . .  	N PROC	0238	_TEXT	Length = 0034
_SET_WINDOWS . . . . . . . . . .  	N PROC	026C	_TEXT	Length = 0052
_source_addr . . . . . . . . . .  	L NEAR	0000	_TEXT	External
_total_pages . . . . . . . . . .  	V WORD	0000	_DATA	External
Microsoft (R) Macro Assembler Version 5.10                  5/17/24 09:44:41
EMMP - EMM protected mode functions                         Symbols-13


_VM1_EMM_Pages . . . . . . . . .  	V WORD	0000	_DATA	External


   4110 Source  Lines
   4472 Total   Lines
    610 Symbols

  45558 + 126823 Bytes symbol space free

      0 Warning Errors
      0 Severe  Errors
