Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenv86vdm.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/ke/i386/v86vdm.c 00005 * PURPOSE: V8086 and VDM Trap Emulation 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 * Alex Ionescu (alex.ionescu@reactos.org) 00008 */ 00009 00010 /* INCLUDES *******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define KiVdmGetInstructionSize(x) ((x) & 0xFF) 00017 #define KiVdmGetPrefixFlags(x) ((x) & 0xFFFFFF00) 00018 00019 /* GLOBALS ********************************************************************/ 00020 00021 ULONG KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE; 00022 ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK; 00023 PVOID Ki386IopmSaveArea; 00024 BOOLEAN KeI386VirtualIntExtensions = FALSE; 00025 const PULONG KiNtVdmState = (PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT; 00026 00027 /* UNHANDLED OPCODES **********************************************************/ 00028 00029 KiVdmUnhandledOpcode(F); 00030 KiVdmUnhandledOpcode(OUTSW); 00031 KiVdmUnhandledOpcode(OUTSB); 00032 KiVdmUnhandledOpcode(INSB); 00033 KiVdmUnhandledOpcode(INSW); 00034 KiVdmUnhandledOpcode(NPX); 00035 KiVdmUnhandledOpcode(INBimm); 00036 KiVdmUnhandledOpcode(INWimm); 00037 KiVdmUnhandledOpcode(OUTBimm); 00038 KiVdmUnhandledOpcode(OUTWimm); 00039 KiVdmUnhandledOpcode(INB); 00040 KiVdmUnhandledOpcode(INW); 00041 KiVdmUnhandledOpcode(OUTB); 00042 KiVdmUnhandledOpcode(OUTW); 00043 KiVdmUnhandledOpcode(HLT); 00044 KiVdmUnhandledOpcode(INTO); 00045 KiVdmUnhandledOpcode(INV); 00046 00047 /* OPCODE HANDLERS ************************************************************/ 00048 00049 BOOLEAN 00050 FASTCALL 00051 KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame, 00052 IN ULONG Flags) 00053 { 00054 ULONG Esp, V86EFlags, TrapEFlags; 00055 00056 /* Check for VME support */ 00057 ASSERT(KeI386VirtualIntExtensions == FALSE); 00058 00059 /* Get current V8086 flags and mask out interrupt flag */ 00060 V86EFlags = *KiNtVdmState; 00061 V86EFlags &= ~EFLAGS_INTERRUPT_MASK; 00062 00063 /* Get trap frame EFLags and leave only align, nested task and interrupt */ 00064 TrapEFlags = TrapFrame->EFlags; 00065 V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); 00066 00067 /* Add in those flags if they exist, and add in the IOPL flag */ 00068 V86EFlags |= TrapEFlags; 00069 V86EFlags |= EFLAGS_IOPL; 00070 00071 /* Build flat ESP */ 00072 Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp; 00073 00074 /* Check for OPER32 */ 00075 if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32) 00076 { 00077 /* Save EFlags */ 00078 Esp -= 4; 00079 *(PULONG)Esp = V86EFlags; 00080 } 00081 else 00082 { 00083 /* Save EFLags */ 00084 Esp -= 2; 00085 *(PUSHORT)Esp = (USHORT)V86EFlags; 00086 } 00087 00088 /* Set new ESP and EIP */ 00089 TrapFrame->HardwareEsp = Esp - (TrapFrame->HardwareSegSs << 4); 00090 TrapFrame->Eip += KiVdmGetInstructionSize(Flags); 00091 00092 /* We're done */ 00093 return TRUE; 00094 } 00095 00096 BOOLEAN 00097 FASTCALL 00098 KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame, 00099 IN ULONG Flags) 00100 { 00101 ULONG Esp, V86EFlags, EFlags, TrapEFlags; 00102 00103 /* Build flat ESP */ 00104 Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp; 00105 00106 /* Check for OPER32 */ 00107 if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32) 00108 { 00109 /* Read EFlags */ 00110 EFlags = *(PULONG)Esp; 00111 Esp += 4; 00112 } 00113 else 00114 { 00115 /* Read EFlags */ 00116 EFlags = *(PUSHORT)Esp; 00117 Esp += 2; 00118 } 00119 00120 /* Set new ESP */ 00121 TrapFrame->HardwareEsp = Esp - (TrapFrame->HardwareSegSs << 4); 00122 00123 /* Mask out IOPL from the flags */ 00124 EFlags &= ~EFLAGS_IOPL; 00125 00126 /* Save the V86 flags, but mask out the nested task flag */ 00127 V86EFlags = EFlags & ~EFLAGS_NESTED_TASK; 00128 00129 /* Now leave only alignment, nested task and interrupt flag */ 00130 EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); 00131 00132 /* Get trap EFlags */ 00133 TrapEFlags = TrapFrame->EFlags; 00134 00135 /* Check for VME support */ 00136 ASSERT(KeI386VirtualIntExtensions == FALSE); 00137 00138 /* Add V86 and Interrupt flag */ 00139 V86EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; 00140 00141 /* Update EFlags in trap frame */ 00142 TrapFrame->EFlags = V86EFlags; 00143 00144 /* Check if ESP0 needs to be fixed up */ 00145 if (TrapEFlags & EFLAGS_V86_MASK) Ki386AdjustEsp0(TrapFrame); 00146 00147 /* Update the V8086 EFlags state */ 00148 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); 00149 KiVdmSetVdmEFlags(EFlags); 00150 00151 /* FIXME: Check for VDM interrupts */ 00152 00153 /* Update EIP */ 00154 TrapFrame->Eip += KiVdmGetInstructionSize(Flags); 00155 00156 /* We're done */ 00157 return TRUE; 00158 } 00159 00160 BOOLEAN 00161 FASTCALL 00162 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame, 00163 IN ULONG Flags) 00164 { 00165 ULONG Esp, V86EFlags, TrapEFlags, Eip, Interrupt; 00166 00167 /* Read trap frame EFlags */ 00168 TrapEFlags = TrapFrame->EFlags; 00169 00170 /* Remove interrupt flag from V8086 EFlags */ 00171 V86EFlags = *KiNtVdmState; 00172 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK); 00173 00174 /* Keep only alignment and interrupt flag from the V8086 state */ 00175 V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_INTERRUPT_MASK); 00176 00177 /* Check for VME support */ 00178 ASSERT(KeI386VirtualIntExtensions == FALSE); 00179 00180 /* Mask in the relevant V86 EFlags into the trap flags */ 00181 V86EFlags |= (TrapEFlags & ~EFLAGS_INTERRUPT_MASK); 00182 00183 /* And mask out the VIF, nested task and TF flag from the trap flags */ 00184 TrapFrame->EFlags = TrapEFlags &~ (EFLAGS_VIF | EFLAGS_NESTED_TASK | EFLAGS_TF); 00185 00186 /* Add the IOPL flag to the local trap flags */ 00187 V86EFlags |= EFLAGS_IOPL; 00188 00189 /* Build flat ESP */ 00190 Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp; 00191 00192 /* Push EFlags */ 00193 Esp -= 2; 00194 *(PUSHORT)(Esp) = (USHORT)V86EFlags; 00195 00196 /* Push CS */ 00197 Esp -= 2; 00198 *(PUSHORT)(Esp) = (USHORT)TrapFrame->SegCs; 00199 00200 /* Push IP */ 00201 Esp -= 2; 00202 *(PUSHORT)(Esp) = (USHORT)TrapFrame->Eip + KiVdmGetInstructionSize(Flags) + 1; 00203 00204 /* Update ESP */ 00205 TrapFrame->HardwareEsp = (USHORT)Esp; 00206 00207 /* Get flat EIP */ 00208 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip; 00209 00210 /* Now get the *next* EIP address (current is original + the count - 1) */ 00211 Eip += KiVdmGetInstructionSize(Flags); 00212 00213 /* Now read the interrupt number */ 00214 Interrupt = *(PUCHAR)Eip; 00215 00216 /* Read the EIP from its IVT entry */ 00217 Interrupt = *(PULONG)(Interrupt * 4); 00218 TrapFrame->Eip = (USHORT)Interrupt; 00219 00220 /* Now get the CS segment */ 00221 Interrupt = (USHORT)(Interrupt >> 16); 00222 00223 /* Check if the trap was not V8086 trap */ 00224 if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) 00225 { 00226 /* Was it a kernel CS? */ 00227 Interrupt |= RPL_MASK; 00228 if (TrapFrame->SegCs == KGDT_R0_CODE) 00229 { 00230 /* Add the RPL mask */ 00231 TrapFrame->SegCs = Interrupt; 00232 } 00233 else 00234 { 00235 /* Set user CS */ 00236 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK; 00237 } 00238 } 00239 else 00240 { 00241 /* Set IVT CS */ 00242 TrapFrame->SegCs = Interrupt; 00243 } 00244 00245 /* We're done */ 00246 return TRUE; 00247 } 00248 00249 BOOLEAN 00250 FASTCALL 00251 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame, 00252 IN ULONG Flags) 00253 { 00254 ULONG Esp, V86EFlags, EFlags, TrapEFlags, Eip; 00255 00256 /* Build flat ESP */ 00257 Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp; 00258 00259 /* Check for OPER32 */ 00260 if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32) 00261 { 00262 /* Build segmented EIP */ 00263 TrapFrame->Eip = *(PULONG)Esp; 00264 TrapFrame->SegCs = *(PUSHORT)(Esp + 4); 00265 00266 /* Set new ESP */ 00267 TrapFrame->HardwareEsp += 12; 00268 00269 /* Get EFLAGS */ 00270 EFlags = *(PULONG)(Esp + 8); 00271 } 00272 else 00273 { 00274 /* Build segmented EIP */ 00275 TrapFrame->Eip = *(PUSHORT)Esp; 00276 TrapFrame->SegCs = *(PUSHORT)(Esp + 2); 00277 00278 /* Set new ESP */ 00279 TrapFrame->HardwareEsp += 6; 00280 00281 /* Get EFLAGS */ 00282 EFlags = *(PUSHORT)(Esp + 4); 00283 } 00284 00285 /* Mask out EFlags */ 00286 EFlags &= ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP); 00287 V86EFlags = EFlags; 00288 00289 /* Check for VME support */ 00290 ASSERT(KeI386VirtualIntExtensions == FALSE); 00291 00292 /* Add V86 and Interrupt flag */ 00293 EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; 00294 00295 /* Update EFlags in trap frame */ 00296 TrapEFlags = TrapFrame->EFlags; 00297 TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | EFlags; 00298 00299 /* Check if ESP0 needs to be fixed up */ 00300 if (!(TrapEFlags & EFLAGS_V86_MASK)) Ki386AdjustEsp0(TrapFrame); 00301 00302 /* Update the V8086 EFlags state */ 00303 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK); 00304 KiVdmSetVdmEFlags(V86EFlags); 00305 00306 /* Build flat EIP and check if this is the BOP instruction */ 00307 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip; 00308 if (*(PUSHORT)Eip == 0xC4C4) 00309 { 00310 /* Dispatch the BOP */ 00311 VdmDispatchBop(TrapFrame); 00312 } 00313 else 00314 { 00315 /* FIXME: Check for VDM interrupts */ 00316 DPRINT("FIXME: Check for VDM interrupts\n"); 00317 } 00318 00319 /* We're done */ 00320 return TRUE; 00321 } 00322 00323 BOOLEAN 00324 FASTCALL 00325 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame, 00326 IN ULONG Flags) 00327 { 00328 /* Check for VME support */ 00329 ASSERT(KeI386VirtualIntExtensions == FALSE); 00330 00331 /* Disable interrupts */ 00332 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK); 00333 00334 /* Skip instruction */ 00335 TrapFrame->Eip += KiVdmGetInstructionSize(Flags); 00336 00337 /* Done */ 00338 return TRUE; 00339 } 00340 00341 BOOLEAN 00342 FASTCALL 00343 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame, 00344 IN ULONG Flags) 00345 { 00346 /* Check for VME support */ 00347 ASSERT(KeI386VirtualIntExtensions == FALSE); 00348 00349 /* Enable interrupts */ 00350 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK); 00351 00352 /* Skip instruction */ 00353 TrapFrame->Eip += KiVdmGetInstructionSize(Flags); 00354 00355 /* Done */ 00356 return TRUE; 00357 } 00358 00359 /* MASTER OPCODE HANDLER ******************************************************/ 00360 00361 BOOLEAN 00362 FASTCALL 00363 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame, 00364 IN ULONG Flags) 00365 { 00366 ULONG Eip; 00367 00368 /* Get flat EIP of the *current* instruction (not the original EIP) */ 00369 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip; 00370 Eip += KiVdmGetInstructionSize(Flags) - 1; 00371 00372 /* Read the opcode entry */ 00373 switch (*(PUCHAR)Eip) 00374 { 00375 case 0xF: return KiCallVdmHandler(F); 00376 case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES); 00377 case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS); 00378 case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS); 00379 case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS); 00380 case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS); 00381 case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS); 00382 case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32); 00383 case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32); 00384 case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK); 00385 case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE); 00386 case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP); 00387 case 0x6C: return KiCallVdmHandler(INSB); 00388 case 0x6D: return KiCallVdmHandler(INSW); 00389 case 0x6E: return KiCallVdmHandler(OUTSB); 00390 case 0x6F: return KiCallVdmHandler(OUTSW); 00391 case 0x98: return KiCallVdmHandler(NPX); 00392 case 0xD8: return KiCallVdmHandler(NPX); 00393 case 0xD9: return KiCallVdmHandler(NPX); 00394 case 0xDA: return KiCallVdmHandler(NPX); 00395 case 0xDB: return KiCallVdmHandler(NPX); 00396 case 0xDC: return KiCallVdmHandler(NPX); 00397 case 0xDD: return KiCallVdmHandler(NPX); 00398 case 0xDE: return KiCallVdmHandler(NPX); 00399 case 0xDF: return KiCallVdmHandler(NPX); 00400 case 0x9C: return KiCallVdmHandler(PUSHF); 00401 case 0x9D: return KiCallVdmHandler(POPF); 00402 case 0xCD: return KiCallVdmHandler(INTnn); 00403 case 0xCE: return KiCallVdmHandler(INTO); 00404 case 0xCF: return KiCallVdmHandler(IRET); 00405 case 0xE4: return KiCallVdmHandler(INBimm); 00406 case 0xE5: return KiCallVdmHandler(INWimm); 00407 case 0xE6: return KiCallVdmHandler(OUTBimm); 00408 case 0xE7: return KiCallVdmHandler(OUTWimm); 00409 case 0xEC: return KiCallVdmHandler(INB); 00410 case 0xED: return KiCallVdmHandler(INW); 00411 case 0xEE: return KiCallVdmHandler(OUTB); 00412 case 0xEF: return KiCallVdmHandler(OUTW); 00413 case 0xF4: return KiCallVdmHandler(HLT); 00414 case 0xFA: return KiCallVdmHandler(CLI); 00415 case 0xFB: return KiCallVdmHandler(STI); 00416 default: return KiCallVdmHandler(INV); 00417 } 00418 } 00419 00420 /* PREFIX HANDLER *************************************************************/ 00421 00422 BOOLEAN 00423 FASTCALL 00424 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame, 00425 IN ULONG Flags) 00426 { 00427 /* Increase instruction size */ 00428 Flags++; 00429 00430 /* Handle the next opcode */ 00431 return KiVdmHandleOpcode(TrapFrame, Flags); 00432 } 00433 00434 /* TRAP HANDLER ***************************************************************/ 00435 00436 BOOLEAN 00437 FASTCALL 00438 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame) 00439 { 00440 /* Clean up */ 00441 TrapFrame->Eip &= 0xFFFF; 00442 TrapFrame->HardwareEsp &= 0xFFFF; 00443 00444 /* We start with only 1 byte per instruction */ 00445 return KiVdmHandleOpcode(TrapFrame, 1); 00446 } 00447 00448 ULONG_PTR 00449 FASTCALL 00450 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame) 00451 { 00452 PKV8086_STACK_FRAME StackFrame; 00453 PKGDTENTRY GdtEntry; 00454 PKTHREAD Thread; 00455 PKTRAP_FRAME PmTrapFrame; 00456 PKV86_FRAME V86Frame; 00457 PFX_SAVE_AREA NpxFrame; 00458 00459 /* Get the stack frame back */ 00460 StackFrame = CONTAINING_RECORD(TrapFrame->Esi, KV8086_STACK_FRAME, V86Frame); 00461 PmTrapFrame = &StackFrame->TrapFrame; 00462 V86Frame = &StackFrame->V86Frame; 00463 NpxFrame = &StackFrame->NpxArea; 00464 00465 /* Copy the FPU frame back */ 00466 Thread = KeGetCurrentThread(); 00467 RtlCopyMemory(KiGetThreadNpxArea(Thread), NpxFrame, sizeof(FX_SAVE_AREA)); 00468 00469 /* Set initial stack back */ 00470 Thread->InitialStack = (PVOID)((ULONG_PTR)V86Frame->ThreadStack + sizeof(FX_SAVE_AREA)); 00471 00472 /* Set ESP0 back in the KTSS */ 00473 KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&PmTrapFrame->V86Es; 00474 00475 /* Restore TEB addresses */ 00476 Thread->Teb = V86Frame->ThreadTeb; 00477 KeGetPcr()->NtTib.Self = V86Frame->PcrTeb; 00478 00479 /* Setup real TEB descriptor */ 00480 GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)]; 00481 GdtEntry->BaseLow = (USHORT)((ULONG_PTR)Thread->Teb & 0xFFFF); 00482 GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Thread->Teb >> 16); 00483 GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Thread->Teb >> 24); 00484 00485 /* Enable interrupts and return a pointer to the trap frame */ 00486 _enable(); 00487 return (ULONG)PmTrapFrame; 00488 } 00489 00490 VOID 00491 FASTCALL 00492 KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame) 00493 { 00494 PKTHREAD Thread; 00495 PKGDTENTRY GdtEntry; 00496 PKTRAP_FRAME TrapFrame = &StackFrame->TrapFrame; 00497 PKV86_FRAME V86Frame = &StackFrame->V86Frame; 00498 PFX_SAVE_AREA NpxFrame = &StackFrame->NpxArea; 00499 00500 /* Build fake user-mode trap frame */ 00501 TrapFrame->SegCs = KGDT_R0_CODE | RPL_MASK; 00502 TrapFrame->SegEs = TrapFrame->SegDs = TrapFrame->SegFs = TrapFrame->SegGs = 0; 00503 TrapFrame->ErrCode = 0; 00504 00505 /* Get the current thread's initial stack */ 00506 Thread = KeGetCurrentThread(); 00507 V86Frame->ThreadStack = KiGetThreadNpxArea(Thread); 00508 00509 /* Save TEB addresses */ 00510 V86Frame->ThreadTeb = Thread->Teb; 00511 V86Frame->PcrTeb = KeGetPcr()->NtTib.Self; 00512 00513 /* Save return EIP */ 00514 TrapFrame->Eip = (ULONG_PTR)Ki386BiosCallReturnAddress; 00515 00516 /* Save our stack (after the frames) */ 00517 TrapFrame->Esi = (ULONG_PTR)V86Frame; 00518 TrapFrame->Edi = (ULONG_PTR)_AddressOfReturnAddress() + 4; 00519 00520 /* Sanitize EFlags and enable interrupts */ 00521 TrapFrame->EFlags = __readeflags() & 0x60DD7; 00522 TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK; 00523 00524 /* Fill out the rest of the frame */ 00525 TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK; 00526 TrapFrame->HardwareEsp = 0x11FFE; 00527 TrapFrame->ExceptionList = EXCEPTION_CHAIN_END; 00528 TrapFrame->Dr7 = 0; 00529 00530 /* Set some debug fields if trap debugging is enabled */ 00531 KiFillTrapFrameDebug(TrapFrame); 00532 00533 /* Disable interrupts */ 00534 _disable(); 00535 00536 /* Copy the thread's NPX frame */ 00537 RtlCopyMemory(NpxFrame, V86Frame->ThreadStack, sizeof(FX_SAVE_AREA)); 00538 00539 /* Clear exception list */ 00540 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 00541 00542 /* Set new ESP0 */ 00543 KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&TrapFrame->V86Es; 00544 00545 /* Set new initial stack */ 00546 Thread->InitialStack = V86Frame; 00547 00548 /* Set VDM TEB */ 00549 Thread->Teb = (PTEB)TRAMPOLINE_TEB; 00550 KeGetPcr()->NtTib.Self = (PVOID)TRAMPOLINE_TEB; 00551 00552 /* Setup VDM TEB descriptor */ 00553 GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)]; 00554 GdtEntry->BaseLow = (USHORT)((ULONG_PTR)TRAMPOLINE_TEB & 0xFFFF); 00555 GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 16); 00556 GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 24); 00557 00558 /* Enable interrupts */ 00559 _enable(); 00560 00561 /* Start VDM execution */ 00562 NtVdmControl(VdmStartExecution, NULL); 00563 00564 /* Exit to V86 mode */ 00565 KiEoiHelper(TrapFrame); 00566 } 00567 00568 VOID 00569 NTAPI 00570 Ke386SetIOPL(VOID) 00571 { 00572 00573 PKTHREAD Thread = KeGetCurrentThread(); 00574 PKPROCESS Process = Thread->ApcState.Process; 00575 PKTRAP_FRAME TrapFrame; 00576 CONTEXT Context; 00577 00578 /* IOPL was enabled for this process/thread */ 00579 Process->Iopl = TRUE; 00580 Thread->Iopl = TRUE; 00581 00582 /* Get the trap frame on exit */ 00583 TrapFrame = KeGetTrapFrame(Thread); 00584 00585 /* Convert to a context */ 00586 Context.ContextFlags = CONTEXT_CONTROL; 00587 KeTrapFrameToContext(TrapFrame, NULL, &Context); 00588 00589 /* Set the IOPL flag */ 00590 Context.EFlags |= EFLAGS_IOPL; 00591 00592 /* Convert back to a trap frame */ 00593 KeContextToTrapFrame(&Context, NULL, TrapFrame, CONTEXT_CONTROL, UserMode); 00594 } 00595 00596 /* PUBLIC FUNCTIONS ***********************************************************/ 00597 00598 /* 00599 * @implemented 00600 */ 00601 NTSTATUS 00602 NTAPI 00603 Ke386CallBios(IN ULONG Int, 00604 OUT PCONTEXT Context) 00605 { 00606 PUCHAR Trampoline = (PUCHAR)TRAMPOLINE_BASE; 00607 PTEB VdmTeb = (PTEB)TRAMPOLINE_TEB; 00608 PVDM_TIB VdmTib = (PVDM_TIB)TRAMPOLINE_TIB; 00609 ULONG ContextSize = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 00610 PKTHREAD Thread = KeGetCurrentThread(); 00611 PKTSS Tss = KeGetPcr()->TSS; 00612 PKPROCESS Process = Thread->ApcState.Process; 00613 PVDM_PROCESS_OBJECTS VdmProcessObjects; 00614 USHORT OldOffset, OldBase; 00615 00616 /* Start with a clean TEB */ 00617 RtlZeroMemory(VdmTeb, sizeof(TEB)); 00618 00619 /* Write the interrupt and bop */ 00620 *Trampoline++ = 0xCD; 00621 *Trampoline++ = (UCHAR)Int; 00622 *(PULONG)Trampoline = TRAMPOLINE_BOP; 00623 00624 /* Setup the VDM TEB and TIB */ 00625 VdmTeb->Vdm = (PVOID)TRAMPOLINE_TIB; 00626 RtlZeroMemory(VdmTib, sizeof(VDM_TIB)); 00627 VdmTib->Size = sizeof(VDM_TIB); 00628 00629 /* Set a blank VDM state */ 00630 *VdmState = 0; 00631 00632 /* Copy the context */ 00633 RtlCopyMemory(&VdmTib->VdmContext, Context, ContextSize); 00634 VdmTib->VdmContext.SegCs = (ULONG_PTR)Trampoline >> 4; 00635 VdmTib->VdmContext.SegSs = (ULONG_PTR)Trampoline >> 4; 00636 VdmTib->VdmContext.Eip = 0; 00637 VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG_PTR); 00638 VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; 00639 VdmTib->VdmContext.ContextFlags = CONTEXT_FULL; 00640 00641 /* This can't be a real VDM process */ 00642 ASSERT(PsGetCurrentProcess()->VdmObjects == NULL); 00643 00644 /* Allocate VDM structure */ 00645 VdmProcessObjects = ExAllocatePoolWithTag(NonPagedPool, 00646 sizeof(VDM_PROCESS_OBJECTS), 00647 ' eK'); 00648 if (!VdmProcessObjects) return STATUS_NO_MEMORY; 00649 00650 /* Set it up */ 00651 RtlZeroMemory(VdmProcessObjects, sizeof(VDM_PROCESS_OBJECTS)); 00652 VdmProcessObjects->VdmTib = VdmTib; 00653 PsGetCurrentProcess()->VdmObjects = VdmProcessObjects; 00654 00655 /* Set the system affinity for the current thread */ 00656 KeSetSystemAffinityThread(1); 00657 00658 /* Make sure there's space for two IOPMs, then copy & clear the current */ 00659 ASSERT(((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / 8].LimitLow >= 00660 (0x2000 + IOPM_OFFSET - 1)); 00661 RtlCopyMemory(Ki386IopmSaveArea, &Tss->IoMaps[0].IoMap, PAGE_SIZE * 2); 00662 RtlZeroMemory(&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2); 00663 00664 /* Save the old offset and base, and set the new ones */ 00665 OldOffset = Process->IopmOffset; 00666 OldBase = Tss->IoMapBase; 00667 Process->IopmOffset = (USHORT)IOPM_OFFSET; 00668 Tss->IoMapBase = (USHORT)IOPM_OFFSET; 00669 00670 /* Switch stacks and work the magic */ 00671 Ki386SetupAndExitToV86Mode(VdmTeb); 00672 00673 /* Restore IOPM */ 00674 RtlCopyMemory(&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, PAGE_SIZE * 2); 00675 Process->IopmOffset = OldOffset; 00676 Tss->IoMapBase = OldBase; 00677 00678 /* Restore affinity */ 00679 KeRevertToUserAffinityThread(); 00680 00681 /* Restore context */ 00682 RtlCopyMemory(Context, &VdmTib->VdmContext, ContextSize); 00683 Context->ContextFlags = CONTEXT_FULL; 00684 00685 /* Free VDM objects */ 00686 ExFreePool(PsGetCurrentProcess()->VdmObjects); 00687 PsGetCurrentProcess()->VdmObjects = NULL; 00688 00689 /* Return status */ 00690 return STATUS_SUCCESS; 00691 } 00692 00693 /* 00694 * @implemented 00695 */ 00696 BOOLEAN 00697 NTAPI 00698 Ke386IoSetAccessProcess(IN PKPROCESS Process, 00699 IN ULONG MapNumber) 00700 { 00701 USHORT MapOffset; 00702 PKPRCB Prcb; 00703 KAFFINITY TargetProcessors; 00704 00705 if(MapNumber > IOPM_COUNT) 00706 return FALSE; 00707 00708 MapOffset = KiComputeIopmOffset(MapNumber); 00709 00710 Process->IopmOffset = MapOffset; 00711 00712 TargetProcessors = Process->ActiveProcessors; 00713 Prcb = KeGetCurrentPrcb(); 00714 if (TargetProcessors & Prcb->SetMember) 00715 KeGetPcr()->TSS->IoMapBase = MapOffset; 00716 00717 return TRUE; 00718 } 00719 00720 /* 00721 * @implemented 00722 */ 00723 BOOLEAN 00724 NTAPI 00725 Ke386SetIoAccessMap(IN ULONG MapNumber, 00726 IN PKIO_ACCESS_MAP IopmBuffer) 00727 { 00728 PKPROCESS CurrentProcess; 00729 PKPRCB Prcb; 00730 PVOID pt; 00731 00732 if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE)) 00733 return FALSE; 00734 00735 Prcb = KeGetCurrentPrcb(); 00736 00737 // Copy the IOP map and load the map for the current process. 00738 pt = &(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap); 00739 RtlMoveMemory(pt, (PVOID)IopmBuffer, IOPM_SIZE); 00740 CurrentProcess = Prcb->CurrentThread->ApcState.Process; 00741 KeGetPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset; 00742 00743 return TRUE; 00744 } 00745 00746 /* 00747 * @implemented 00748 */ 00749 BOOLEAN 00750 NTAPI 00751 Ke386QueryIoAccessMap(IN ULONG MapNumber, 00752 IN PKIO_ACCESS_MAP IopmBuffer) 00753 { 00754 ULONG i; 00755 PVOID Map; 00756 PUCHAR p; 00757 00758 if (MapNumber > IOPM_COUNT) 00759 return FALSE; 00760 00761 if (MapNumber == IO_ACCESS_MAP_NONE) 00762 { 00763 // no access, simply return a map of all 1s 00764 p = (PUCHAR)IopmBuffer; 00765 for (i = 0; i < IOPM_SIZE; i++) { 00766 p[i] = (UCHAR)-1; 00767 } 00768 } 00769 else 00770 { 00771 // copy the bits 00772 Map = (PVOID)&(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap); 00773 RtlMoveMemory((PVOID)IopmBuffer, Map, IOPM_SIZE); 00774 } 00775 00776 return TRUE; 00777 } Generated on Sun May 27 2012 04:37:32 for ReactOS by
1.7.6.1
|