4 ;******************************************************************************
5 title EMM
- Expanded Memory Manager interface for MEMM
6 ;******************************************************************************
8 ; (C) Copyright MICROSOFT Corp. 1986
10 ; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
12 ; Module: EMM - Expanded Memory Manager interface
20 ;******************************************************************************
24 ; DATE REVISION Description
25 ; -------- -------- --------------------------------------------
27 ; 06/28/86 0.02 Name change from MEMM386 to MEMM
28 ; 06/29/86 0.02 Protect port 84/85 from ints
29 ; 07/05/86 0.04 moved EMM_rEntry to R_CODE
30 ; 07/06/86 0.04 Changed assume to DGROUP
31 ; 07/08/86 0.04 Changed EMM_pEntry to call EMM functions
33 ; 07/10/86 0.05 jmp $+2 before "POPF"
34 ; 07/10/86 0.05 added EMM_Flag
35 ; 06/09/88 remove _map_known since there is no map now (pc)
36 ; 07/20/88 remove debugger code (pc)
38 ;******************************************************************************
39 ; Functional Description:
40 ; The module contains code for calling the EMM functions and a routine
41 ; for managing the AUTO mode of MEMM.
42 ; There are two EMM entry points in this module; one for real/virtual
43 ; mode entry and one for protected mode (IDT entry points here). When
44 ; MEMM is ON (system in Virtual mode), INT 67H calls transition to protected
45 ; mode and the EMM_pEntry entry point. EMM_pEntry sets up the same stack
46 ; conditions as the generic int67_Entry dispatcher and calls the appropriate
47 ; EMM function. Some EMM functions cannot be executed in protected mode.
48 ; These functions are called by reflecting the INT 67H to the real/virtual
49 ; mode entry point. EMM functions which are executed in PROTECTED mode
50 ; will take less time (they don't suffer the extra time to reflect the
53 ;******************************************************************************
57 ;******************************************************************************
58 ; P U B L I C D E C L A R A T I O N S
59 ;******************************************************************************
61 public EMM_pEntry
; protected mode entry point
62 public EMM_rEntry
; real mode entry point
63 public EMM_rEfix
; label for far jump to int67_entry
64 public _AutoUpdate
; update auto mode of VDM/EMM
65 public EMM_Flag
; flag for EMM calls
68 ;******************************************************************************
69 ; L O C A L C O N S T A N T S
70 ;******************************************************************************
75 ; include instr386.inc
83 ; these EMM functions are handled in protected mode
85 EMM_MAP_PAGE equ 44h
; map handle page
86 EMM_RESTORE equ 48h
; restore page map
87 EMM_GET_SET equ 4Eh
; get/set page map
88 EMM_GET_SET_PARTIAL equ 4Fh
; get/set partial page map
89 EMM_MAP_PAGE_ARRAY equ 50h
; map handle page array
90 EMM_ALTER_MAP_JUMP equ 55h
; alter mapping and jump
91 EMM_ALTER_MAP_CALL equ 56h
; alter mapping and call
92 EMM_MOVE_XCHG_MEM equ 57h
; move/xchg memory region
93 EMM_ALTER_MAP_REG_SET equ 5
Bh ; alternate map register set
95 EMM_HW_MALFUNCTION equ 81h
;
97 ;******************************************************************************
98 ; E X T E R N A L R E F E R E N C E S
99 ;******************************************************************************
101 ABS0
segment use16 at 0000h
103 org 67h
* 4 ; EMM function interrupt
104 EMMVec dw ?
; offset of vector
105 dw ?
; segment of vector
111 extrn _EMMstatus
:word
112 extrn Active_Status
:byte ; current VDM status
113 extrn Auto_Mode
:byte ; current Auto mode status
114 ;extrn _map_known:byte ; non-zero => I/O map known to a user
115 extrn _handle_count
:word ; number of active EMM handles
116 extrn _regp
:word ; pointer to args on stack
122 extrn int67_Entry
:far ; it's far because we need CS on stack too
128 extrn _GetStatus
:near
129 extrn _GetPageFrameAddress
:near
130 extrn _GetUnallocatedPageCount
:near
131 extrn _AllocatePages
:near
132 extrn _MapHandlePage
:near
133 extrn _DeallocatePages
:near
134 extrn _GetEMMVersion
:near
135 extrn _SavePageMap
:near
136 extrn _RestorePageMap
:near
137 extrn _GetPageMappingRegisterIOArray
:near
138 extrn _GetLogicalToPhysicalPageTrans
:near
139 extrn _GetEMMHandleCount
:near
140 extrn _GetEMMHandlePages
:near
141 extrn _GetAllEMMHandlePages
:near
142 extrn _GetSetPageMap
:near
144 extrn _GetSetPartial
:near
145 extrn _MapHandleArray
:near
146 extrn _AlterMapAndJump
:near
147 extrn _AlterMapAndCall
:near
148 extrn _MoveExchangeMemory
:near
149 extrn _AlternateMapRegisterSet
:near
154 ;******************************************************************************
155 ; S E G M E N T D E F I N I T I O N
156 ;******************************************************************************
159 EMM_Flag db 0 ; non-zero => EMM function called by our code
163 ;******************************************************************************
167 ;******************************************************************************
170 assume
cs:_TEXT
, ds:DGROUP
, es:DGROUP
171 ;******************************************************************************
172 ; protected mode dispatch table
173 ; allocate(43h)/deallocate(45h) pages and get I/O map (49h)
174 ; MUST be reflected to Virtual mode
175 ; MapHandlePage,RestorePageMap,GetSetPageMap,GetSetPartial,
176 ; MapHandleArray,MoveExchangeMemory,AlterMapAndJump,
177 ; AlterMapAndCall and AlternateMapRegisterSet are protected mode ONLY.
178 ;******************************************************************************
179 EpE_Dispatch
label word
180 dw offset _TEXT
:EpE_Null
181 dw offset _TEXT
:EpE_Null
182 dw offset _TEXT
:EpE_Null
183 dw offset _TEXT
:EpE_Null
184 dw offset _TEXT
:_MapHandlePage
;44h
185 dw offset _TEXT
:EpE_Null
186 dw offset _TEXT
:EpE_Null
187 dw offset _TEXT
:EpE_Null
188 dw offset _TEXT
:_RestorePageMap
;48h
189 dw offset _TEXT
:EpE_Null
190 dw offset _TEXT
:EpE_Null
191 dw offset _TEXT
:EpE_Null
192 dw offset _TEXT
:EpE_Null
193 dw offset _TEXT
:EpE_Null
194 dw offset _TEXT
:_GetSetPageMap
;4eh
195 dw offset _TEXT
:_GetSetPartial
;4fh
196 dw offset _TEXT
:_MapHandleArray
;50h
197 dw offset _TEXT
:EpE_Null
198 dw offset _TEXT
:EpE_Null
199 dw offset _TEXT
:EpE_Null
200 dw offset _TEXT
:EpE_Null
201 dw offset _TEXT
:_AlterMapAndJump
;55h
202 dw offset _TEXT
:_AlterMapAndCall
;56h
203 dw offset _TEXT
:_MoveExchangeMemory
;57h
204 dw offset _TEXT
:EpE_Null
205 dw offset _TEXT
:EpE_Null
206 dw offset _TEXT
:EpE_Null
207 dw offset _TEXT
:_AlternateMapRegisterSet
;5bh
208 dw offset _TEXT
:EpE_Null
209 dw offset _TEXT
:EpE_Null
212 ;******************************************************************************
213 ; EMM_pEntry - protected mode entry point for EMM function calls
215 ; ENTRY: Protected mode
216 ; DGROUP:[EMM_Flag] = zero => reflect this int
217 ; SS:[SP] pointing to virtual mode INT stack frame
219 ; EXIT: Protected mode
220 ; if this EMM function is to be handled in protected mode,
221 ; registers as set by EMM functions
223 ; reflect int 67 to virtual mode EMM code
226 ; Allocate(43h)/deallocate(44h) pages and get I/O map (49h)
227 ; MUST be reflected to Virtual mode.
231 ;******************************************************************************
233 ; reflect EMM function to real mode
240 ; client not in Virtual mode
243 pop ebp ; N: call error handler
245 mov ax,ExcpErr
; exception error
246 mov bx,ErrINTProt
; invalid software interrupt
255 test [bp.VTFO
+VMTF_EFLAGShi
],2 ;Q:client in Virtual mode ?
256 jz EpE_not_VM
; N: handle it
262 cmp [EMM_Flag
],0 ;Q: did we do this int67 ?
263 je EpE_Reflect
; N: reflect it
264 mov [EMM_Flag
],0 ; Y: clear EMM_Flag for next
265 ; time and handle function
268 ; dispatch EMM function OR reflect to real/vm dispatcher
271 HwTabUnlock
; unlock ROM
273 push [bp.VTFO
+VMTF_FS
] ; client FS
274 push [bp.VTFO
+VMTF_GS
] ; client GS
275 push [bp.VTFO
+VMTF_ES
] ; client ES
276 push [bp.VTFO
+VMTF_DS
] ; client DS
277 push [bp.VTFO
+VMTF_EFLAGS
] ; client Flag
278 push [bp.VTFO
+VMTF_CS
] ; client CS
279 push word ptr [bp.VTFO
+VMTF_EIP
] ; client IP (low word of EIP)
280 ; stack has - IP,CS,PFlag,DS,ES,GS,FS
281 pushad ; all regs saved
282 mov bp,sp ; SS:BP -> to stack args (see r67_Frame struc)
283 mov [_regp
],sp ; regp points to regs on stack
284 mov [_regp
+2],ss ; regp now has a far ptr to regs
287 mov ax, PFLAG_VIRTUAL
; Faked VM bit
288 or [bp.PFlag
], ax ; Incorpated in PFlag
291 ; validate function code
293 sub ah,40h
; check if entry code too small
294 jb EpE_inv_exit
; if so, error exit
295 cmp ah,(5
Dh-40h
) ; check if entry code too big
296 ja EpE_inv_exit
; if so, error exit
297 ; else, AH = 0 base function #
299 ; call through the jump table
302 xchg ah,al ; AL = function code
304 xchg ah,al ; AH = function code again
305 and si,00FFh ; SI = function #
306 shl si,1 ; SI = table offset
307 call CS:EpE_Dispatch
[si] ; call function
310 ; check to see if we need to patch CS:IP on the iretd stack frame
313 test word ptr [bp.PFlag
], PFLAG_PATCH_CS_IP
316 mov bp, sp ; use bp to address stack
318 ; patch iretd's CS:EIP to new CS:IP on stack
320 mov ax, [bp.retaddr
] ; get return IP
321 mov [bp.rFS
+6], ax ; iretd's IP (6 bytes beyond FS)
323 mov [bp.rFS
+8], ax ; zero high word of EIP
324 mov ax, [bp.rCS
] ; get return CS
325 mov [bp.rFS
+10], ax ; iretd's CS
329 add sp, 6 ; throw away return addr cs and ip and flags
330 pop [bp.VTFO
+VMTF_DS
] ; client DS
331 pop [bp.VTFO
+VMTF_ES
] ; client ES
332 pop [bp.VTFO
+VMTF_GS
] ; client GS
333 pop [bp.VTFO
+VMTF_FS
] ; client FS
340 iretd ; return to virtual mode caller
342 ; Null function - do nothing (should not get to here)
344 ret ; return after doing nothing
348 EpE_inv_exit: ; set invalid function code error
349 mov byte ptr [bp.rAX+1],INVALID_FUNCTION
355 ;******************************************************************************
356 ; EMM_rLink - real/virtual mode link for EMM function calls from
359 ; ENTRY: real/virtual mode
360 ; all registers as set by user
362 ; EXIT: real/virtual mode
363 ; registers as set by EMM functions
367 ;******************************************************************************
371 ; check for protected mode ONLY function
373 cmp ah,EMM_MAP_PAGE
;Q: map handle page function ?
374 je ErE_GoProt
; Y: do it in protected mode
375 cmp ah,EMM_RESTORE
;Q: restore page map function ?
376 je ErE_GoProt
; Y: do it in protected mode
377 cmp ah,EMM_GET_SET
;Q: get/set page map function ?
378 je ErE_GoProt
; Y: do it in protected mode
379 cmp ah,EMM_GET_SET_PARTIAL
;Q: get/set partial function ?
380 je ErE_GoProt
; Y: do it in protected mode
381 cmp ah,EMM_MAP_PAGE_ARRAY
;Q: map handle page array ?
382 je ErE_GoProt
; Y: do it in protected mode
383 cmp ah,EMM_ALTER_MAP_JUMP
;Q: alter map and jump ?
384 je ErE_GoProt
; Y: do it in protected mode
385 cmp ah,EMM_ALTER_MAP_CALL
;Q: alter map and call ?
386 je ErE_GoProt
; Y: do it in protected mode
387 cmp ah,EMM_MOVE_XCHG_MEM
;Q: move/xchg memory region ?
388 je ErE_GoProt
; Y: do it in protected mode
389 cmp ah,EMM_ALTER_MAP_REG_SET
;Q: alternate map register set ?
390 je ErE_GoProt
; Y: do it in protected mode
391 ; N: do it in real/virtual mode
393 ; here for real/virtual mode functions
399 push 00 ; PFlag => real mode call to EMM functions
401 pop ds ; set DS = DGROUP
402 call int67_Entry
; call dispatcher
403 add sp,2 ; drop PFlag arg
404 pop ds ; restore seg regs
411 ; Here if protected mode function called via real IDT
412 ; - set EMM flag and go for it...
418 cmp [Active_Status
],0 ;Q: are we in Virtual Mode ?
419 jne ErE_Pcall
; Y: call protected mode function
420 ; mov [_map_known],TRUE ; N: set global auto mode flag
421 call _AutoUpdate
; go into virtual mode
424 mov [EMM_Flag
],TRUE
; set flag
426 int 67h
; go for it ...
432 ;******************************************************************************
433 ; _AutoUpdate - updates the EMM status when in AutoMode
435 ; ENTRY: REAL or VIRTUAL mode ONLY
436 ; DS = DGROUP segment
437 ; DS:[Auto_Mode] = non-zero => system currently in auto mode
438 ; DS:[Active_Status] = non-zero => system currently ON
439 ; DS:[_map_known] = non-zero => I/O map has been given to a user
441 ; EXIT: exits in real or virtual depending on the state variables
442 ; DS:[Active_Status] = current ON/OFF status
446 ;******************************************************************************
447 _AutoUpdate proc
near
449 cmp [Auto_Mode
],0 ;Q: in Auto mode now ?
451 cmp [Active_Status
],0 ; Y:Q: ON now ?
452 je AU_chkoff
; N: check OFF state status
454 ; here if we are currently ON
456 ; cmp [_map_known],0 ; Y:Q: map known ?
457 ; jne AU_exit ; Y: then stay ON...
458 cmp [_handle_count
],0 ; N:Q: any active handles ?
459 jne AU_exit
; Y: then stay ON...
460 mov [Active_Status
],0 ; N: go to OFF state
462 call RRProc
; Force processor into real mode
464 jmp AU_exit
; and leave in real mode
466 ; here if we are currently OFF
469 cmp [_handle_count
],0 ;Q: any active handles ?
470 je AU_exit
; N: stay off
472 ; cmp [_map_known],0 ;; Q: is the map known ?
473 ; je AU_exit ;; N: then stay OFF...
475 AU_ON: ; Y: turn ON EMM
476 mov [Active_Status
],1 ; go to ON state,
477 call GoVirtual
; and go to virtual mode (ON)
486 ;******************************************************************************
488 ; R_CODE Code Segment
490 ;******************************************************************************
493 assume
cs:R_CODE
, ds:DGROUP
, es:DGROUP
496 ;******************************************************************************
497 ; EMM_rEntry - real/virtual mode entry point for EMM function calls
499 ; ENTRY: real/virtual mode
500 ; all registers as set by user
502 ; EXIT: real/virtual mode
503 ; registers as set by EMM functions
507 ;******************************************************************************
510 cli ; just in case pushf/call far
513 call EMM_rLink
; call _TEXT segment link
514 iret ; return to caller