summaryrefslogtreecommitdiff
path: root/v4.0/src/MEMM/MEMM/EM386LL.ASM
blob: 3408eaa648831d31d8d0d4cba2d1aabf064a9934 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
page	58,132
;******************************************************************************
	title	EM386LL - 386 routine to emulate 386 LOADALL
;******************************************************************************
;
;   (C) Copyright MICROSOFT Corp. 1986
;
;   Title:    MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
;
;   Module:   EM386LL - 386 routine to emulate 386 LOADALL
;
;   Version:  0.04
;
;   Date:     April 11,1986
;
;   Author:
;
;******************************************************************************
;
;   Change log:
;
;     DATE    REVISION			DESCRIPTION
;   --------  --------	-------------------------------------------------------
;   04/16/86  Original
;   05/12/86  A	Cleanup and segment reorganization
;   06/28/86  0.02	Name change from MEMM386 to MEMM
;   06/29/86  0.02	Fixed error handler call. Error handler called
;			only on attempt to set VM bit in EFLAGS
;   06/30/86  0.02	Jmp to error routine (instead of calling)
;   07/03/86  0.03	Removed logic to enable A20 line watch
;   07/05/86  0.04	JumpReal in R_CODE
;   07/06/86  0.04	Changed assume to DGROUP
;   07/08/86  0.04	added DB67 NOPs to avoid B1 errata
;
;******************************************************************************
;
;   Functional Description:
;
;   386 LOADALL is emulated by building a buffer for a
;   386 LOADALL from the client's 386 LOADALL buffer and executing the 386
;   LOADALL.
;
;		check DR6/DR7 for addresses > 1meg ?
;
;******************************************************************************
.lfcond 				; list false conditionals
.386p
	page
;******************************************************************************
;			P U B L I C   D E C L A R A T I O N S
;******************************************************************************
;
	public	EM386ll
;
	page
;******************************************************************************
;			L O C A L   C O N S T A N T S
;******************************************************************************
;
	include loadall.inc
	include VDMseg.inc
	include desc.inc
	include VDMsel.inc
	include instr386.inc
	include vm386.inc
	include	oemdep.inc

FALSE	equ	0
TRUE	equ	not FALSE

;
; Desc3Copy
;	Macro for copying a 386 Loadall descriptor cache entry to a
;	386 Loadall descriptor cache entry.
;   ENTRY: DS:ESI pts to client's 386 Loadall descriptor entry
;	   ES:DI pts to our 386 Loadall descriptor entry
;
;   EXIT:  DS:ESI pts to byte after client's 386 ll descr entry (next entry).
;	   ES:DI pts to byte after 386 Loadall descriptor entry (next entry).
;		*** The access rights byte in set to DPL 3 for virtual mode ***
;
;   USED:  EAX
;
Desc3Copy	MACRO
	OP32
	EA32				; EAX = dword from DS:[ESI]
	lodsw				; get access rights

	or	ah,D_DPL3		;* set DPL 3 for virtual mode access

	OP32
	stosw				; store access rights

	OP32
	EA32				; EAX = dword from DS:[ESI]
	lodsw				; 32 bits of Base Addr from 386 entry

	call	MapLinear		; map this linear addr by page tables

	OP32
	stosw				; store Base Addr for 386 entry

	OP32
	EA32				; EAX = dword from DS:[ESI]
	lodsw				; get 32 bits of limit

	OP32
	stosw				; store 32 bit LIMIT into 386 entry
	ENDM

;
; CurCopy
;	Macro for copying a current descriptor cache entry to a
;	386 Loadall descriptor cache entry.
;   ENTRY: DS:BX pts to current descriptor
;	   ES:DI pts to 386 Loadall descriptor entry
;
;   EXIT:  DS:BX unchanged.
;	   ES:DI pts to byte after 386 Loadall descriptor entry (next entry).
;		*** The access rights byte in set to DPL 3 for virtual mode ***
;
;   USED:  EAX
;
CurCopy 	MACRO
	OP32
	mov	ax,[bx+4]		; get AR info
	or	ah,D_DPL3		;* set DPL 3 for virtual mode access
	OP32
	stosw				; store into cache entry
	mov	ah,[bx+7]		; AX = Base[31..16]
	OP32
	shl	ax,16			; high word of EAX = Base[31..16]
	mov	ax,[bx+2]		; EAX = Base[31..0]
	OP32
	stosw
	mov	al,[bx+6]		; LIMIT[19..16] in low bits of AL
	and	ax,0Fh
	OP32
	shl	ax,16			; high word of EAX = LIMIT[31..16]
					; NOTE: VDM does not use page
					;  granularity for limit field !!
	mov	ax,[bx] 		; EAX = LIMIT[31..0]
	OP32
	stosw				; store into cache for 386 buffer
	ENDM

