]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/MEMM/MEMM/EM386LL.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / MEMM / MEMM / EM386LL.ASM
1
2
3 page 58,132
4 ;******************************************************************************
5 title EM386LL - 386 routine to emulate 386 LOADALL
6 ;******************************************************************************
7 ;
8 ; (C) Copyright MICROSOFT Corp. 1986
9 ;
10 ; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
11 ;
12 ; Module: EM386LL - 386 routine to emulate 386 LOADALL
13 ;
14 ; Version: 0.04
15 ;
16 ; Date: April 11,1986
17 ;
18 ; Author:
19 ;
20 ;******************************************************************************
21 ;
22 ; Change log:
23 ;
24 ; DATE REVISION DESCRIPTION
25 ; -------- -------- -------------------------------------------------------
26 ; 04/16/86 Original
27 ; 05/12/86 A Cleanup and segment reorganization
28 ; 06/28/86 0.02 Name change from MEMM386 to MEMM
29 ; 06/29/86 0.02 Fixed error handler call. Error handler called
30 ; only on attempt to set VM bit in EFLAGS
31 ; 06/30/86 0.02 Jmp to error routine (instead of calling)
32 ; 07/03/86 0.03 Removed logic to enable A20 line watch
33 ; 07/05/86 0.04 JumpReal in R_CODE
34 ; 07/06/86 0.04 Changed assume to DGROUP
35 ; 07/08/86 0.04 added DB67 NOPs to avoid B1 errata
36 ;
37 ;******************************************************************************
38 ;
39 ; Functional Description:
40 ;
41 ; 386 LOADALL is emulated by building a buffer for a
42 ; 386 LOADALL from the client's 386 LOADALL buffer and executing the 386
43 ; LOADALL.
44 ;
45 ; check DR6/DR7 for addresses > 1meg ?
46 ;
47 ;******************************************************************************
48 .lfcond ; list false conditionals
49 .386p
50 page
51 ;******************************************************************************
52 ; P U B L I C D E C L A R A T I O N S
53 ;******************************************************************************
54 ;
55 public EM386ll
56 ;
57 page
58 ;******************************************************************************
59 ; L O C A L C O N S T A N T S
60 ;******************************************************************************
61 ;
62 include loadall.inc
63 include VDMseg.inc
64 include desc.inc
65 include VDMsel.inc
66 include instr386.inc
67 include vm386.inc
68 include oemdep.inc
69
70 FALSE equ 0
71 TRUE equ not FALSE
72
73 ;
74 ; Desc3Copy
75 ; Macro for copying a 386 Loadall descriptor cache entry to a
76 ; 386 Loadall descriptor cache entry.
77 ; ENTRY: DS:ESI pts to client's 386 Loadall descriptor entry
78 ; ES:DI pts to our 386 Loadall descriptor entry
79 ;
80 ; EXIT: DS:ESI pts to byte after client's 386 ll descr entry (next entry).
81 ; ES:DI pts to byte after 386 Loadall descriptor entry (next entry).
82 ; *** The access rights byte in set to DPL 3 for virtual mode ***
83 ;
84 ; USED: EAX
85 ;
86 Desc3Copy MACRO
87 OP32
88 EA32 ; EAX = dword from DS:[ESI]
89 lodsw ; get access rights
90
91 or ah,D_DPL3 ;* set DPL 3 for virtual mode access
92
93 OP32
94 stosw ; store access rights
95
96 OP32
97 EA32 ; EAX = dword from DS:[ESI]
98 lodsw ; 32 bits of Base Addr from 386 entry
99
100 call MapLinear ; map this linear addr by page tables
101
102 OP32
103 stosw ; store Base Addr for 386 entry
104
105 OP32
106 EA32 ; EAX = dword from DS:[ESI]
107 lodsw ; get 32 bits of limit
108
109 OP32
110 stosw ; store 32 bit LIMIT into 386 entry
111 ENDM
112
113 ;
114 ; CurCopy
115 ; Macro for copying a current descriptor cache entry to a
116 ; 386 Loadall descriptor cache entry.
117 ; ENTRY: DS:BX pts to current descriptor
118 ; ES:DI pts to 386 Loadall descriptor entry
119 ;
120 ; EXIT: DS:BX unchanged.
121 ; ES:DI pts to byte after 386 Loadall descriptor entry (next entry).
122 ; *** The access rights byte in set to DPL 3 for virtual mode ***
123 ;
124 ; USED: EAX
125 ;
126 CurCopy MACRO
127 OP32
128 mov ax,[bx+4] ; get AR info
129 or ah,D_DPL3 ;* set DPL 3 for virtual mode access
130 OP32
131 stosw ; store into cache entry
132 mov ah,[bx+7] ; AX = Base[31..16]
133 OP32
134 shl ax,16 ; high word of EAX = Base[31..16]
135 mov ax,[bx+2] ; EAX = Base[31..0]
136 OP32
137 stosw
138 mov al,[bx+6] ; LIMIT[19..16] in low bits of AL
139 and ax,0Fh
140 OP32
141 shl ax,16 ; high word of EAX = LIMIT[31..16]
142 ; NOTE: VDM does not use page
143 ; granularity for limit field !!
144 mov ax,[bx] ; EAX = LIMIT[31..0]
145 OP32
146 stosw ; store into cache for 386 buffer
147 ENDM
148
149 ;******************************************************************************
150 ; L O C A L D A T A A R E A
151 ;******************************************************************************
152
153 _DATA segment
154 extrn ELOff:word ; offset of 386 loadall buffer
155 _DATA ends
156
157
158 R_CODE segment
159 extrn JumpReal:far ; continue client in real mode (rrtrap.asm)
160 R_CODE ends
161
162 _TEXT segment
163 extrn MapLinear:near ; maps linear addresses (maplin.asm)
164 extrn PortTrap:near ; IOBM trap set function (vminit.asm)
165 extrn ErrHndlr:near ; error handler (errhndlr.asm)
166 _TEXT ends
167
168
169 page
170 ;******************************************************************************
171 ; S E G M E N T D E F I N I T I O N
172 ;******************************************************************************
173 ;
174 _TEXT segment
175 ASSUME CS:_TEXT,DS:DGROUP,ES:DGROUP
176
177 ;******************************************************************************
178 ; EM386ll - emulate 386 Loadall
179 ; The basic approach here is to filter the client's loadall buffer into
180 ; a temporary buffer, setting our values for the parameters we don't want
181 ; him to change and then executing the 386 loadall from our buffer.
182 ;
183 ; ENTRY: Protected Mode
184 ; BP points to bottom of client's GPfault stack frame
185 ; ES(in GP frame):EDI points to the client's loadall buffer info
186 ; on stack: ESI,EBX,EBP
187 ;
188 ; EXIT: via Loadall to virtual mode
189 ; The 386 Loadall buffer is emulated with the following
190 ; exceptions:
191 ; The VM bit is set in EFLAGS.
192 ; The TR, IDT descriptor cache, & TSS descriptor cache are
193 ; pointed to the VDM entries.
194 ;
195 ; USED: Not applicable... loadall reloads all registers
196 ;
197 ;******************************************************************************
198 EM386ll proc near
199 ;
200 PUSH_EAX
201 PUSH_ECX
202 PUSH_EDI
203
204 ; Build a descriptor to client's 386 loadall buffer
205
206 mov bx,GDTD_GSEL ; get GDT data alias
207 mov ds,bx ; DS -> GDT
208 mov bx, [bp.VTFOE+VMTF_ES] ; Get VM ES from GP stack frame
209 mov ax,bx
210 shl bx,4 ; BX = low 16 bits of base
211 mov ds:[VM1_GSEL+2],bx ; place in descriptor
212 shr ax, 4 ; AH = high 8 bits of base
213 mov ds:[VM1_GSEL+4],ah ; place in descriptor
214
215 ; Point DS:ESI to start of client's 386 loadall buffer
216 mov bx,VM1_GSEL
217 mov ds,bx
218 OP32
219 mov si,di
220 ASSUME ds:nothing
221
222 ; Point ES:EDI to start of our 386 loadall buffer
223
224 mov ax,VDMD_GSEL
225 mov es,ax
226 OP32
227 xor di,di ; clear EDI
228 mov di,ES:[ELOff] ; ES:EDI pts to our 386 loadall buffer
229 ;
230 cld
231
232 ; Walk through the two buffers in parallel, copying the client's values
233 ; when appropriate
234
235 ;
236 ; CR0 entry
237 ;
238 EA32
239 OP32
240 lodsw ; get client's CR0
241
242 ;(0.02) OP32
243 ;(0.02) test ax,0001h ; TEST EAX,80000001h
244 ;(0.02) dw 8000h ; Q: PG or PE bit set ?
245 ;(0.02) jz CR0_OK ; N: continue
246 ;(0.02) call Em386_Err ; Y: error
247 ;
248 CR0_OK:
249 MOV_ECX_CR0
250 OP32
251 and cx,0011h ; and ECX,80000011h
252 dw 8000h ; save only PG,ET, & PE bits
253 OP32
254 or ax,cx ; or EAX,ECX
255 OP32
256 stosw ; store CR0 for 386 buffer
257 XOR_ECX_ECX ; clear ECX
258 ;
259 ; EFLAGS
260 ;
261 EA32
262 OP32
263 lodsw ; get EFLAGS
264 ;
265 OP32
266 test ax,0000h
267 dw 0002h ;Q: client's VM bit set ?
268 jz EF_OK ; N: continue
269 jmp Em386_Err ; Y: error handler - won't return here
270 EF_OK:
271 and ax,0FFFh ; clear IOPL & NT bits
272 OP32
273 or ax,3000h
274 dw 0002h ; set VM bit and IOPL = 3
275 OP32
276 stosw ; store EFLAGS for 386 buffer
277 ;
278 ; Copy the client's EIP, EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX, DR6 & DR7
279 ; register images from his 386 loadall buffer to our 386 loadall buffer
280 ;
281 mov cx,11 ; copy 11 register contents
282 OP32 ; dwords from DS:[ESI] to ES:[EDI]
283 EA32
284 rep movsw ; copy 11 dwords
285
286 EA32
287 nop ; this avoids a B1 errata
288 ;
289 ; store TR and LDTR
290 ;
291 XOR_EAX_EAX ; clear EAX
292 mov ax,TSS_GSEL ; get current TR for VDM's TSS !!!
293 OP32
294 stosw ; store TR for 386 buffer
295 ;
296 sldt ax ; use current LDT
297 OP32
298 stosw ; store LDTR for 386 buffer
299 ;
300 ; Copy the client's GS, FS, DS, SS, CS, ES register images from
301 ; his 386 loadall buffer to our 386 loadall buffer
302 ;
303 add si,offset ll3_GS - offset ll3_TSSR
304 mov cx,6
305 OP32 ; dwords from DS:[ESI] to ES:[EDI]
306 EA32
307 rep movsw ; copy 6 dwords
308
309 EA32
310 nop ; this avoids a B1 errata
311 ;
312 ; Copy the current TSS, GDT, IDT, LDT descriptors from the GDT table to
313 ; our 386 loadall buffer
314 ;
315 push ds ; save client's buffer selector
316 mov ax,GDTD_GSEL
317 mov ds,ax
318
319 mov cx, 4
320 mov bx, TSS_GSEL
321 push word ptr LDTD_GSEL
322 push word ptr GDTD_GSEL
323 push word ptr IDTD_GSEL
324
325 CopyCur: ; Copy current descriptors
326 CurCopy ; DS:[BX] points to current descriptor
327 pop bx
328 loop CopyCur
329 mov ds, bx ; restore client's buffer selector
330
331 ; DS:SI pts to 386 GS cache entry
332 ;
333 ; Copy the client's GS, FS, DS, SS, CS, ES register cache images from
334 ; his 386 loadall buffer to our 386 loadall buffer
335 ;
336 add si,offset ll3_GScache - offset ll3_TSScache
337 mov cx,6
338 CopyCac: ; ES:DI pts to our 386 buf cache entry
339 Desc3Copy ; store his cache in our 386 buffer
340 loop CopyCac ; DS:SI pts to client's buf cache entry
341
342 ;
343 ; 386 Loadall buffer complete
344 ;
345
346 ;(0.03) push es
347 ;(0.03) mov ax, TSSD_GSEL ; Point ES to TSS for PortTrap
348 ;(0.03) mov es, ax
349 ;(0.03) mov bh, 80h ; set every 1k
350 ;(0.03) mov ax, KbdDataPort
351 ;(0.03) call PortTrap ; set traps on keyboard ports
352 ;(0.03) mov ax, KbdCmdPort ; in case client
353 ;(0.03) call PortTrap ; tries to disable A20
354 ;(0.03) pop es
355 ;(0.03) mov es:[A20watch], YesLLdone ; set A20 watch flag
356
357 HwTabLock ; Hardware lock the high ram
358
359 OP32
360 xor di,di ; XOR EDI,EDI - clear EDI
361 mov di,ES:[ELOff] ; ES:EDI pts to loadall buffer
362 dw LODAL386 ; execute 386 LOADALL
363
364 ASSUME DS:DGROUP
365 ;
366 ;
367 EM386ll endp
368
369 page
370 ;******************************************************************************
371 ; Em386_Err - handle 386 ll emulation error
372 ; This routine is currently called only on attempts to set the
373 ; VM bit via loadall.
374 ;******************************************************************************
375 Em386_Err proc near
376 push ax
377 push bx
378 mov ax, PrivErr
379 mov bx, Err3LL
380 call ErrHndlr
381 pop bx
382 pop bx
383 ;
384 ; continue client in real mode
385 ;
386 POP_EDI ; restore used regs
387 POP_ECX
388 POP_EAX
389 ; stack back to VmFault exit condition
390
391 jmp JumpReal ; "jump" to real mode and continue interrupted
392 ; code.
393
394 Em386_Err endp
395 ;
396 _TEXT ends
397 end