diff options
Diffstat (limited to 'v4.0/src/MEMM/MEMM/EM386LL.ASM')
| -rw-r--r-- | v4.0/src/MEMM/MEMM/EM386LL.ASM | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/v4.0/src/MEMM/MEMM/EM386LL.ASM b/v4.0/src/MEMM/MEMM/EM386LL.ASM new file mode 100644 index 0000000..3408eaa --- /dev/null +++ b/v4.0/src/MEMM/MEMM/EM386LL.ASM | |||
| @@ -0,0 +1,397 @@ | |||
| 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 | ||