;******************************************************************************
;			L O C A L   D A T A   A R E A
;******************************************************************************

_DATA	 segment
extrn	ELOff:word		; offset of 386 loadall buffer
_DATA	 ends


R_CODE	segment
extrn	JumpReal:far		; continue client in real mode (rrtrap.asm)
R_CODE	ends

_TEXT	segment
extrn	MapLinear:near		; maps linear addresses	 (maplin.asm)
extrn	PortTrap:near		; IOBM trap set function (vminit.asm)
extrn	ErrHndlr:near		; error handler		 (errhndlr.asm)
_TEXT	ends


	page
;******************************************************************************
;			S E G M E N T	D E F I N I T I O N
;******************************************************************************
;
_TEXT	 segment
	ASSUME CS:_TEXT,DS:DGROUP,ES:DGROUP

;******************************************************************************
;	EM386ll - emulate 386 Loadall
;	The basic approach here is to filter the client's loadall buffer into
;	a temporary buffer, setting our values for the parameters we don't want
;	him to change and then executing the 386 loadall from our buffer.
;
;	ENTRY:	Protected Mode
;		BP points to bottom of client's GPfault stack frame
;		ES(in GP frame):EDI points to the client's loadall buffer info
;		 on stack: ESI,EBX,EBP
;
;	EXIT:	via Loadall to virtual mode
;		The 386 Loadall buffer is emulated with the following
;		exceptions:
;		  The VM bit is set in EFLAGS.
;		  The TR, IDT descriptor cache, & TSS descriptor cache are
;			pointed to the VDM entries.
;
;	USED:	Not applicable...  loadall reloads all registers
;
;******************************************************************************
EM386ll proc	near
;
	PUSH_EAX
	PUSH_ECX
	PUSH_EDI

;   Build a descriptor to client's 386 loadall buffer

	mov	bx,GDTD_GSEL		; get GDT data alias
	mov	ds,bx			; DS -> GDT
	mov	bx, [bp.VTFOE+VMTF_ES]	; Get VM ES from GP stack frame
	mov	ax,bx
	shl	bx,4			; BX = low 16 bits of base
	mov	ds:[VM1_GSEL+2],bx	; place in descriptor
	shr	ax, 4			; AH = high 8 bits of base
	mov	ds:[VM1_GSEL+4],ah	; place in descriptor

;   Point DS:ESI to start of client's 386 loadall buffer
	mov	bx,VM1_GSEL
	mov	ds,bx
	OP32
	mov	si,di
	ASSUME	ds:nothing

;   Point ES:EDI to start of our 386 loadall buffer

	mov	ax,VDMD_GSEL
	mov	es,ax
	OP32
	xor	di,di			; clear EDI
	mov	di,ES:[ELOff]		; ES:EDI pts to our 386 loadall buffer
;
	cld

;   Walk through the two buffers in parallel, copying the client's values
;   when appropriate

;
;   CR0 entry
;
	EA32
	OP32
	lodsw				; get client's CR0

;(0.02)	OP32
;(0.02)	test	ax,0001h		;    TEST EAX,80000001h
;(0.02)	dw	8000h			; Q: PG or PE bit set ?
;(0.02)	jz	CR0_OK			;   N: continue
;(0.02)	call	Em386_Err		;   Y: error
;
CR0_OK:
	MOV_ECX_CR0
	OP32
	and	cx,0011h		; and ECX,80000011h
	dw	8000h			; save only PG,ET, & PE bits
	OP32
	or	ax,cx			; or EAX,ECX
	OP32
	stosw				;  store CR0 for 386 buffer
	XOR_ECX_ECX			; clear ECX
;
;  EFLAGS
;
	EA32
	OP32
	lodsw				; get EFLAGS
