Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

emulx86.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 emulx86.c 00008 00009 Abstract: 00010 00011 This module implements all of the x86 opcode handling regardles of which 00012 mode the trap occured in (V86, protected, etc.). It is basically 00013 a combination of instemul.asm and emv86.asm from the .../ke/i386 00014 directory 00015 00016 Author: 00017 00018 Charles Spirakis (intel) 1 Feb 1996 00019 00020 Environment: 00021 00022 Kernel mode only. 00023 00024 Revision History: 00025 00026 00027 --*/ 00028 00029 #include "ki.h" 00030 #include "ia32def.h" 00031 #include "vdmntos.h" 00032 00033 #if DEVL 00034 ULONG ExVdmOpcodeDispatchCounts[MAX_VDM_INDEX]; 00035 ULONG ExVdmSegmentNotPresent; 00036 #endif 00037 00038 extern ULONG KeIA32EFlagsAndMaskV86; 00039 extern ULONG KeIA32EFlagsOrMaskV86; 00040 extern BOOLEAN KeIA32VdmIoplAllowed; 00041 extern ULONG KeIA32VirtualIntExtensions; 00042 00043 #if defined(WX86) && defined(TRY_NTVDM) 00044 // 00045 // These are external functions.... 00046 // 00047 00048 BOOLEAN 00049 KiIA32VdmDispatchIo( 00050 IN ULONG PortNumber, 00051 IN ULONG Size, 00052 IN BOOLEAN Read, 00053 IN UCHAR InstructionSize, 00054 IN PKIA32_FRAME TrapFrame 00055 ); 00056 00057 BOOLEAN 00058 KiIA32VdmDispatchStringIo( 00059 IN ULONG PortNumber, 00060 IN ULONG Size, 00061 IN BOOLEAN Rep, 00062 IN BOOLEAN Read, 00063 IN ULONG Count, 00064 IN ULONG Address, 00065 IN UCHAR InstructionSize, 00066 IN PKIA32_FRAME TrapFrame 00067 ); 00068 00069 00070 // 00071 // Declare non-ke and non-ki function prototypes 00072 // 00073 BOOLEAN 00074 PushInt( 00075 IN ULONG InterruptNumber, 00076 IN OUT PREGINFO Regs 00077 ); 00078 00079 BOOLEAN 00080 PushException( 00081 IN ULONG ExceptionNumber, 00082 IN OUT PREGINFO Regs 00083 ); 00084 00085 BOOLEAN 00086 CsToLinear( 00087 IN OUT PREGINFO Regs, 00088 IN BOOLEAN IsV86 00089 ); 00090 00091 BOOLEAN 00092 SsToLinear( 00093 IN OUT PREGINFO Regs, 00094 IN BOOLEAN IsV86 00095 ); 00096 00097 BOOLEAN 00098 CheckEip( 00099 IN PREGINFO Regs 00100 ); 00101 00102 BOOLEAN 00103 CheckEsp( 00104 IN PREGINFO Regs, 00105 IN ULONG StackNeeded 00106 ); 00107 00108 VOID 00109 GetVirtualBits( 00110 IN OUT PULONG PFlags, 00111 IN PKIA32_FRAME Frame 00112 ); 00113 00114 VOID 00115 SetVirtualBits( 00116 IN ULONG Flags, 00117 IN PREGINFO PRegs 00118 ); 00119 00120 VOID 00121 VdmDispatchIntAck( 00122 IN PKIA32_FRAME Frame 00123 ); 00124 00125 VOID 00126 CheckVdmFlags( 00127 IN OUT PREGINFO Regs 00128 ); 00129 00130 VOID 00131 KeIA32AndOrVdmLock( 00132 IN ULONG AndMask, 00133 IN ULONG OrMask 00134 ); 00135 00136 BOOLEAN 00137 KeIA32UnscrambleLdtEntry( 00138 IN ULONG Selector, 00139 OUT PKXDESCRIPTOR XDescriptor 00140 ); 00141 00142 ULONGLONG 00143 KeIA32Unscramble( 00144 IN PLDT_ENTRY Descriptor 00145 ); 00146 00147 NTSTATUS 00148 PspQueryDescriptorThread ( 00149 PETHREAD Thread, 00150 PVOID ThreadInformation, 00151 ULONG ThreadInformationLength, 00152 PULONG ReturnLength 00153 ); 00154 00155 00156 00157 00158 BOOLEAN 00159 KiIA32DispatchOpcode( 00160 IN PKIA32_FRAME Frame 00161 ) 00162 00163 /*++ 00164 00165 Routine Description: 00166 00167 This routine dispatches to the opcode of the specific emulation routine. 00168 based on the first byte of the opcode. It is a combination of the 00169 original x86 emulation routines written in assembly (i386/instemul.asm 00170 and i386/emv86.asm). 00171 00172 Arguments: 00173 00174 Frame - pointer to the ia32 trap frame. 00175 00176 Return Value: 00177 00178 Returns true if the opcode was handled, otherwise false 00179 00180 --*/ 00181 00182 { 00183 REGINFO Regs; 00184 ULONG IOPort; 00185 ULONG IOCount; 00186 ULONG IOAddress; 00187 ULONG flags; 00188 KXDESCRIPTOR NewXDescriptor; 00189 00190 // 00191 // Temporary variables that are needed to access memory in 00192 // different sizes... 00193 // 00194 PULONG longPtr; 00195 PUSHORT shortPtr; 00196 PUCHAR charPtr; 00197 00198 // 00199 // Set up the valules that are always needed 00200 // 00201 Regs.RiInstLength = 1; 00202 Regs.RiPrefixFlags = 0; 00203 Regs.RiTrapFrame = Frame; 00204 Regs.RiSegCs = Frame->SegCs; 00205 Regs.RiEip = Frame->Eip; 00206 00207 // 00208 // Convert and verify the linear address is legal 00209 // 00210 if (! CsToLinear(&Regs, VM86USER(Frame))) { 00211 return FALSE; 00212 } 00213 00214 // 00215 // The ASM files used an arbitrary maximum length of 128 prefixes... 00216 // This constant comes from MI.INC (but is not 128) 00217 // 00218 while (Regs.RiInstLength <= MAX_INSTRUCTION_LENGTH) { 00219 00220 // Should there be a Probe or a try/except block? 00221 Regs.RiOpcode = *Regs.RiLinearAddr; 00222 00223 switch(Regs.RiOpcode) { 00224 case 0x0f: 00225 // Handle the 0x0f series of opcodes 00226 #if DEVL 00227 ExVdmOpcodeDispatchCounts[VDM_INDEX_0F]++; 00228 #endif 00229 #if VDMDBG 00230 DbgPrintf("Saw 0x0f opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00231 #endif 00232 return(VdmOpcode0F(&Regs)); 00233 00234 case 0x26: 00235 #if DEVL 00236 ExVdmOpcodeDispatchCounts[VDM_INDEX_ESPrefix]++; 00237 #endif 00238 #if VDMDBG 00239 DbgPrintf("Saw ES Prefix opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00240 #endif 00241 Regs.RiPrefixFlags |= PREFIX_ES; 00242 break; 00243 00244 case 0x2e: 00245 #if DEVL 00246 ExVdmOpcodeDispatchCounts[VDM_INDEX_CSPrefix]++; 00247 #endif 00248 #if VDMDBG 00249 DbgPrintf("Saw CS Prefix opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00250 #endif 00251 Regs.RiPrefixFlags |= PREFIX_CS; 00252 break; 00253 00254 case 0x36: 00255 #if DEVL 00256 ExVdmOpcodeDispatchCounts[VDM_INDEX_SSPrefix]++; 00257 #endif 00258 #if VDMDBG 00259 DbgPrintf("Saw SS Prefix opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00260 #endif 00261 Regs.RiPrefixFlags |= PREFIX_SS; 00262 break; 00263 00264 case 0x3e: 00265 #if DEVL 00266 ExVdmOpcodeDispatchCounts[VDM_INDEX_DSPrefix]++; 00267 #endif 00268 #if VDMDBG 00269 DbgPrintf("Saw DS Prefix opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00270 #endif 00271 Regs.RiPrefixFlags |= PREFIX_DS; 00272 break; 00273 00274 case 0x64: 00275 #if DEVL 00276 ExVdmOpcodeDispatchCounts[VDM_INDEX_FSPrefix]++; 00277 #endif 00278 #if VDMDBG 00279 DbgPrintf("Saw FS Prefix opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00280 #endif 00281 Regs.RiPrefixFlags |= PREFIX_FS; 00282 break; 00283 00284 case 0x65: 00285 #if DEVL 00286 ExVdmOpcodeDispatchCounts[VDM_INDEX_GSPrefix]++; 00287 #endif 00288 #if VDMDBG 00289 DbgPrintf("Saw GS Prefix opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00290 #endif 00291 Regs.RiPrefixFlags |= PREFIX_GS; 00292 break; 00293 00294 case 0x66: 00295 #if DEVL 00296 ExVdmOpcodeDispatchCounts[VDM_INDEX_OPER32Prefix]++; 00297 #endif 00298 #if VDMDBG 00299 DbgPrintf("Saw Operand 32 Prefix opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00300 #endif 00301 Regs.RiPrefixFlags |= PREFIX_OPER32; 00302 break; 00303 00304 case 0x67: 00305 #if DEVL 00306 ExVdmOpcodeDispatchCounts[VDM_INDEX_ADDR32Prefix]++; 00307 #endif 00308 #if VDMDBG 00309 DbgPrintf("Saw Address 32 Prefix opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00310 #endif 00311 Regs.RiPrefixFlags |= PREFIX_ADDR32; 00312 break; 00313 00314 // 00315 // The next four instructions (INSB, INSW, OUTSB, and OUTSW) 00316 // could be optimized to pass fewer parameters to 00317 // KiIA32VdmDispatchStringIo(). But, in an attempt to change as 00318 // little as possible, this will be left alone for the moment. 00319 // Really only need to pass &regs structure, size info (byte/word) 00320 // and read/write info. All else is contained in &Regs... 00321 // 00322 case 0x6c: 00323 // The INSB instruction 00324 #if DEVL 00325 ExVdmOpcodeDispatchCounts[VDM_INDEX_INSB]++; 00326 #endif 00327 #if VDMDBG 00328 DbgPrintf("Saw INSB opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00329 #endif 00330 IOAddress = ( Frame->SegEs << 16 ) + Frame->Edi; 00331 00332 if (Regs.RiPrefixFlags & PREFIX_REP) { 00333 IOCount = Frame->Ecx; 00334 } 00335 else { 00336 IOCount = 1; 00337 } 00338 IOPort = Frame->Edx; 00339 00340 return(KiIA32VdmDispatchStringIo(IOPort, 1, Regs.RiPrefixFlags & PREFIX_REP, TRUE, IOCount, IOAddress, Regs.RiInstLength, Frame)); 00341 00342 case 0x6d: 00343 // The INSW instruction 00344 #if DEVL 00345 ExVdmOpcodeDispatchCounts[VDM_INDEX_INSW]++; 00346 #endif 00347 #if VDMDBG 00348 DbgPrintf("Saw INSW opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00349 #endif 00350 IOAddress = ( Frame->SegEs << 16 ) + Frame->Edi; 00351 00352 if (Regs.RiPrefixFlags & PREFIX_REP) { 00353 IOCount = Frame->Ecx; 00354 } 00355 else { 00356 IOCount = 1; 00357 } 00358 IOPort = Frame->Edx; 00359 00360 return(KiIA32VdmDispatchStringIo(IOPort, 2, Regs.RiPrefixFlags & PREFIX_REP, TRUE, IOCount, IOAddress, Regs.RiInstLength, Frame)); 00361 00362 case 0x6e: 00363 // The OUTSB instruction 00364 #if DEVL 00365 ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTSB]++; 00366 #endif 00367 #if VDMDBG 00368 DbgPrintf("Saw OUTSB opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00369 #endif 00370 IOAddress = ( Frame->SegEs << 16 ) + Frame->Edi; 00371 00372 if (Regs.RiPrefixFlags & PREFIX_REP) { 00373 IOCount = Frame->Ecx; 00374 } 00375 else { 00376 IOCount = 1; 00377 } 00378 IOPort = Frame->Edx; 00379 00380 return(KiIA32VdmDispatchStringIo(IOPort, 1, Regs.RiPrefixFlags & PREFIX_REP, FALSE, IOCount, IOAddress, Regs.RiInstLength, Frame)); 00381 00382 case 0x6f: 00383 // The OUTSW instruction 00384 #if DEVL 00385 ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTSW]++; 00386 #endif 00387 #if VDMDBG 00388 DbgPrintf("Saw OUTSW opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00389 #endif 00390 IOAddress = ( Frame->SegEs << 16 ) + Frame->Edi; 00391 00392 if (Regs.RiPrefixFlags & PREFIX_REP) { 00393 IOCount = Frame->Ecx; 00394 } 00395 else { 00396 IOCount = 1; 00397 } 00398 IOPort = Frame->Edx; 00399 00400 return(KiIA32VdmDispatchStringIo(IOPort, 2, Regs.RiPrefixFlags & PREFIX_REP, FALSE, IOCount, IOAddress, Regs.RiInstLength, Frame)); 00401 00402 case 0x9b: 00403 case 0x0d8: 00404 case 0x0d9: 00405 case 0x0da: 00406 case 0x0db: 00407 case 0x0dc: 00408 case 0x0dd: 00409 case 0x0de: 00410 case 0x0df: 00411 #if DEVL 00412 ExVdmOpcodeDispatchCounts[VDM_INDEX_NPX]++; 00413 #endif 00414 #if VDMDBG 00415 DbgPrintf("Saw NPX opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00416 #endif 00417 break; 00418 00419 case 0x09c: 00420 #if DEVL 00421 ExVdmOpcodeDispatchCounts[VDM_INDEX_PUSHF]++; 00422 #endif 00423 #if VDMDBG 00424 DbgPrintf("Saw PUSHF opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00425 #endif 00426 // This one should only happen in V86 mode 00427 if (! VM86USER(Frame)) { 00428 return FALSE; 00429 } 00430 00431 flags = Frame->EFlags & (~EFLAGS_INTERRUPT_MASK); 00432 flags |= EFLAGS_IOPL_MASK; 00433 flags |= (*VdmFixedStateLinear & (VDM_VIRTUAL_INTERRUPTS | EFLAGS_ALIGN_CHECK | EFLAGS_NT_MASK)); 00434 00435 if (Regs.RiPrefixFlags & PREFIX_OPER32) { 00436 Frame->HardwareEsp = (Frame->HardwareEsp - 4) & 0xffff; 00437 longPtr = (PULONG) (Frame->SegSs << 4) + Frame->HardwareEsp; 00438 *longPtr = flags; 00439 } 00440 else { 00441 Frame->HardwareEsp = (Frame->HardwareEsp - 2) & 0xffff; 00442 shortPtr = (PUSHORT) (Frame->SegSs << 4) + Frame->HardwareEsp; 00443 *shortPtr = flags & 0xffff; 00444 } 00445 00446 Frame->Eip += Regs.RiInstLength; 00447 00448 return TRUE; 00449 00450 case 0x9d: 00451 #if DEVL 00452 ExVdmOpcodeDispatchCounts[VDM_INDEX_POPF]++; 00453 #endif 00454 #if VDMDBG 00455 DbgPrintf("Saw POPF opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00456 #endif 00457 // This one should only happen in V86 mode 00458 if (! VM86USER(Frame)) { 00459 return FALSE; 00460 } 00461 00462 if (Regs.RiPrefixFlags & PREFIX_OPER32) { 00463 longPtr = (PULONG) ((Frame->SegSs << 4) + Frame->HardwareEsp); 00464 flags = *longPtr; 00465 Frame->HardwareEsp = (Frame->HardwareEsp + 4) & 0xffff; 00466 } 00467 else { 00468 shortPtr = (PUSHORT) ((Frame->SegSs << 4) + Frame->HardwareEsp); 00469 flags = *shortPtr; 00470 Frame->HardwareEsp = (Frame->HardwareEsp + 2) & 0xffff; 00471 } 00472 00473 flags &= ~EFLAGS_IOPL_MASK; 00474 00475 KeIA32AndOrVdmLock(~(EFLAGS_INTERRUPT_MASK | EFLAGS_ALIGN_CHECK | EFLAGS_NT_MASK), (flags & (EFLAGS_INTERRUPT_MASK | EFLAGS_ALIGN_CHECK | EFLAGS_NT_MASK))); 00476 00477 flags &= ~EFLAGS_NT_MASK; 00478 00479 // 00480 // Original x86 code checked for virtual extensions.. 00481 // Still being decided if these are worth the trouble... 00482 // 00483 if (KeIA32VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) { 00484 flags |= EFLAGS_VIF; 00485 if (! (flags & EFLAGS_INTERRUPT_MASK)) { 00486 flags &= ~EFLAGS_VIF; 00487 } 00488 } 00489 flags |= (EFLAGS_INTERRUPT_MASK | EFLAGS_V86_MASK); 00490 Frame->EFlags = flags; 00491 00492 Frame->Eip += Regs.RiInstLength; 00493 00494 return TRUE; 00495 00496 case 0x0cd: 00497 #if DEVL 00498 ExVdmOpcodeDispatchCounts[VDM_INDEX_INTnn]++; 00499 #endif 00500 #if VDMDBG 00501 DbgPrintf("Saw INTnn opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00502 #endif 00503 if (VM86USER(Frame)) { 00504 // 00505 // V86 mode int XX 00506 // 00507 00508 // 00509 // Two EFLAGS to handle - one put in the trap frame 00510 // and one that is pushed on the stack... First handle 00511 // the one pushed on the stack 00512 // 00513 00514 Frame->HardwareEsp = (Frame->HardwareEsp - 2) & 0xffff; 00515 shortPtr = (PUSHORT) ((Frame->SegSs << 4) + Frame->HardwareEsp); 00516 flags = Frame->EFlags; 00517 00518 if (! KeIA32VdmIoplAllowed) { 00519 flags = (flags & ~EFLAGS_INTERRUPT_MASK) | (*VdmFixedStateLinear & (VDM_INTERRUPT_PENDING | EFLAGS_ALIGN_CHECK)); 00520 } 00521 00522 flags |= EFLAGS_IOPL_MASK; 00523 *shortPtr = flags; 00524 00525 // 00526 // Now handle the one on the trap frame... 00527 // 00528 flags = Frame->EFlags; 00529 00530 if (KeIA32VdmIoplAllowed) { 00531 flags &= ~EFLAGS_INTERRUPT_MASK; 00532 } 00533 else { 00534 KeIA32AndOrVdmLock(~VDM_VIRTUAL_INTERRUPTS, 0); 00535 flags |= EFLAGS_INTERRUPT_MASK; 00536 } 00537 00538 flags &= ~(EFLAGS_NT_MASK | EFLAGS_TF_MASK); 00539 Frame->EFlags = flags; 00540 00541 // Now push CS on the stack 00542 Frame->HardwareEsp = (Frame->HardwareEsp - 2) & 0xffff; 00543 shortPtr = (PUSHORT) ((Frame->SegSs << 4) + Frame->HardwareEsp); 00544 *shortPtr = Frame->SegCs; 00545 00546 // And push IP on the stack 00547 Frame->HardwareEsp = (Frame->HardwareEsp - 2) & 0xffff; 00548 shortPtr = (PUSHORT) ((Frame->SegSs << 4) + Frame->HardwareEsp); 00549 *shortPtr = Frame->Eip; 00550 00551 // 00552 // get the interrupt number and the address in memeory 00553 // that it points to... 00554 // 00555 Regs.RiLinearAddr++; 00556 longPtr = (PULONG) (*(Regs.RiLinearAddr) * 4); 00557 00558 // 00559 // And set up the proper CS and IP based on the int number 00560 // from above... 00561 // 00562 Frame->Eip = *longPtr & 0xffff; 00563 Frame->SegCs = *longPtr >> 16; 00564 } 00565 else { 00566 // 00567 // protected mode intXX 00568 // 00569 00570 // 00571 // Get the eflags 00572 // 00573 flags = Frame->EFlags; 00574 GetVirtualBits(&flags, Frame); 00575 Regs.RiEFlags = flags; 00576 00577 // 00578 // And get the stack 00579 // 00580 Regs.RiSegSs = Frame->SegSs; 00581 Regs.RiEsp = Frame->HardwareEsp; 00582 if (! SsToLinear(&Regs, VM86USER(Frame))) { 00583 return FALSE; 00584 } 00585 00586 // 00587 // Make sure that the nn part of INTnn 00588 // can be accessed legitimately 00589 // 00590 Regs.RiEip++; 00591 Regs.RiLinearAddr++; 00592 if (! CheckEip(&Regs)) { 00593 return FALSE; 00594 } 00595 00596 // 00597 // Point to the next instruction after the INTnn 00598 // 00599 Regs.RiEip++; 00600 Regs.RiLinearAddr++; 00601 00602 00603 // 00604 // And put the right things on the stack... 00605 // 00606 if (! PushInt(*(Regs.RiLinearAddr - 1), &Regs)) { 00607 return FALSE; 00608 } 00609 00610 // 00611 // If all went well, update the trap frame 00612 // 00613 // QUESTION 00614 if (! KeIA32UnscrambleLdtEntry(Regs.RiSegCs, &NewXDescriptor)) { 00615 return FALSE; 00616 } 00617 00618 Frame->HardwareEsp = Regs.RiEsp; 00619 Frame->EFlags = Regs.RiEFlags; 00620 Frame->SegCs = Regs.RiSegCs; 00621 Frame->Eip = Regs.RiEip; 00622 } 00623 00624 return TRUE; 00625 00626 case 0x0ce: 00627 #if DEVL 00628 ExVdmOpcodeDispatchCounts[VDM_INDEX_INTO]++; 00629 #endif 00630 #if VDMDBG 00631 DbgPrintf("Saw INTO opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00632 #endif 00633 00634 // 00635 // Both v86 and protected mode don't want to 00636 // deal with into... 00637 // 00638 return FALSE; 00639 00640 break; 00641 00642 case 0x0cf: 00643 #if DEVL 00644 ExVdmOpcodeDispatchCounts[VDM_INDEX_IRET]++; 00645 #endif 00646 #if VDMDBG 00647 DbgPrintf("Saw IRET opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00648 #endif 00649 // 00650 // This one should only happen in V86 mode 00651 // 00652 00653 if (! VM86USER(Frame)) { 00654 return FALSE; 00655 } 00656 00657 00658 // 00659 // update the Trap frame with the iret values (CS, IP, flags) 00660 // based on size of iret (16 vs. 32 bits) 00661 // 00662 if (Regs.RiPrefixFlags & PREFIX_OPER32) { 00663 longPtr = (PULONG) ((Frame->SegSs << 4) + Frame->HardwareEsp); 00664 00665 Frame->Eip = *longPtr++; 00666 Frame->SegCs = *longPtr++; 00667 flags = *longPtr; 00668 00669 Frame->HardwareEsp = (Frame->HardwareEsp + 12) & 0xffff; 00670 } 00671 else { 00672 shortPtr = (PUSHORT) ((Frame->SegSs << 4) + Frame->HardwareEsp); 00673 00674 Frame->Eip = *shortPtr++ & 0xffff; 00675 Frame->SegCs = *shortPtr++ & 0xffff; 00676 flags = *shortPtr & 0xffff; 00677 00678 Frame->HardwareEsp = (Frame->HardwareEsp + 6) & 0xffff; 00679 } 00680 00681 flags &= ~(EFLAGS_IOPL_MASK | EFLAGS_NT_MASK); 00682 00683 KeIA32AndOrVdmLock(~VDM_VIRTUAL_INTERRUPTS, flags & EFLAGS_INTERRUPT_MASK ); 00684 00685 // 00686 // Original x86 code checked for virtual extensions.. 00687 // We haven't decided if they are worth the effort yet... 00688 // 00689 if (KeIA32VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) { 00690 if (flags & EFLAGS_INTERRUPT_MASK) { 00691 flags |= EFLAGS_VIF; 00692 } 00693 else { 00694 flags &= ~EFLAGS_VIF; 00695 } 00696 } 00697 00698 flags |= (EFLAGS_INTERRUPT_MASK | EFLAGS_V86_MASK); 00699 Frame->EFlags = flags; 00700 00701 // Before we return, check for a BOP or a virtual interrupt 00702 shortPtr = (Frame->SegCs << 4) + Frame->Eip; 00703 00704 if ((*shortPtr & 0xffff) == BOP_OPCODE) { 00705 VdmDispatchBop(Frame); 00706 } 00707 else if ((*VdmFixedStateLinear & VDM_INTERRUPT_PENDING) && 00708 (*VdmFixedStateLinear & VDM_VIRTUAL_INTERRUPTS)) { 00709 VdmDispatchIntAck(Frame); 00710 } 00711 00712 return TRUE; 00713 00714 case 0x0e4: 00715 #if DEVL 00716 ExVdmOpcodeDispatchCounts[VDM_INDEX_INBimm]++; 00717 #endif 00718 #if VDMDBG 00719 DbgPrintf("Saw INB immediate opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00720 #endif 00721 // The immediate byte means the instruction is one byte longer 00722 Regs.RiInstLength++; 00723 00724 // Check that the immediate byte address is legit 00725 charPtr = Regs.RiLinearAddr + 1; 00726 if ((charPtr - Regs.RiCsBase) > Regs.RiCsLimit) { 00727 return FALSE; 00728 } 00729 00730 IOPort = *charPtr; 00731 00732 return(KiIA32VdmDispatchIo(IOPort, 1, TRUE, Regs.RiInstLength, Frame)); 00733 00734 case 0x0e5: 00735 #if DEVL 00736 ExVdmOpcodeDispatchCounts[VDM_INDEX_INWimm]++; 00737 #endif 00738 #if VDMDBG 00739 DbgPrintf("Saw INW immediate opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00740 #endif 00741 // The immediate byte means the instruction is one byte longer 00742 Regs.RiInstLength++; 00743 00744 // Check that the immediate byte address is legit 00745 charPtr = Regs.RiLinearAddr + 1; 00746 if ((charPtr - Regs.RiCsBase) > Regs.RiCsLimit) { 00747 return FALSE; 00748 } 00749 00750 IOPort = *charPtr; 00751 00752 return(KiIA32VdmDispatchIo(IOPort, 2, TRUE, Regs.RiInstLength, Frame)); 00753 case 0x0e6: 00754 #if DEVL 00755 ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTBimm]++; 00756 #endif 00757 #if VDMDBG 00758 DbgPrintf("Saw OUTB immediate opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00759 #endif 00760 // The immediate byte means the instruction is one byte longer 00761 Regs.RiInstLength++; 00762 00763 // Check that the immediate byte address is legit 00764 charPtr = Regs.RiLinearAddr + 1; 00765 if ((charPtr - Regs.RiCsBase) > Regs.RiCsLimit) { 00766 return FALSE; 00767 } 00768 00769 IOPort = *charPtr; 00770 00771 return(KiIA32VdmDispatchIo(IOPort, 1, FALSE, Regs.RiInstLength, Frame)); 00772 case 0x0e7: 00773 #if DEVL 00774 ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTWimm]++; 00775 #endif 00776 #if VDMDBG 00777 DbgPrintf("Saw OUTW immediate opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00778 #endif 00779 // The immediate byte means the instruction is one byte longer 00780 Regs.RiInstLength++; 00781 00782 // Check that the immediate byte address is legit 00783 charPtr = Regs.RiLinearAddr + 1; 00784 if ((charPtr - Regs.RiCsBase) > Regs.RiCsLimit) { 00785 return FALSE; 00786 } 00787 00788 IOPort = *charPtr; 00789 00790 return(KiIA32VdmDispatchIo(IOPort, 2, FALSE, Regs.RiInstLength, Frame)); 00791 00792 case 0x0ec: 00793 #if DEVL 00794 ExVdmOpcodeDispatchCounts[VDM_INDEX_INB]++; 00795 #endif 00796 #if VDMDBG 00797 DbgPrintf("Saw INB opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00798 #endif 00799 IOPort = Frame->Edx; 00800 00801 // 00802 // In V86 mode, handle Japan support for non PC/AT compatible machines 00803 // 00804 #ifdef NON_PCAT 00805 if (VM86USER(Frame)) { 00806 if (KeIA32MachineType & MACHINE_TYPE_MASK) { 00807 return(KiIA32VdmDispatchIo(IOPort, 1, TRUE, Regs.RiInstLength, Frame)); 00808 } 00809 } 00810 #endif 00811 // Check for printer status request... 00812 switch (IOPort) { 00813 case 0x03bd: 00814 case 0x0379: 00815 case 0x0279: 00816 if (VdmPrinterStatus(IOPort, Regs.RiInstLength, Frame)) { 00817 return TRUE; 00818 } 00819 // Fall through 00820 default: 00821 return(KiIA32VdmDispatchIo(IOPort, 1, TRUE, Regs.RiInstLength, Frame)); 00822 } 00823 // Should never get here... 00824 return FALSE; 00825 00826 case 0x0ed: 00827 #if DEVL 00828 ExVdmOpcodeDispatchCounts[VDM_INDEX_INW]++; 00829 #endif 00830 #if VDMDBG 00831 DbgPrintf("Saw INW opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00832 #endif 00833 IOPort = Frame->Edx; 00834 return(KiIA32VdmDispatchIo(IOPort, 2, TRUE, Regs.RiInstLength, Frame)); 00835 00836 case 0x0ee: 00837 #if DEVL 00838 ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTB]++; 00839 #endif 00840 #if VDMDBG 00841 DbgPrintf("Saw OUTB opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00842 #endif 00843 IOPort = Frame->Edx; 00844 00845 // Check for printer status request... 00846 switch (IOPort) { 00847 case 0x03bc: 00848 case 0x0378: 00849 case 0x0278: 00850 if (VdmPrinterWriteData(IOPort, Regs.RiInstLength, Frame)) { 00851 return TRUE; 00852 } 00853 // 00854 // Fall through to dispatch if VdmPrinterWriteData() fails 00855 // 00856 default: 00857 return(KiIA32VdmDispatchIo(IOPort, 1, FALSE, Regs.RiInstLength, Frame)); 00858 } 00859 // Should never get here... 00860 return FALSE; 00861 00862 case 0x0ef: 00863 #if DEVL 00864 ExVdmOpcodeDispatchCounts[VDM_INDEX_OUTW]++; 00865 #endif 00866 #if VDMDBG 00867 DbgPrintf("Saw OUTW opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00868 #endif 00869 IOPort = Frame->Edx; 00870 return(KiIA32VdmDispatchIo(IOPort, 2, FALSE, Regs.RiInstLength, Frame)); 00871 00872 case 0x0f0: 00873 #if DEVL 00874 ExVdmOpcodeDispatchCounts[VDM_INDEX_LOCKPrefix]++; 00875 #endif 00876 #if VDMDBG 00877 DbgPrintf("Saw LOCK Prefix (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00878 #endif 00879 Regs.RiPrefixFlags |= PREFIX_LOCK; 00880 break; 00881 00882 case 0x0f2: 00883 #if DEVL 00884 ExVdmOpcodeDispatchCounts[VDM_INDEX_REPNEPrefix]++; 00885 #endif 00886 #if VDMDBG 00887 DbgPrintf("Saw REPNE Prefix (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00888 #endif 00889 Regs.RiPrefixFlags |= PREFIX_REPNE; 00890 break; 00891 00892 case 0x0f3: 00893 #if DEVL 00894 ExVdmOpcodeDispatchCounts[VDM_INDEX_REPPrefix]++; 00895 #endif 00896 #if VDMDBG 00897 DbgPrintf("Saw REP Prefix (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00898 #endif 00899 Regs.RiPrefixFlags |= PREFIX_REP; 00900 break; 00901 00902 case 0x0f4: 00903 #if DEVL 00904 ExVdmOpcodeDispatchCounts[VDM_INDEX_HLT]++; 00905 #endif 00906 #if VDMDBG 00907 DbgPrintf("Saw HLT opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00908 #endif 00909 // This one should only happen in V86 mode 00910 00911 if (! VM86USER(Frame)) { 00912 return FALSE; 00913 } 00914 00915 // We are in V86 mode... 00916 00917 // 00918 // Skip over the instruction 00919 // 00920 00921 Frame->Eip = (Frame->Eip + Regs.RiInstLength) & 0xffff; 00922 00923 return TRUE; 00924 00925 break; 00926 00927 case 0x0fa: 00928 #if DEVL 00929 ExVdmOpcodeDispatchCounts[VDM_INDEX_CLI]++; 00930 #endif 00931 #if VDMDBG 00932 DbgPrintf("Saw CLI opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00933 #endif 00934 if (! VM86USER(Frame)) { 00935 flags = Frame->EFlags & ~EFLAGS_INTERRUPT_MASK; 00936 SetVirtualBits(flags, &Regs); 00937 } 00938 else { 00939 KeIA32AndOrVdmLock(~VDM_VIRTUAL_INTERRUPTS, 0); 00940 } 00941 00942 // Skip over the instruction 00943 Frame->Eip += Regs.RiInstLength; 00944 00945 return TRUE; 00946 00947 case 0x0fb: 00948 #if DEVL 00949 ExVdmOpcodeDispatchCounts[VDM_INDEX_STI]++; 00950 #endif 00951 #if VDMDBG 00952 DbgPrintf("Saw STI opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00953 #endif 00954 if (! VM86USER(Frame)) { 00955 flags = Frame->EFlags | EFLAGS_INTERRUPT_MASK; 00956 SetVirtualBits(flags, &Regs); 00957 } 00958 else { 00959 // Original x86 code checked for virtual extensions.. 00960 // We haven't decided if they're worth it or not... 00961 if (KeIA32VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) { 00962 Frame->EFlags |= EFLAGS_VIF; 00963 } 00964 00965 KeIA32AndOrVdmLock(0xffffffff, EFLAGS_INTERRUPT_MASK); 00966 } 00967 00968 // Skip over the instruction 00969 Frame->Eip += Regs.RiInstLength; 00970 00971 // Interrupts are now "enabled", so handle any 00972 // that are pending 00973 if (*VdmFixedStateLinear & VDM_INTERRUPT_PENDING) { 00974 VdmDispatchIntAck(Frame); 00975 } 00976 return TRUE; 00977 00978 default: 00979 // Opcode Invalid 00980 #if VDMDBG 00981 DbgPrintf("Saw unexpected opcode (0x%02x) at linear address 0x%08lx\n", (int) Regs.RiOpcode, (long) Regs.RiLinearAddr); 00982 #endif 00983 return FALSE; 00984 00985 } 00986 00987 // If we get here, it was a prefix instruction 00988 00989 Regs.RiLinearAddr++; 00990 Regs.RiInstLength++; 00991 } 00992 00993 // Prefix was too long, so allow a GP fault 00994 00995 return (FALSE); 00996 } 00997 00998 00999 VOID 01000 VdmDispatchIntAck( 01001 IN PKIA32_FRAME Frame 01002 ) 01003 01004 /*++ 01005 01006 Routine Description: 01007 01008 Pushes stack arguments for VdmDispatchInterrupts 01009 and invokes VdmDispatchInterrupts 01010 01011 Expects VDM_INTERRUPT_PENDING, and VDM_VIRTUAL_INTERRUPTS 01012 01013 Arguments: 01014 01015 Frame - pointer to the ia32 trap frame 01016 01017 Returns: 01018 01019 nothing 01020 01021 --*/ 01022 { 01023 PVDM_TIB VdmTib; 01024 01025 VdmTib = (PsGetCurrentThread()->Tcb.Teb)->Vdm; 01026 01027 if (*VdmFixedStateLinear & VDM_INT_HARDWARE) { 01028 // Dispatch interrupt directly from kernel 01029 01030 VdmDispatchInterrupts(Frame, VdmTib); 01031 } 01032 else { 01033 // Dispatch interrupt via monitor 01034 01035 VdmTib->EventInfo.Event = VdmIntAck; 01036 VdmTib->EventInfo.Size = 0; 01037 VdmTib->EventInfo.IntAckInfo = 0; 01038 VdmEndExecution(Frame, VdmTib); 01039 } 01040 } 01041 01042 // 01043 // These are only used by the GetVirtualBits() routine 01044 // 01045 #define _VDM_EXTOFF_FUNC(x) (x = (x & ~EFLAGS_INTERRUPT_MASK) | (*VdmFixedStateLinear & (VDM_VIRTUAL_INTERRUPTS | EFLAGS_ALIGN_CHECK)) | EFLAGS_IOPL_MASK) 01046 #define _VDM_EXTON_FUNC(x) (x = (x & ~EFLAGS_INTERRUPT_MASK) | (*VdmFixedStateLinear & (VDM_VIRTUAL_INTERRUPTS | EFLAGS_ALIGN_CHECK)) | EFLAGS_IOPL_MASK) 01047 #define _VDM_IOPL_FUNC(x) (x = (x & ~EFLAGS_ALIGN_CHECK) | (*VdmFixedStateLinear & EFLAGS_ALIGN_CHECK) | EFLAGS_IOPL_MASK) 01048 01049 01050 VOID 01051 GetVirtualBits( 01052 IN OUT PULONG PFlags, 01053 IN PKIA32_FRAME Frame 01054 ) 01055 01056 /*++ 01057 01058 Routine Description: 01059 01060 This routine correctly gets the VDMs virtual interrupt flag 01061 and puts it into an EFlags image 01062 01063 Arguments: 01064 01065 PFlags - pointer to the Eflags 01066 Frame - pointer to the ia32 trap frame 01067 01068 Returns: 01069 01070 nothing 01071 01072 --*/ 01073 { 01074 // We need to decide if we want this or not... 01075 if (KeIA32VdmIoplAllowed) { 01076 if (*PFlags & EFLAGS_V86_MASK) { 01077 _VDM_IOPL_FUNC(*PFlags); 01078 } 01079 else { 01080 _VDM_EXTOFF_FUNC(*PFlags); 01081 } 01082 } 01083 else { 01084 01085 // 01086 // A check was made for virtual extensions. We don't know if 01087 // we want to implement those extensions or not, so... 01088 // 01089 01090 if (KeIA32VirtualIntExtensions & (V86_VIRTUAL_INT_EXTENSIONS | PM_VIRTUAL_INT_EXTENSIONS)) { 01091 if (*PFlags & EFLAGS_V86_MASK) { 01092 if (KeIA32VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) { 01093 _VDM_EXTON_FUNC(*PFlags); 01094 } 01095 else { 01096 _VDM_EXTOFF_FUNC(*PFlags); 01097 } 01098 } 01099 else { 01100 if (KeIA32VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) { 01101 _VDM_EXTON_FUNC(*PFlags); 01102 } 01103 else { 01104 _VDM_EXTOFF_FUNC(*PFlags); 01105 } 01106 } 01107 } 01108 else { 01109 _VDM_EXTOFF_FUNC(*PFlags); 01110 } 01111 } 01112 } 01113 01114 VOID 01115 SetVirtualBits( 01116 IN ULONG Flags, 01117 IN PREGINFO PRegs 01118 ) 01119 01120 /*++ 01121 01122 Routine Description: 01123 01124 This routine correctly sets the VDMs virtual interrupt flag 01125 01126 Arguments: 01127 01128 Flags - the EFlags value 01129 PRegs - pointer to instruction information (prefix, inst length, etc.) 01130 01131 Returns: 01132 01133 nothing 01134 01135 --*/ 01136 { 01137 KeIA32AndOrVdmLock(~VDM_VIRTUAL_INTERRUPTS, Flags & EFLAGS_INTERRUPT_MASK); 01138 01139 // 01140 // There was a lot of code here to check for Virtual Extensions... 01141 // Depending on if they existed or not, a value in eax was changed 01142 // (in ../i386/instemul.asm - at label svb50: ) but it is never used 01143 // (not even as a return value...) 01144 // So, rather than repeat all that silly code that doesn't do anything, 01145 // I only show the code that is actually executed... Enjoy... 01146 // 01147 01148 #if 0 01149 if (KeIA32VirtualIntExtensions & (V86_VIRTUAL_INT_EXTENSIONS | PM_VIRTUAL_INT_EXTENSIONS)) { 01150 if (Flags & EFLAGS_V86_MASK) { 01151 if (KeIA32VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) { 01152 } 01153 else { 01154 } 01155 } 01156 else { 01157 if (KeIA32VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) { 01158 } 01159 else { 01160 } 01161 } 01162 } 01163 else { 01164 } 01165 #endif 01166 01167 if (PRegs->RiPrefixFlags & PREFIX_OPER32) { 01168 KeIA32AndOrVdmLock(~EFLAGS_ALIGN_CHECK, Flags & EFLAGS_ALIGN_CHECK); 01169 } 01170 } 01171 01172 01173 BOOLEAN 01174 KiIA32VdmReflectException( 01175 IN OUT PKIA32_FRAME Frame, 01176 IN ULONG Code 01177 ) 01178 /*++ 01179 01180 Routine Description: 01181 01182 This routine reflects an exception to a VDM. It uses the information 01183 in the trap frame to determine what exception to reflect, and updates 01184 the trap frame with the new CS, EIP, SS, and SP values 01185 01186 Arguments: 01187 01188 Frame - Pointer to the IA32 trap frame 01189 Code - The trap number that brought us here 01190 01191 Returns 01192 01193 Nothing 01194 01195 Notes: 01196 Interrupts are enable upon entry, Irql is at APC level 01197 This routine may not preserve all of the non-volatile registers if 01198 a fault occurs. 01199 --*/ 01200 { 01201 REGINFO Regs; 01202 KXDESCRIPTOR NewXCsDescriptor, NewXSsDescriptor; 01203 01204 // 01205 // First see if it is a GP fault and if we are set up to catch them 01206 // 01207 if ((Code == EXCEPTION_GP_FAULT) && (*VdmFixedStateLinear & VDM_BREAK_EXCEPTIONS)) { 01208 VdmDispatchException(Frame, STATUS_ACCESS_VIOLATION, Frame->Eip, 2, 0, -1, 0); 01209 return TRUE; 01210 } 01211 01212 // 01213 // Then see if this is a debug exception 01214 // 01215 if (*VdmFixedStateLinear & VDM_BREAK_DEBUGGER) { 01216 if (Code == EXCEPTION_DEBUG) { 01217 // 01218 // BUGBUG: iVE doesn't respond to TF, so need to reset 01219 // it elsewhere as well 01220 // 01221 Frame->EFlags &= ~EFLAGS_TF_MASK; 01222 VdmDispatchException(Frame, STATUS_SINGLE_STEP, Frame->Eip, 0, 0, 0, 0); 01223 return TRUE; 01224 } 01225 if (Code == EXCEPTION_INT3) { 01226 VdmDispatchException(Frame, STATUS_BREAKPOINT, Frame->Eip - 1, 3, USER_BREAKPOINT, 0, 0); 01227 01228 return TRUE; 01229 } 01230 } 01231 01232 // 01233 // Don't really know why this is here... But it is... 01234 // 01235 if (FLATUSER(Frame)) { 01236 return TRUE; 01237 } 01238 01239 01240 #if DEVL 01241 if (Code == EXCEPTION_SEGMENT_NOT_PRESENT) { 01242 ExVdmSegmentNotPresent++; 01243 } 01244 #endif 01245 01246 // 01247 // Allow for fiddling of the stack frame later 01248 // 01249 01250 Regs.RiTrapFrame = Frame; 01251 Regs.RiSegSs = Frame->SegSs; 01252 Regs.RiEsp = Frame->HardwareEsp; 01253 Regs.RiEFlags = Frame->EFlags; 01254 Regs.RiEip = Frame->Eip; 01255 Regs.RiSegCs = Frame->SegCs; 01256 01257 if (! CsToLinear(&Regs, VM86USER(Frame))) { 01258 return FALSE; 01259 } 01260 01261 if (! SsToLinear(&Regs, VM86USER(Frame))) { 01262 return FALSE; 01263 } 01264 01265 if (! PushException(Code, &Regs)) { 01266 return FALSE; 01267 } 01268 01269 // 01270 // For EM, when we change any segment register, we 01271 // need to change the descriptor as well.. PushException() 01272 // may have changed CS and SS, so need to update their descriptors 01273 // 01274 if (Regs.RiEFlags & EFLAGS_V86_MASK) { 01275 // QUESTION 01276 NewXCsDescriptor.DescriptorWords = (ULONGLONG) (Regs.RiSegCs << 4); 01277 NewXSsDescriptor.DescriptorWords = (ULONGLONG) (Regs.RiSegSs << 4); 01278 } 01279 else { 01280 if (! KeIA32UnscrambleLdtEntry(Regs.RiSegCs, &NewXCsDescriptor)) { 01281 return FALSE; 01282 } 01283 01284 if (! KeIA32UnscrambleLdtEntry(Regs.RiSegSs, &NewXSsDescriptor)) { 01285 return FALSE; 01286 } 01287 } 01288 01289 Frame->HardwareEsp = Regs.RiEsp; 01290 01291 // 01292 // Ss touched in PushException()... 01293 // 01294 Frame->SegSs = Regs.RiSegSs; 01295 Frame->EFlags = Regs.RiEFlags; 01296 01297 // 01298 // Cs touched in PushException()... 01299 // 01300 Frame->SegCs = Regs.RiSegCs; 01301 Frame->Eip = Regs.RiEip; 01302 01303 if (Code == EXCEPTION_DEBUG) { 01304 // 01305 // BUGBUG: iVE doesn't respond to TF, so need to reset 01306 // it elsewhere as well 01307 // 01308 Frame->EFlags &= ~EFLAGS_TF_MASK; 01309 } 01310 01311 return TRUE; 01312 } 01313 01314 01315 BOOLEAN 01316 KiIA32VdmSegmentNotPresent( 01317 IN OUT PKIA32_FRAME Frame 01318 ) 01319 /*++ 01320 01321 Routine Description: 01322 01323 This routine reflects a TRAP 0x0B to a VDM. It uses information 01324 in the trap frame to determine what exception to reflect 01325 and updates the trap frame with the new CS, EIP, SS, and ESP values 01326 01327 Arguments: 01328 01329 Frame - Pointer to the IA32 trap frame 01330 01331 Returns 01332 01333 True if the reflection was successful, false otherwise 01334 01335 Notes: 01336 none 01337 --*/ 01338 { 01339 PVDM_TIB VdmTib; 01340 PVDM_FAULTHANDLER NoSegFault; 01341 ULONG Flags; 01342 KXDESCRIPTOR NewXCsDescriptor; 01343 KXDESCRIPTOR NewXSsDescriptor; 01344 ULONG Offset; 01345 01346 // 01347 // Get the Segment Not Present handler information 01348 // 01349 VdmTib = (PVDM_TIB) (PsGetCurrentThread()->Tcb.Teb)->Vdm; 01350 01351 // 01352 // If not switching stacks, let regular reflection code handle this... 01353 // 01354 if (VdmTib->PmStackInfo.LockCount != 0) { 01355 return(KiIA32VdmReflectException(Frame, EXCEPTION_SEGMENT_NOT_PRESENT)); 01356 } 01357 01358 NoSegFault = &(VdmTib->VdmFaultHandlers[EXCEPTION_SEGMENT_NOT_PRESENT]); 01359 01360 #if DEVL 01361 ExVdmSegmentNotPresent++; 01362 #endif 01363 01364 // 01365 // Just like SwitchToStack() if there had been one... 01366 // 01367 VdmTib->PmStackInfo.LockCount++; 01368 VdmTib->PmStackInfo.SaveEip = Frame->Eip; 01369 VdmTib->PmStackInfo.SaveEsp = Frame->HardwareEsp; 01370 VdmTib->PmStackInfo.SaveSsSelector = Frame->SegSs; 01371 01372 // 01373 // We'll need to update the Frame with the proper descriptors, 01374 // so get them and unscramble them now... 01375 // 01376 if (! KeIA32UnscrambleLdtEntry(NoSegFault->CsSelector, &NewXCsDescriptor)) { 01377 return FALSE; 01378 } 01379 01380 if (! KeIA32UnscrambleLdtEntry(VdmTib->PmStackInfo.SsSelector, &NewXSsDescriptor)) { 01381 return FALSE; 01382 } 01383 01384 // 01385 // Regardless of 16/32 bit handler, still need the flags 01386 // 01387 Flags = Frame->EFlags; 01388 GetVirtualBits(&Flags, Frame); 01389 01390 // 01391 // See if this is a 32-bit handler 01392 // 01393 if (VdmTib->PmStackInfo.Flags & 1) { 01394 PULONG ExcptStack32; 01395 01396 // 01397 // Now make ExcptStack points to the actual stack space... 01398 // 01399 ExcptStack32 = (PULONG) (NewXSsDescriptor.Words.Bits.Base + DPMISTACK_OFFSET); 01400 01401 // 01402 // And put normal fault arguments on the stack... 01403 // 01404 // QUESTION 01405 *--ExcptStack32 = Frame->SegSs; 01406 *--ExcptStack32 = Frame->HardwareEsp; 01407 *--ExcptStack32 = Flags; 01408 01409 *--ExcptStack32 = Frame->SegCs; 01410 *--ExcptStack32 = Frame->Eip; 01411 *--ExcptStack32 = Frame->ISRCode; 01412 01413 // 01414 // And push dosx iret segment and offset 01415 // 01416 *--ExcptStack32 = VdmTib->PmStackInfo.DosxFaultIretD >> 16; 01417 *--ExcptStack32 = VdmTib->PmStackInfo.DosxFaultIretD & 0x0ffff; 01418 01419 Offset = ((PUCHAR) ExcptStack32) - NewXSsDescriptor.Words.Bits.Base; 01420 } 01421 else { 01422 PUSHORT ExcptStack16; 01423 01424 // 01425 // Now make ExcptStack points to the actual stack space... 01426 // 01427 ExcptStack16 = NewXSsDescriptor.Words.Bits.Base + DPMISTACK_OFFSET; 01428 01429 // 01430 // And put normal fault arguments on the stack... 01431 // 01432 *--ExcptStack16 = Frame->SegSs; 01433 *--ExcptStack16 = Frame->HardwareEsp; 01434 *--ExcptStack16 = Flags; 01435 01436 *--ExcptStack16 = Frame->SegCs; 01437 *--ExcptStack16 = Frame->Eip; 01438 *--ExcptStack16 = Frame->ISRCode; 01439 01440 // 01441 // And push dosx iret segment and offset 01442 // 01443 *--ExcptStack16 = VdmTib->PmStackInfo.DosxFaultIretD >> 16; 01444 *--ExcptStack16 = VdmTib->PmStackInfo.DosxFaultIretD & 0x0ffff; 01445 Offset = ((PUCHAR) ExcptStack16) - NewXSsDescriptor.Words.Bits.Base; 01446 } 01447 01448 if (NoSegFault->Flags & VDM_INT_INT_GATE) { 01449 KeIA32AndOrVdmLock(~VDM_VIRTUAL_INTERRUPTS, 0); 01450 Frame->EFlags &= ~EFLAGS_VIF; 01451 } 01452 01453 Frame->SegCs = NoSegFault->CsSelector; 01454 Frame->Eip = NoSegFault->Eip; 01455 Frame->SegSs = VdmTib->PmStackInfo.SsSelector; 01456 Frame->HardwareEsp = Offset; 01457 01458 return TRUE; 01459 } 01460 01461 01462 VOID 01463 VdmDispatchException( 01464 IN PKIA32_FRAME Frame, 01465 IN NTSTATUS ExcepCode, 01466 IN PVOID ExcepAddr, 01467 IN ULONG NumParms, 01468 IN ULONG Parm1, 01469 IN ULONG Parm2, 01470 IN ULONG Parm3 01471 ) 01472 01473 /*++ 01474 01475 Routine Description: 01476 01477 Dispatches an exception for the VDM to the kernel by invoking the 01478 KiIA32DispatchException() routine. 01479 01480 Arguments: 01481 01482 See KiIA32DispatchException() 01483 01484 Returns: 01485 01486 nothing 01487 01488 --*/ 01489 { 01490 // 01491 // Lower the IRQL to 0 and give any APC's and Debuggers a chance 01492 // 01493 // QUESTION 01494 KeLowerIrql(0); 01495 01496 // 01497 // Might as well make sure things are legal... 01498 // 01499 ASSERT(NumParms <= 3); 01500 01501 // 01502 // This was a call to CommonDispatchException() but that routine 01503 // doesn't exist in EM, so trying to call the nearest available... 01504 // 01505 KiIA32ExceptionDispatch(Frame, ExcepCode, ExcepAddr, NumParms, Parm1, Parm2, Parm3); 01506 01507 // 01508 // Should Never get here... KiIA32ExceptionDispatch() never returns... 01509 // 01510 } 01511 01512 01513 BOOLEAN 01514 PushInt(IN ULONG InterruptNumber, 01515 IN OUT PREGINFO Regs 01516 ) 01517 /*++ 01518 01519 Routine Description: 01520 01521 This routine pushes an interrupt frame on the user stack 01522 01523 Arguments: 01524 01525 InterruptNumber - self explanitory... 01526 Regs - Pointer to a REGINFO structure 01527 01528 Returns: 01529 01530 True if stack successfully modified and Regs updated, otherwise false 01531 01532 Notes: 01533 01534 None 01535 --*/ 01536 { 01537 PVDM_TIB VdmTib; 01538 PVDM_INTERRUPTHANDLER IntHandler; 01539 PULONG ExcptStack32; 01540 PUSHORT ExcptStack16; 01541 ULONG Flags; 01542 01543 ASSERT(InterruptNumber < 256); 01544 01545 VdmTib = (PVDM_TIB) (PsGetCurrentThread()->Tcb.Teb)->Vdm; 01546 01547 IntHandler = &(VdmTib->VdmInterruptHandlers[InterruptNumber]); 01548 01549 // 01550 // If we are a small segment, make sure the ESP is 16 bits. 01551 // 01552 if (! Regs->RiSsDescriptor.Words.Bits.Default_Big) { 01553 Regs->RiEsp &= 0xffff; 01554 } 01555 01556 // 01557 // Make sure there is space on the stack 01558 // 01559 if (IntHandler->Flags & VDM_INT_32) { 01560 if (Regs->RiEsp <= (3 * sizeof(PVOID))) { 01561 return FALSE; 01562 } 01563 01564 Regs->RiEsp -= 3 * sizeof(PVOID); 01565 } 01566 else { 01567 if (Regs->RiEsp <= (3 * sizeof(SHORT))) { 01568 return FALSE; 01569 } 01570 01571 Regs->RiEsp -= 3 * sizeof(SHORT); 01572 } 01573 01574 // 01575 // Check that esp is still OK 01576 // 01577 if (Regs->RiSsDescriptor.Words.Bits.Type & DESCRIPTOR_EXPAND_DOWN) { 01578 if (Regs->RiEsp <= Regs->RiSsLimit) { 01579 return FALSE; 01580 } 01581 } 01582 else { 01583 if (Regs->RiEsp >= Regs->RiSsLimit) { 01584 return FALSE; 01585 } 01586 } 01587 01588 // 01589 // Push the iret frame 01590 // 01591 01592 // 01593 // Get the modified EFlags 01594 // 01595 Flags = Regs->RiEFlags; 01596 GetVirtualBits(&Flags, Regs->RiTrapFrame); 01597 01598 if (IntHandler->Flags & VDM_INT_32) { 01599 ExcptStack32 = Regs->RiSsBase + Regs->RiEsp; 01600 01601 // 01602 // And put arguments on the stack... 01603 // 01604 *ExcptStack32++ = Regs->RiEip; 01605 *ExcptStack32++ = Regs->RiSegCs; 01606 *ExcptStack32 = Flags; 01607 } 01608 else { 01609 ExcptStack16 = Regs->RiSsBase + Regs->RiEsp; 01610 01611 // 01612 // And put arguments on the stack... 01613 // 01614 *ExcptStack16++ = Regs->RiEip; 01615 *ExcptStack16++ = Regs->RiSegCs; 01616 *ExcptStack16 = Flags; 01617 } 01618 01619 // 01620 // Make sure the address pointed to by CS exists 01621 // 01622 Regs.RiSegCs = IntHandler->CsSelector; 01623 Regs.RiEip = IntHandler->Eip; 01624 01625 if (CsToLinear(&Regs, ! (IntHandler->Flags & VDM_INT_32))) { 01626 if (! Regs->RiCsDescriptor.Words.Bits.Pres) { 01627 return FALSE; 01628 } 01629 } 01630 else { 01631 // 01632 // This is a little strange... CsToLinear fails if either the 01633 // type of the descriptor is wrong, or if the limit is bad... 01634 // Only reject the INT handler if the limit is bad... 01635 // 01636 01637 if (Regs.RiEip >= Regs.RiCsLimit) { 01638 return FALSE; 01639 } 01640 } 01641 01642 Regs.RiEFlags &= ~EFLAGS_TF_MASK; 01643 01644 if (IntHandler->Flags & VDM_INT_INT_GATE) { 01645 if (KeIA32VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) { 01646 Regs->RiEFlags &= ~EFLAGS_VIF; 01647 } 01648 KeIA32AndOrVdmLock(~EFLAGS_INTERRUPT_MASK, 0); 01649 } 01650 01651 Regs.RiEFlags &= ~(EFLAGS_IOPL_MASK | EFLAGS_NT_MASK | EFLAGS_V86_MASK); 01652 Regs.RiEFlags |= EFLAGS_INTERRUPT_MASK; 01653 01654 return TRUE; 01655 } 01656 01657 01658 BOOLEAN 01659 PushException( 01660 IN ULONG ExceptionNumber, 01661 IN OUT PREGINFO Regs 01662 ) 01663 /*++ 01664 01665 Routine Description: 01666 01667 This routine pushes an exception onto the user stack 01668 01669 Arguments: 01670 01671 ExceptionNumber - self explanitory... 01672 Regs - Pointer to a REGINFO structure 01673 01674 Returns: 01675 01676 True if stack successfully modified and Regs updated, otherwise false 01677 01678 Notes: 01679 01680 None 01681 --*/ 01682 { 01683 PVDM_TIB VdmTib; 01684 PVDM_FAULTHANDLER ExceptHandler; 01685 ULONG Flags; 01686 01687 ASSERT(ExceptionNumber < 32); 01688 01689 VdmTib = (PVDM_TIB) (PsGetCurrentThread()->Tcb.Teb)->Vdm; 01690 ExceptHandler = &(VdmTib->VdmFaultHandlers[ExceptionNumber]); 01691 01692 if (Regs->RiEFlags & EFLAGS_V86_MASK) { 01693 PUSHORT ExcptStack16; 01694 01695 // We were in V86 mode when exception happened... 01696 01697 // 01698 // device not available fault... Per win3.1, no exceptions 01699 // above 7 for v86 mode 01700 // 01701 if (ExceptionNumber > 7) { 01702 return FALSE; 01703 } 01704 01705 // 01706 // And push things on the stack for V86 mode 01707 // making sure to handle wrap-around each time... 01708 // 01709 Regs->RiEsp = ((Regs->RiEsp - 2) & 0xffff); 01710 ExcptStack16 = Regs->RiSsBase + Regs->RiEsp; 01711 Flags = Regs->RiEFlags; 01712 GetVirtualBits(&Flags, Regs->RiTrapFrame); 01713 *ExcptStack16 = Flags; 01714 01715 Regs->RiEsp = ((Regs->RiEsp - 2) & 0xffff); 01716 ExcptStack16 = Regs->RiSsBase + Regs->RiEsp; 01717 *ExcptStack16 = Regs->RiSegCs; 01718 01719 Regs->RiEsp = ((Regs->RiEsp - 2) & 0xffff); 01720 ExcptStack16 = Regs->RiSsBase + Regs->RiEsp; 01721 *ExcptStack16 = Regs->RiEip; 01722 } 01723 else { 01724 // We were in protected mode when the exception happened... 01725 01726 // 01727 // This was originally part of a seperate routine 01728 // called SwitchToHandlerStack(), but it was never called 01729 // anywhere else, so now it's inline... 01730 // 01731 01732 // 01733 // Have we already switched stacks? 01734 // 01735 if (VdmTib->PmStackInfo.LockCount == 0) { 01736 VdmTib->PmStackInfo.SaveEip = Regs.RiEip; 01737 VdmTib->PmStackInfo.SaveEsp = Regs.RiEsp; 01738 VdmTib->PmStackInfo.SaveSsSelector = Regs.RiSegSs; 01739 01740 Regs->RiSegSs = VdmTib->PmStackInfo.SsSelector; 01741 Regs->RiEsp = DPMISTACK_EXCEPTION_OFFSET; 01742 01743 // 01744 // And update and verify the Regs structure 01745 // 01746 if (! SsToLinear(Regs, FALSE)) { 01747 return FALSE; 01748 } 01749 01750 VdmTib->PmStackInfo.LockCount++; 01751 } 01752 01753 // 01754 // Windows 3.1 undocumented feature 01755 // 01756 Regs->RiEsp -= 0x20; 01757 01758 if (! Regs->RiSsDescriptor.Words.Bits.Default_Big) { 01759 // 01760 // If we are not "big" then the ESP should stay 16 bit 01761 // 01762 Regs->RiEsp &= 0xffff; 01763 } 01764 01765 Flags = Regs->RiEFlags; 01766 GetVirtualBits(&Flags, Regs->RiTrapFrame); 01767 01768 if (VdmTib->PmStackInfo.Flags) { 01769 PULONG ExcptStack32; 01770 01771 // 01772 // This is a 32-bit handler 01773 // 01774 01775 if (! CheckEsp(Regs, 32)) { 01776 return FALSE; 01777 } 01778 01779 ExcptStack32 = Regs.RiSsBase + Regs.RiEsp; 01780 *--ExcptStack32 = VdmTib->PmStackInfo.SaveSsSelector; 01781 *--ExcptStack32 = VdmTib->PmStackInfo.SaveEsp; 01782 *--ExcptStack32 = Flags; 01783 *--ExcptStack32 = Regs->RiSegCs; 01784 *--ExcptStack32 = VdmTib->PmStackInfo.SaveEip; 01785 *--ExcptStack32 = Regs->RiTrapFrame->ISRCode; 01786 01787 // 01788 // And push dosx iret segment and offset 01789 // 01790 *--ExcptStack32 = VdmTib->PmStackInfo.DosxFaultIretD >> 16; 01791 *--ExcptStack32 = VdmTib->PmStackInfo.DosxFaultIretD & 0x0ffff; 01792 01793 // QUESTION 01794 Regs.RiEsp = ExcptStack32 - Regs.RiSsBase; 01795 01796 } 01797 else { 01798 PUSHORT ExcptStack16; 01799 01800 // 01801 // Do the 16 bit handler thing... 01802 // 01803 01804 if (! CheckEsp(Regs, 16)) { 01805 return FALSE; 01806 } 01807 01808 ExcptStack16 = Regs.RiSsBase + Regs.RiEsp; 01809 *--ExcptStack16 = VdmTib->PmStackInfo.SaveSsSelector; 01810 *--ExcptStack16 = VdmTib->PmStackInfo.SaveEsp; 01811 *--ExcptStack16 = Flags; 01812 *--ExcptStack16 = Regs->RiSegCs; 01813 *--ExcptStack16 = VdmTib->PmStackInfo.SaveEip; 01814 *--ExcptStack16 = Regs->RiTrapFrame->ISRCode; 01815 01816 // 01817 // And push dosx iret segment and offset 01818 // 01819 *--ExcptStack16 = VdmTib->PmStackInfo.DosxFaultIretD >> 16; 01820 *--ExcptStack16 = VdmTib->PmStackInfo.DosxFaultIretD & 0x0ffff; 01821 01822 Regs->RiEsp = ExcptStack16 - Regs.RiSsBase; 01823 } 01824 } 01825 01826 // 01827 // Make sure the address pointed to by CS exists 01828 // 01829 Regs.RiSegCs = ExceptHandler->CsSelector; 01830 Regs.RiEip = ExceptHandler->Eip; 01831 01832 if (! CsToLinear(&Regs, Regs->RiEFlags & EFLAGS_V86_MASK)) { 01833 return FALSE; 01834 } 01835 01836 // 01837 // Strange, they do this test twice - it is part of CsToLinear() 01838 // 01839 // if (Regs.RiEip > Regs.RiCsLimit) { 01840 // return FALSE; 01841 // } 01842 01843 if (ExceptHandler->Flags & VDM_INT_INT_GATE) { 01844 SetVirtualBits(Regs->RiEFlags & ~(EFLAGS_INTERRUPT_MASK | EFLAGS_TF_MASK), &Regs); 01845 } 01846 01847 CheckVdmFlags(&Regs); 01848 01849 Regs.RiEFlags &= ~EFLAGS_TF_MASK; 01850 01851 return TRUE; 01852 } 01853 01854 01855 BOOLEAN 01856 CsToLinear( 01857 IN OUT PREGINFO Regs, 01858 IN BOOLEAN IsV86 01859 ) 01860 /*++ 01861 01862 Routine Description: 01863 01864 This routine converts the address shown in CS and IP into a linear 01865 address based on the mode (V86 vs. protected) 01866 01867 Arguments: 01868 01869 Regs - Pointer to a REGINFO structure 01870 IsV86 - True if the CS and IP should be checked against V86 constraints 01871 01872 Returns: 01873 01874 True if Regs->RiLinearAddr is valid, otherwise false 01875 01876 Notes: 01877 01878 None 01879 --*/ 01880 { 01881 if (IsV86) { 01882 // 01883 // Don't need the Descriptor in V86 mode 01884 // 01885 Regs->RiCsBase = Regs->RiSegCs << 4; 01886 // QUESTION 01887 Regs->RiCsDescriptor.DescriptorWords = (ULONGLONG) Regs->RiCsBase; 01888 Regs->RiCsLimit = 0xffff; 01889 } 01890 else { 01891 01892 if (! KeIA32UnscrambleLdtEntry(Regs->RiSegCs, &Regs->RiCsDescriptor)) { 01893 return FALSE; 01894 } 01895 01896 // 01897 // Need to fill in the cs stuff to make translation to linear 01898 // addresses easier 01899 // 01900 Regs->RiCsBase = (ULONG) Regs->RiCsDescriptor.Words.Bits.Base; 01901 Regs->RiCsLimit = (ULONG) Regs->RiCsDescriptor.Words.Bits.Limit; 01902 01903 // 01904 // Check for the big limits 01905 // 01906 if (Regs->RiCsDescriptor.Words.Bits.Granularity) { 01907 Regs->RiCsLimit <<= 12; 01908 Regs->RiCsLimit |= 0xfff; 01909 } 01910 01911 // 01912 // Make sure the cs segment is executable code... 01913 // (see Ki386GetSelectorParameters()...) 01914 // 01915 // Check is done here because the other stuff should be done even 01916 // if this check fails 01917 // 01918 if ((Regs->RiCsDescriptor.Words.Bits.Type & TYPE_CODE_USER ) != 01919 TYPE_CODE_USER) { 01920 return FALSE; 01921 } 01922 } 01923 01924 // 01925 // Now make sure the ip is in the correct range 01926 // 01927 if (Regs->RiEip > Regs->RiCsLimit) { 01928 return FALSE; 01929 } 01930 01931 // 01932 // Finally, generate the linear address 01933 // 01934 Regs->RiLinearAddr = Regs->RiEip + Regs->RiCsBase; 01935 01936 return TRUE; 01937 } 01938 01939 01940 BOOLEAN 01941 CheckEip( 01942 IN PREGINFO Regs 01943 ) 01944 /*++ 01945 01946 Routine Description: 01947 01948 This routine verifies the EIP is legal before putting it back into 01949 a trap frame. 01950 01951 Arguments: 01952 01953 Regs - Pointer to a REGINFO structure 01954 01955 Returns: 01956 01957 True if the EIP is legal, false otherwise 01958 01959 Notes: 01960 01961 --*/ 01962 { 01963 if (Regs->RiEFlags & EFLAGS_V86_MASK) { 01964 Regs->RiEip &= Regs->RiCsLimit; 01965 } 01966 else { 01967 if (Regs->RiEip > Regs->RiCsLimit) { 01968 return FALSE; 01969 } 01970 } 01971 01972 return TRUE; 01973 } 01974 01975 01976 BOOLEAN 01977 SsToLinear( 01978 IN OUT PREGINFO Regs, 01979 IN BOOLEAN IsV86 01980 ) 01981 /*++ 01982 01983 Routine Description: 01984 01985 This routine converts the SS selector given in the regs structure 01986 into a base and limit based on the mode (V86 vs. protected) 01987 01988 01989 Arguments: 01990 01991 Regs - Pointer to a REGINFO structure 01992 IsV86 - True if the Base and Limit should be set using V86 constraints 01993 01994 Returns: 01995 01996 True if Regs->RiSsBase and Regs->RiSsLimit are valid, false otherwise 01997 01998 Notes: 01999 02000 Unlike FastCsToLinear(), this routine does not verify that the user of 02001 the segment (in this case, ESP) is actually within the proper limits 02002 --*/ 02003 { 02004 if (IsV86) { 02005 // 02006 // Don't need the descriptor in this case 02007 // 02008 Regs->RiSsBase = Regs->RiSegSs << 4; 02009 Regs->RiSsDescriptor.DescriptorWords = (ULONGLONG) Regs->RiSsBase; 02010 Regs->RiSsLimit = 0xffff; 02011 } 02012 else { 02013 if (! KeIA32UnscrambleLdtEntry(Regs->RiSegSs, &Regs->RiSsDescriptor)) { 02014 return FALSE; 02015 } 02016 02017 // 02018 // Make sure the ss segment is not executable code but is read/write 02019 // (see Ki386GetSelectorParameters()...) 02020 // 02021 if ((Regs->RiSsDescriptor.Words.Bits.Type & DESCRIPTOR_DATA_READWRITE) != 02022 DESCRIPTOR_DATA_READWRITE ) { 02023 return FALSE; 02024 } 02025 02026 // 02027 // Now fill in the ss stuff... 02028 // 02029 Regs->RiSsBase = (ULONG) (Regs->RiSsDescriptor.Words.Bits.Base); 02030 Regs->RiSsLimit = (ULONG) (Regs->RiSsDescriptor.Words.Bits.Limit); 02031 02032 // 02033 // Check for the big limits... 02034 // 02035 if (Regs->RiSsDescriptor.Words.Bits.Default_Big) { 02036 Regs->RiSsLimit <<= 12; 02037 Regs->RiSsLimit |= 0xfff; 02038 } 02039 } 02040 02041 return TRUE; 02042 } 02043 02044 02045 BOOLEAN 02046 CheckEsp( 02047 IN PREGINFO Regs, 02048 IN ULONG StackNeeded 02049 ) 02050 /*++ 02051 02052 Routine Description: 02053 02054 This routine verifies the ESP is legal before putting it back into 02055 a trap frame. 02056 02057 Arguments: 02058 02059 Regs - Pointer to a REGINFO structure 02060 StackNeeded - Need to be this far away from stack limit 02061 02062 Returns: 02063 02064 True if the ESP is legal (and there is available space on the stack), 02065 false otherwise 02066 02067 Notes: 02068 02069 --*/ 02070 { 02071 if (Regs->RiEFlags & EFLAGS_V86_MASK) { 02072 Regs->RiEsp &= Regs->RiSsLimit; 02073 } 02074 else { 02075 if (! Regs->RiSsDescriptor.Words.Bits.Default_Big) { 02076 // 02077 // If we are not "big" then the ESP should stay 16 bit 02078 // 02079 Regs->RiEsp &= 0xffff; 02080 } 02081 02082 // 02083 // If we are expand up or expand down, this is a problem... 02084 // 02085 if (StackNeeded > Regs->RiEsp) { 02086 return FALSE; 02087 } 02088 02089 if ((Regs->RiSsDescriptor.Words.Bits.Type & DESCRIPTOR_EXPAND_DOWN) == 02090 DESCRIPTOR_EXPAND_DOWN ) { 02091 if (Regs->RiEsp - StackNeeded - 1 < Regs->RiSsLimit) { 02092 return FALSE; 02093 } 02094 } 02095 else { 02096 if (Regs->RiEsp >= Regs->RiSsLimit) { 02097 return FALSE; 02098 } 02099 } 02100 } 02101 02102 return TRUE; 02103 } 02104 02105 02106 BOOLEAN 02107 KeIA32UnscrambleLdtEntry( 02108 IN ULONG Selector, 02109 OUT PKXDESCRIPTOR XDescriptor 02110 ) 02111 /*++ 02112 02113 Routine Description: 02114 02115 This routine gets the requested LDT entry and converts it into 02116 the unscrambled format needed by the EM descriptor registers 02117 02118 Arguments: 02119 02120 Selector - selector number to use 02121 XDescriptor - unscrambled descriptor 02122 02123 Returns: 02124 02125 True if the the selector was found, false otherwise 02126 02127 Notes: 02128 02129 --*/ 02130 { 02131 PETHREAD Thread; 02132 DESCRIPTOR_TABLE_ENTRY DescriptorEntry; 02133 NTSTATUS Status; 02134 02135 // 02136 // We only deal with LDT, so make sure that's what we got... 02137 // 02138 if ((Selector & (SELECTOR_TABLE_INDEX | DPL_USER)) != (SELECTOR_TABLE_INDEX | DPL_USER)) { 02139 02140 return FALSE; 02141 } 02142 02143 Thread = KeGetCurrentThread(); 02144 DescriptorEntry.Selector = Selector; 02145 02146 Status = PspQueryDescriptorThread(Thread, &DescriptorEntry, sizeof(DescriptorEntry), NULL); 02147 if (!NT_SUCCESS(Status)) { 02148 return FALSE; 02149 } 02150 02151 XDescriptor->Words.DescriptorWords = KeIA32Unscramble(&DescriptorEntry.Descriptor); 02152 02153 return TRUE; 02154 } 02155 02156 02157 ULONGLONG 02158 KeIA32Unscramble( 02159 IN PLDT_ENTRY Descriptor 02160 ) 02161 /*++ 02162 02163 Routine Description: 02164 02165 This routine converts from the scrambled format used by memory 02166 into the unscrambled format used by the iVE. Assumes that the following 02167 flags are a constant: 02168 the DPL is always 3, 02169 the accessed bit is always 1, 02170 and the system bit is always 0 02171 02172 Arguments: 02173 02174 Descriptor - scrambled descriptor 02175 02176 Returns: 02177 02178 An unscrambled descriptor 02179 02180 Notes: 02181 02182 --*/ 02183 { 02184 KXDESCRIPTOR Result; 02185 02186 // 02187 // Fill in the base 02188 // 02189 Result.Words.Bits.Base = Descriptor->BaseLow | (Descriptor->HighWord.Bytes.BaseMid << 16) | (Descriptor->HighWord.Bytes.BaseHi << 24); 02190 02191 // 02192 // Fill in the limit 02193 // 02194 Result.Words.Bits.Limit = (Descriptor->LimitLow | (Descriptor->HighWord.Bits.LimitHi << 16)) << UNSCRAM_LIMIT_OFFSET; 02195 02196 // 02197 // Fill in the flags - since the DPL is always 3, the accessed bit 02198 // is always 1, and the system bit is always 0, use a constant for 02199 // those values (0x61)... 02200 // 02201 Result.Words.Bits.Type = Descriptor->HighWord.Bits.Type; 02202 Result.Words.Bits.Dpl = Descriptor->HighWord.Bits.Dpl; 02203 Result.Words.Bits.Pres = Descriptor->HighWord.Bits.Pres; 02204 Result.Words.Bits.Sys = Descriptor->HighWord.Bits.Sys; 02205 Result.Words.Bits.Reserved_0 = Descriptor->HighWord.Bits.Reserved_0; 02206 Result.Words.Bits.Default_Big = Descriptor->HighWord.Bits.Default_Big; 02207 Result.Words.Bits.Granularity = Descriptor->HighWord.Bits.Granularity; 02208 02209 return Result.Words.DescriptorWords; 02210 } 02211 02212 // 02213 // These definitions are only used in the CheckVdmFlags() 02214 // routine below. 02215 // 02216 #define _VDM_CHECK_OR_FUNC(x) ((x) |= EFLAGS_INTERRUPT_MASK) 02217 #define _VDM_CHECK_AND_FUNC(x) ((x) &= ~(EFLAGS_IOPL_MASK | EFLAGS_NT_MASK | EFLAGS_VIF | EFLAGS_VIP)) 02218 02219 02220 VOID 02221 CheckVdmFlags( 02222 IN OUT PREGINFO Regs 02223 ) 02224 02225 /*++ 02226 02227 Routine Description: 02228 02229 This routine checks the flags that are going to be used for the 02230 dos or windows application 02231 02232 Arguments: 02233 02234 Regs - Pointer to REGINFO structure... 02235 02236 Returns: 02237 02238 Nothing. But modifies EFlags field in Regs to an acceptable value 02239 02240 --*/ 02241 { 02242 if (KeIA32VdmIoplAllowed) { 02243 if (! (Regs->RiEFlags & EFLAGS_V86_MASK)) { 02244 _VDM_CHECK_OR_FUNC(Regs->RiEFlags); 02245 } 02246 _VDM_CHECK_AND_FUNC(Regs->RiEFlags); 02247 return; 02248 } 02249 02250 // 02251 // There was a lot of code here to check for Virtual Extensions... 02252 // Depending on if they existed or not, a value in eax was changed 02253 // (in ../i386/instemul.asm - at label cvf50: ) but it is never used 02254 // (not even as a return value...) 02255 // So, rather than repeat all that silly code that doesn't do anything, 02256 // I only show the code that is actually executed... Enjoy... 02257 // 02258 02259 #if 0 02260 if (KeIA32VirtualIntExtensions & (V86_VIRTUAL_INT_EXTENSIONS | PM_VIRTUAL_INT_EXTENSIONS)) { 02261 if (Regs->RiEflags & EFLAGS_V86_MASK) { 02262 if (KeIA32VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) { 02263 } 02264 else { 02265 } 02266 } 02267 else { 02268 if (KeIA32VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) { 02269 } 02270 else { 02271 } 02272 } 02273 } 02274 #endif 02275 02276 _VDM_CHECK_OR_FUNC(Regs->RiEFlags); 02277 _VDM_CHECK_AND_FUNC(Regs->RiEFlags); 02278 } 02279 02280 02281 VOID 02282 KeIA32AndOrVdmLock( 02283 IN ULONG AndMask, 02284 IN ULONG OrMask 02285 ) 02286 02287 /*++ 02288 02289 Routine Description: 02290 02291 This routine modifies the VdmFixedStateLinear location in an MP 02292 safe way. In the original IA code, they used the LOCK prefix. 02293 02294 Arguments: 02295 02296 AndMask - The value to use as the AND mask 02297 OrMask - The value to use as the OR mask 02298 02299 Returns: 02300 02301 nothing 02302 02303 --*/ 02304 { 02305 #ifdef NT_UP 02306 *VdmFixedStateLinear = (*VdmFixedStateLinear & AndMask) | OrMask; 02307 #else 02308 VdmGenericAndOrLock(VdmFixedStateLinear, AndMask, OrMask); 02309 #endif 02310 } 02311 02312 #else // defined(WX86) && defined(TRY_NTVDM) 02313 02314 02315 BOOLEAN 02316 KiIA32VdmReflectException( 02317 IN OUT PKIA32_FRAME Frame, 02318 IN ULONG Code 02319 ) 02320 /*++ 02321 02322 Routine Description: 02323 02324 This routine reflects an exception to a VDM. It uses the information 02325 in the trap frame to determine what exception to reflect, and updates 02326 the trap frame with the new CS, EIP, SS, and SP values 02327 02328 Arguments: 02329 02330 Frame - Pointer to the IA32 trap frame 02331 Code - The trap number that brought us here 02332 02333 Returns 02334 02335 Nothing 02336 02337 Notes: 02338 Interrupts are enable upon entry, Irql is at APC level 02339 This routine may not preserve all of the non-volatile registers if 02340 a fault occurs. 02341 --*/ 02342 { 02343 // 02344 // Not yet implemented... 02345 // 02346 return(FALSE); 02347 } 02348 02349 02350 BOOLEAN 02351 KiIA32DispatchOpcode( 02352 IN PKIA32_FRAME Frame 02353 ) 02354 02355 /*++ 02356 02357 Routine Description: 02358 02359 This routine dispatches to the opcode of the specific emulation routine. 02360 based on the first byte of the opcode. It is a combination of the 02361 original x86 emulation routines written in assembly (i386/instemul.asm 02362 and i386/emv86.asm). 02363 02364 Arguments: 02365 02366 Frame - pointer to the ia32 trap frame. 02367 02368 Return Value: 02369 02370 Returns true if the opcode was handled, otherwise false 02371 02372 --*/ 02373 02374 { 02375 // 02376 // Not yet implemented 02377 // 02378 02379 return(FALSE); 02380 } 02381 02382 02383 BOOLEAN 02384 KiIA32VdmSegmentNotPresent( 02385 IN OUT PKIA32_FRAME Frame 02386 ) 02387 /*++ 02388 02389 Routine Description: 02390 02391 This routine reflects a TRAP 0x0B to a VDM. It uses information 02392 in the trap frame to determine what exception to reflect 02393 and updates the trap frame with the new CS, EIP, SS, and ESP values 02394 02395 Arguments: 02396 02397 Frame - Pointer to the IA32 trap frame 02398 02399 Returns 02400 02401 True if the reflection was successful, false otherwise 02402 02403 Notes: 02404 none 02405 --*/ 02406 { 02407 // 02408 // Not yet implemented 02409 // 02410 02411 return(FALSE); 02412 } 02413 02414 #endif // defined(WX86) && defined(TRY_NTVDM)

Generated on Sat May 15 19:39:49 2004 for test by doxygen 1.3.7