;
	OP32
	test	ax,0000h
	dw	0002h			;Q: client's VM bit set ?
	jz	EF_OK			;  N: continue
	jmp	Em386_Err		;  Y: error handler - won't return here
EF_OK:
	and	ax,0FFFh		; clear IOPL & NT bits
	OP32
	or	ax,3000h
	dw	0002h			; set VM bit and IOPL = 3
	OP32
	stosw				;  store EFLAGS for 386 buffer
;
;   Copy the client's EIP, EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX, DR6 & DR7
;   register images from his 386 loadall buffer to our 386 loadall buffer
;
	mov	cx,11			; copy 11 register contents
	OP32				; dwords from DS:[ESI] to ES:[EDI]
	EA32
	rep movsw			; copy 11 dwords

	EA32
	nop		; this avoids a B1 errata
;
;   store TR and LDTR
;
	XOR_EAX_EAX			; clear EAX
	mov	ax,TSS_GSEL		; get current TR for VDM's TSS !!!
	OP32
	stosw				;  store TR for 386 buffer
;
	sldt	ax			; use current LDT
	OP32
	stosw				;  store LDTR for 386 buffer
;
;   Copy the client's GS, FS, DS, SS, CS, ES register images from
;   his 386 loadall buffer to our 386 loadall buffer
;
	add	si,offset ll3_GS - offset ll3_TSSR
	mov	cx,6
	OP32				; dwords from DS:[ESI] to ES:[EDI]
	EA32
	rep movsw			; copy 6 dwords

	EA32
	nop		; this avoids a B1 errata
;
;   Copy the current TSS, GDT, IDT, LDT  descriptors from the GDT table to
;   our 386 loadall buffer
;
	push	ds			; save client's buffer selector
	mov	ax,GDTD_GSEL
	mov	ds,ax

	mov	cx, 4
	mov	bx, TSS_GSEL
	push	word ptr LDTD_GSEL
	push	word ptr GDTD_GSEL
	push	word ptr IDTD_GSEL

CopyCur:				; Copy current descriptors
	CurCopy 			; DS:[BX] points to current descriptor
	pop	bx
	loop	CopyCur
	mov	ds, bx			; restore client's buffer selector

					; DS:SI pts to 386 GS cache entry
;
;   Copy the client's GS, FS, DS, SS, CS, ES register cache images from
;   his 386 loadall buffer to our 386 loadall buffer
;
	add	si,offset ll3_GScache - offset ll3_TSScache
	mov	cx,6
CopyCac:				; ES:DI pts to our 386 buf cache entry
	Desc3Copy			;   store his cache in our 386 buffer
	loop	CopyCac 		; DS:SI pts to client's buf cache entry

;
;   386 Loadall buffer complete
;

;(0.03)	push	es
;(0.03)	mov	ax, TSSD_GSEL		    ; Point ES to TSS for PortTrap
;(0.03)	mov	es, ax
;(0.03)	mov	bh, 80h 		    ; set every 1k
;(0.03)	mov	ax, KbdDataPort
;(0.03)	call	PortTrap		    ; set traps on keyboard ports
;(0.03)	mov	ax, KbdCmdPort		    ; in case client
;(0.03)	call	PortTrap		    ; tries to disable A20
;(0.03)	pop	es
;(0.03)	mov	es:[A20watch], YesLLdone    ; set A20 watch flag

	HwTabLock			    ; Hardware lock the high ram

	OP32
	xor	di,di			    ; XOR EDI,EDI - clear EDI
	mov	di,ES:[ELOff]		    ; ES:EDI pts to loadall buffer
	dw	LODAL386		    ; execute 386 LOADALL

	ASSUME	DS:DGROUP
;
;
EM386ll endp

	page
;******************************************************************************
;	Em386_Err - handle 386 ll emulation error
;		This routine is currently called only on attempts to set the
;	VM bit via loadall.
;******************************************************************************
Em386_Err	proc	near
	push	ax
	push	bx
	mov	ax, PrivErr
	mov	bx, Err3LL
	call	ErrHndlr
	pop	bx
	pop	bx
;
;  continue client in real mode
;
	POP_EDI		; restore used regs
	POP_ECX
	POP_EAX
			; stack back to VmFault exit condition

	jmp	JumpReal	; "jump" to real mode and continue interrupted
				;    code.

Em386_Err	endp
;
_TEXT	 ends
	end