1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/ke/i386/v86vdm.c 5 * PURPOSE: V8086 and VDM Trap Emulation 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 * Alex Ionescu (alex.ionescu@reactos.org) 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 #define KiVdmGetInstructionSize(x) ((x) & 0xFF) 17 #define KiVdmGetPrefixFlags(x) ((x) & 0xFFFFFF00) 18 19 /* GLOBALS ********************************************************************/ 20 21 ULONG KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE; 22 ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK; 23 PVOID Ki386IopmSaveArea; 24 BOOLEAN KeI386VirtualIntExtensions = FALSE; 25 const PULONG KiNtVdmState = (PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT; 26 27 /* UNHANDLED OPCODES **********************************************************/ 28 29 KiVdmUnhandledOpcode(F); 30 KiVdmUnhandledOpcode(OUTSW); 31 KiVdmUnhandledOpcode(OUTSB); 32 KiVdmUnhandledOpcode(INSB); 33 KiVdmUnhandledOpcode(INSW); 34 KiVdmUnhandledOpcode(NPX); 35 KiVdmUnhandledOpcode(INBimm); 36 KiVdmUnhandledOpcode(INWimm); 37 KiVdmUnhandledOpcode(OUTBimm); 38 KiVdmUnhandledOpcode(OUTWimm); 39 KiVdmUnhandledOpcode(INB); 40 KiVdmUnhandledOpcode(INW); 41 KiVdmUnhandledOpcode(OUTB); 42 KiVdmUnhandledOpcode(OUTW); 43 KiVdmUnhandledOpcode(HLT); 44 KiVdmUnhandledOpcode(INTO); 45 KiVdmUnhandledOpcode(INV); 46 47 /* OPCODE HANDLERS ************************************************************/ 48 49 BOOLEAN 50 FASTCALL 51 KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame, 52 IN ULONG Flags) 53 { 54 ULONG Esp, V86EFlags, TrapEFlags; 55 56 /* Get current V8086 flags and mask out interrupt flag */ 57 V86EFlags = *KiNtVdmState; 58 V86EFlags &= ~EFLAGS_INTERRUPT_MASK; 59 60 /* Get trap frame EFLags */ 61 TrapEFlags = TrapFrame->EFlags; 62 /* Check for VME support */ 63 if(KeI386VirtualIntExtensions) 64 { 65 /* Copy the virtual interrupt flag to the interrupt flag */ 66 TrapEFlags &= ~EFLAGS_INTERRUPT_MASK; 67 if(TrapEFlags & EFLAGS_VIF) 68 TrapEFlags |= EFLAGS_INTERRUPT_MASK; 69 } 70 /* Leave only align, nested task and interrupt */ 71 TrapEFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); 72 73 /* Add in those flags if they exist, and add in the IOPL flag */ 74 V86EFlags |= TrapEFlags; 75 V86EFlags |= EFLAGS_IOPL; 76 77 /* Build flat ESP */ 78 Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp; 79 80 /* Check for OPER32 */ 81 if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32) 82 { 83 /* Save EFlags */ 84 Esp -= 4; 85 *(PULONG)Esp = V86EFlags; 86 } 87 else 88 { 89 /* Save EFLags */ 90 Esp -= 2; 91 *(PUSHORT)Esp = (USHORT)V86EFlags; 92 } 93 94 /* Set new ESP and EIP */ 95 TrapFrame->HardwareEsp = Esp - (TrapFrame->HardwareSegSs << 4); 96 TrapFrame->Eip += KiVdmGetInstructionSize(Flags); 97 98 /* We're done */ 99 return TRUE; 100 } 101 102 BOOLEAN 103 FASTCALL 104 KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame, 105 IN ULONG Flags) 106 { 107 ULONG Esp, V86EFlags, EFlags, TrapEFlags; 108 109 /* Build flat ESP */ 110 Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp; 111 112 /* Check for OPER32 */ 113 if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32) 114 { 115 /* Read EFlags */ 116 EFlags = *(PULONG)Esp; 117 Esp += 4; 118 } 119 else 120 { 121 /* Read EFlags */ 122 EFlags = *(PUSHORT)Esp; 123 Esp += 2; 124 } 125 126 /* Set new ESP */ 127 TrapFrame->HardwareEsp = Esp - (TrapFrame->HardwareSegSs << 4); 128 129 /* Mask out IOPL from the flags */ 130 EFlags &= ~EFLAGS_IOPL; 131 132 /* Save the V86 flags, but mask out the nested task flag */ 133 V86EFlags = EFlags & ~EFLAGS_NESTED_TASK; 134 135 /* Now leave only alignment, nested task and interrupt flag */ 136 EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); 137 138 /* Get trap EFlags */ 139 TrapEFlags = TrapFrame->EFlags; 140 141 /* Check for VME support */ 142 if(KeI386VirtualIntExtensions) 143 { 144 /* Copy the IF flag into the VIF one */ 145 V86EFlags &= ~EFLAGS_VIF; 146 if(V86EFlags & EFLAGS_INTERRUPT_MASK) 147 { 148 V86EFlags |= EFLAGS_VIF; 149 /* Don't set the interrupt flag */ 150 V86EFlags &= ~EFLAGS_INTERRUPT_MASK; 151 } 152 } 153 154 /* Add V86 flag */ 155 V86EFlags |= EFLAGS_V86_MASK; 156 157 /* Update EFlags in trap frame */ 158 TrapFrame->EFlags |= V86EFlags; 159 160 /* Check if ESP0 needs to be fixed up */ 161 if (TrapEFlags & EFLAGS_V86_MASK) Ki386AdjustEsp0(TrapFrame); 162 163 /* Update the V8086 EFlags state */ 164 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); 165 KiVdmSetVdmEFlags(EFlags); 166 167 /* FIXME: Check for VDM interrupts */ 168 169 /* Update EIP */ 170 TrapFrame->Eip += KiVdmGetInstructionSize(Flags); 171 172 /* We're done */ 173 return TRUE; 174 } 175 176 BOOLEAN 177 FASTCALL 178 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame, 179 IN ULONG Flags) 180 { 181 ULONG Esp, V86EFlags, TrapEFlags, Eip, Interrupt; 182 183 /* Read trap frame EFlags */ 184 TrapEFlags = TrapFrame->EFlags; 185 186 /* Remove interrupt flag from V8086 EFlags */ 187 V86EFlags = *KiNtVdmState; 188 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK); 189 190 /* Keep only alignment and interrupt flag from the V8086 state */ 191 V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_INTERRUPT_MASK); 192 193 /* Check for VME support */ 194 ASSERT(KeI386VirtualIntExtensions == FALSE); 195 196 /* Mask in the relevant V86 EFlags into the trap flags */ 197 V86EFlags |= (TrapEFlags & ~EFLAGS_INTERRUPT_MASK); 198 199 /* And mask out the VIF, nested task and TF flag from the trap flags */ 200 TrapFrame->EFlags = TrapEFlags &~ (EFLAGS_VIF | EFLAGS_NESTED_TASK | EFLAGS_TF); 201 202 /* Add the IOPL flag to the local trap flags */ 203 V86EFlags |= EFLAGS_IOPL; 204 205 /* Build flat ESP */ 206 Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp; 207 208 /* Push EFlags */ 209 Esp -= 2; 210 *(PUSHORT)(Esp) = (USHORT)V86EFlags; 211 212 /* Push CS */ 213 Esp -= 2; 214 *(PUSHORT)(Esp) = (USHORT)TrapFrame->SegCs; 215 216 /* Push IP */ 217 Esp -= 2; 218 *(PUSHORT)(Esp) = (USHORT)TrapFrame->Eip + KiVdmGetInstructionSize(Flags) + 1; 219 220 /* Update ESP */ 221 TrapFrame->HardwareEsp = (USHORT)Esp; 222 223 /* Get flat EIP */ 224 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip; 225 226 /* Now get the *next* EIP address (current is original + the count - 1) */ 227 Eip += KiVdmGetInstructionSize(Flags); 228 229 /* Now read the interrupt number */ 230 Interrupt = *(PUCHAR)Eip; 231 232 /* Read the EIP from its IVT entry */ 233 Interrupt = *(PULONG)(Interrupt * 4); 234 TrapFrame->Eip = (USHORT)Interrupt; 235 236 /* Now get the CS segment */ 237 Interrupt = (USHORT)(Interrupt >> 16); 238 239 /* Check if the trap was not V8086 trap */ 240 if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) 241 { 242 /* Was it a kernel CS? */ 243 Interrupt |= RPL_MASK; 244 if (TrapFrame->SegCs == KGDT_R0_CODE) 245 { 246 /* Add the RPL mask */ 247 TrapFrame->SegCs = Interrupt; 248 } 249 else 250 { 251 /* Set user CS */ 252 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK; 253 } 254 } 255 else 256 { 257 /* Set IVT CS */ 258 TrapFrame->SegCs = Interrupt; 259 } 260 261 /* We're done */ 262 return TRUE; 263 } 264 265 BOOLEAN 266 FASTCALL 267 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame, 268 IN ULONG Flags) 269 { 270 ULONG Esp, V86EFlags, EFlags, TrapEFlags, Eip; 271 272 /* Build flat ESP */ 273 Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp; 274 275 /* Check for OPER32 */ 276 if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32) 277 { 278 /* Build segmented EIP */ 279 TrapFrame->Eip = *(PULONG)Esp; 280 TrapFrame->SegCs = *(PUSHORT)(Esp + 4); 281 282 /* Set new ESP */ 283 TrapFrame->HardwareEsp += 12; 284 285 /* Get EFLAGS */ 286 EFlags = *(PULONG)(Esp + 8); 287 } 288 else 289 { 290 /* Build segmented EIP */ 291 TrapFrame->Eip = *(PUSHORT)Esp; 292 TrapFrame->SegCs = *(PUSHORT)(Esp + 2); 293 294 /* Set new ESP */ 295 TrapFrame->HardwareEsp += 6; 296 297 /* Get EFLAGS */ 298 EFlags = *(PUSHORT)(Esp + 4); 299 } 300 301 /* Mask out EFlags */ 302 EFlags &= ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP); 303 V86EFlags = EFlags; 304 305 /* Check for VME support */ 306 ASSERT(KeI386VirtualIntExtensions == FALSE); 307 308 /* Add V86 and Interrupt flag */ 309 EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; 310 311 /* Update EFlags in trap frame */ 312 TrapEFlags = TrapFrame->EFlags; 313 TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | EFlags; 314 315 /* Check if ESP0 needs to be fixed up */ 316 if (!(TrapEFlags & EFLAGS_V86_MASK)) Ki386AdjustEsp0(TrapFrame); 317 318 /* Update the V8086 EFlags state */ 319 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK); 320 KiVdmSetVdmEFlags(V86EFlags); 321 322 /* Build flat EIP and check if this is the BOP instruction */ 323 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip; 324 if (*(PUSHORT)Eip == 0xC4C4) 325 { 326 /* Dispatch the BOP */ 327 VdmDispatchBop(TrapFrame); 328 } 329 else 330 { 331 /* FIXME: Check for VDM interrupts */ 332 DPRINT("FIXME: Check for VDM interrupts\n"); 333 } 334 335 /* We're done */ 336 return TRUE; 337 } 338 339 BOOLEAN 340 FASTCALL 341 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame, 342 IN ULONG Flags) 343 { 344 /* Check for VME support */ 345 ASSERT(KeI386VirtualIntExtensions == FALSE); 346 347 /* Disable interrupts */ 348 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK); 349 350 /* Skip instruction */ 351 TrapFrame->Eip += KiVdmGetInstructionSize(Flags); 352 353 /* Done */ 354 return TRUE; 355 } 356 357 BOOLEAN 358 FASTCALL 359 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame, 360 IN ULONG Flags) 361 { 362 /* Check for VME support */ 363 ASSERT(KeI386VirtualIntExtensions == FALSE); 364 365 /* Enable interrupts */ 366 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK); 367 368 /* Skip instruction */ 369 TrapFrame->Eip += KiVdmGetInstructionSize(Flags); 370 371 /* Done */ 372 return TRUE; 373 } 374 375 /* MASTER OPCODE HANDLER ******************************************************/ 376 377 BOOLEAN 378 FASTCALL 379 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame, 380 IN ULONG Flags) 381 { 382 ULONG Eip; 383 384 /* Get flat EIP of the *current* instruction (not the original EIP) */ 385 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip; 386 Eip += KiVdmGetInstructionSize(Flags) - 1; 387 388 /* Read the opcode entry */ 389 switch (*(PUCHAR)Eip) 390 { 391 case 0xF: return KiCallVdmHandler(F); 392 case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES); 393 case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS); 394 case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS); 395 case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS); 396 case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS); 397 case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS); 398 case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32); 399 case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32); 400 case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK); 401 case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE); 402 case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP); 403 case 0x6C: return KiCallVdmHandler(INSB); 404 case 0x6D: return KiCallVdmHandler(INSW); 405 case 0x6E: return KiCallVdmHandler(OUTSB); 406 case 0x6F: return KiCallVdmHandler(OUTSW); 407 case 0x98: return KiCallVdmHandler(NPX); 408 case 0xD8: return KiCallVdmHandler(NPX); 409 case 0xD9: return KiCallVdmHandler(NPX); 410 case 0xDA: return KiCallVdmHandler(NPX); 411 case 0xDB: return KiCallVdmHandler(NPX); 412 case 0xDC: return KiCallVdmHandler(NPX); 413 case 0xDD: return KiCallVdmHandler(NPX); 414 case 0xDE: return KiCallVdmHandler(NPX); 415 case 0xDF: return KiCallVdmHandler(NPX); 416 case 0x9C: return KiCallVdmHandler(PUSHF); 417 case 0x9D: return KiCallVdmHandler(POPF); 418 case 0xCD: return KiCallVdmHandler(INTnn); 419 case 0xCE: return KiCallVdmHandler(INTO); 420 case 0xCF: return KiCallVdmHandler(IRET); 421 case 0xE4: return KiCallVdmHandler(INBimm); 422 case 0xE5: return KiCallVdmHandler(INWimm); 423 case 0xE6: return KiCallVdmHandler(OUTBimm); 424 case 0xE7: return KiCallVdmHandler(OUTWimm); 425 case 0xEC: return KiCallVdmHandler(INB); 426 case 0xED: return KiCallVdmHandler(INW); 427 case 0xEE: return KiCallVdmHandler(OUTB); 428 case 0xEF: return KiCallVdmHandler(OUTW); 429 case 0xF4: return KiCallVdmHandler(HLT); 430 case 0xFA: return KiCallVdmHandler(CLI); 431 case 0xFB: return KiCallVdmHandler(STI); 432 default: 433 DPRINT1("Unhandled instruction: 0x%02x.\n", *(PUCHAR)Eip); 434 return KiCallVdmHandler(INV); 435 } 436 } 437 438 /* PREFIX HANDLER *************************************************************/ 439 440 BOOLEAN 441 FASTCALL 442 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame, 443 IN ULONG Flags) 444 { 445 /* Increase instruction size */ 446 Flags++; 447 448 /* Handle the next opcode */ 449 return KiVdmHandleOpcode(TrapFrame, Flags); 450 } 451 452 /* TRAP HANDLER ***************************************************************/ 453 454 BOOLEAN 455 FASTCALL 456 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame) 457 { 458 /* Clean up */ 459 TrapFrame->Eip &= 0xFFFF; 460 TrapFrame->HardwareEsp &= 0xFFFF; 461 462 /* We start with only 1 byte per instruction */ 463 return KiVdmHandleOpcode(TrapFrame, 1); 464 } 465 466 ULONG_PTR 467 FASTCALL 468 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame) 469 { 470 PKPCR Pcr = KeGetPcr(); 471 ULONG_PTR StackFrameUnaligned; 472 PKV8086_STACK_FRAME StackFrame; 473 PKTHREAD Thread; 474 PKV86_FRAME V86Frame; 475 PFX_SAVE_AREA NpxFrame; 476 477 /* Get the stack frame back */ 478 StackFrameUnaligned = TrapFrame->Esi; 479 StackFrame = (PKV8086_STACK_FRAME)(ROUND_UP(StackFrameUnaligned - 4, 16) + 4); 480 V86Frame = &StackFrame->V86Frame; 481 NpxFrame = &StackFrame->NpxArea; 482 ASSERT((ULONG_PTR)NpxFrame % 16 == 0); 483 484 /* Copy the FPU frame back */ 485 Thread = KeGetCurrentThread(); 486 RtlCopyMemory(KiGetThreadNpxArea(Thread), NpxFrame, sizeof(FX_SAVE_AREA)); 487 488 /* Set initial stack back */ 489 Thread->InitialStack = (PVOID)((ULONG_PTR)V86Frame->ThreadStack + sizeof(FX_SAVE_AREA)); 490 491 /* Set ESP0 back in the KTSS */ 492 Pcr->TSS->Esp0 = (ULONG_PTR)Thread->InitialStack; 493 Pcr->TSS->Esp0 -= sizeof(KTRAP_FRAME) - FIELD_OFFSET(KTRAP_FRAME, V86Es); 494 Pcr->TSS->Esp0 -= NPX_FRAME_LENGTH; 495 496 /* Restore TEB addresses */ 497 Thread->Teb = V86Frame->ThreadTeb; 498 KiSetTebBase(KeGetPcr(), V86Frame->ThreadTeb); 499 500 /* Enable interrupts and return a pointer to the trap frame */ 501 _enable(); 502 return StackFrameUnaligned; 503 } 504 505 VOID 506 FASTCALL 507 KiEnterV86Mode(IN ULONG_PTR StackFrameUnaligned) 508 { 509 PKTHREAD Thread; 510 PKV8086_STACK_FRAME StackFrame = (PKV8086_STACK_FRAME)(ROUND_UP(StackFrameUnaligned - 4, 16) + 4); 511 PKTRAP_FRAME TrapFrame = &StackFrame->TrapFrame; 512 PKV86_FRAME V86Frame = &StackFrame->V86Frame; 513 PFX_SAVE_AREA NpxFrame = &StackFrame->NpxArea; 514 515 ASSERT((ULONG_PTR)NpxFrame % 16 == 0); 516 517 /* Build fake user-mode trap frame */ 518 TrapFrame->SegCs = KGDT_R0_CODE | RPL_MASK; 519 TrapFrame->SegEs = TrapFrame->SegDs = TrapFrame->SegFs = TrapFrame->SegGs = 0; 520 TrapFrame->ErrCode = 0; 521 522 /* Get the current thread's initial stack */ 523 Thread = KeGetCurrentThread(); 524 V86Frame->ThreadStack = KiGetThreadNpxArea(Thread); 525 526 /* Save TEB addresses */ 527 V86Frame->ThreadTeb = Thread->Teb; 528 V86Frame->PcrTeb = KeGetPcr()->NtTib.Self; 529 530 /* Save return EIP */ 531 TrapFrame->Eip = (ULONG_PTR)Ki386BiosCallReturnAddress; 532 533 /* Save our stack (after the frames) */ 534 TrapFrame->Esi = StackFrameUnaligned; 535 TrapFrame->Edi = (ULONG_PTR)_AddressOfReturnAddress() + 4; 536 537 /* Sanitize EFlags and enable interrupts */ 538 TrapFrame->EFlags = __readeflags() & 0x60DD7; 539 TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK; 540 541 /* Fill out the rest of the frame */ 542 TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK; 543 TrapFrame->HardwareEsp = 0x11FFE; 544 TrapFrame->ExceptionList = EXCEPTION_CHAIN_END; 545 TrapFrame->Dr7 = 0; 546 547 /* Set some debug fields if trap debugging is enabled */ 548 KiFillTrapFrameDebug(TrapFrame); 549 550 /* Disable interrupts */ 551 _disable(); 552 553 /* Copy the thread's NPX frame */ 554 RtlCopyMemory(NpxFrame, V86Frame->ThreadStack, sizeof(FX_SAVE_AREA)); 555 556 /* Clear exception list */ 557 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 558 559 /* Set new ESP0 */ 560 KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&TrapFrame->V86Es; 561 562 /* Set new initial stack */ 563 Thread->InitialStack = V86Frame; 564 565 /* Set VDM TEB */ 566 Thread->Teb = (PTEB)TRAMPOLINE_TEB; 567 KiSetTebBase(KeGetPcr(), (PVOID)TRAMPOLINE_TEB); 568 569 /* Enable interrupts */ 570 _enable(); 571 572 /* Start VDM execution */ 573 NtVdmControl(VdmStartExecution, NULL); 574 575 /* Exit to V86 mode */ 576 KiEoiHelper(TrapFrame); 577 } 578 579 VOID 580 NTAPI 581 Ke386SetIOPL(VOID) 582 { 583 584 PKTHREAD Thread = KeGetCurrentThread(); 585 PKPROCESS Process = Thread->ApcState.Process; 586 PKTRAP_FRAME TrapFrame; 587 CONTEXT Context; 588 589 /* IOPL was enabled for this process/thread */ 590 Process->Iopl = TRUE; 591 Thread->Iopl = TRUE; 592 593 /* Get the trap frame on exit */ 594 TrapFrame = KeGetTrapFrame(Thread); 595 596 /* Convert to a context */ 597 Context.ContextFlags = CONTEXT_CONTROL; 598 KeTrapFrameToContext(TrapFrame, NULL, &Context); 599 600 /* Set the IOPL flag */ 601 Context.EFlags |= EFLAGS_IOPL; 602 603 /* Convert back to a trap frame */ 604 KeContextToTrapFrame(&Context, NULL, TrapFrame, CONTEXT_CONTROL, UserMode); 605 } 606 607 /* PUBLIC FUNCTIONS ***********************************************************/ 608 609 /* 610 * @implemented 611 */ 612 NTSTATUS 613 NTAPI 614 Ke386CallBios(IN ULONG Int, 615 OUT PCONTEXT Context) 616 { 617 PUCHAR Trampoline = (PUCHAR)TRAMPOLINE_BASE; 618 PTEB VdmTeb = (PTEB)TRAMPOLINE_TEB; 619 PVDM_TIB VdmTib = (PVDM_TIB)TRAMPOLINE_TIB; 620 ULONG ContextSize = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 621 PKTHREAD Thread = KeGetCurrentThread(); 622 PKTSS Tss = KeGetPcr()->TSS; 623 PKPROCESS Process = Thread->ApcState.Process; 624 PVDM_PROCESS_OBJECTS VdmProcessObjects; 625 USHORT OldOffset, OldBase; 626 627 /* Start with a clean TEB */ 628 RtlZeroMemory(VdmTeb, sizeof(TEB)); 629 630 /* Write the interrupt and bop */ 631 *Trampoline++ = 0xCD; 632 *Trampoline++ = (UCHAR)Int; 633 *(PULONG)Trampoline = TRAMPOLINE_BOP; 634 635 /* Setup the VDM TEB and TIB */ 636 VdmTeb->Vdm = (PVOID)TRAMPOLINE_TIB; 637 RtlZeroMemory(VdmTib, sizeof(VDM_TIB)); 638 VdmTib->Size = sizeof(VDM_TIB); 639 640 /* Set a blank VDM state */ 641 *VdmState = 0; 642 643 /* Copy the context */ 644 RtlCopyMemory(&VdmTib->VdmContext, Context, ContextSize); 645 VdmTib->VdmContext.SegCs = (ULONG_PTR)Trampoline >> 4; 646 VdmTib->VdmContext.SegSs = (ULONG_PTR)Trampoline >> 4; 647 VdmTib->VdmContext.Eip = 0; 648 VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG_PTR); 649 VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; 650 VdmTib->VdmContext.ContextFlags = CONTEXT_FULL; 651 652 /* This can't be a real VDM process */ 653 ASSERT(PsGetCurrentProcess()->VdmObjects == NULL); 654 655 /* Allocate VDM structure */ 656 VdmProcessObjects = ExAllocatePoolWithTag(NonPagedPool, 657 sizeof(VDM_PROCESS_OBJECTS), 658 ' eK'); 659 if (!VdmProcessObjects) return STATUS_NO_MEMORY; 660 661 /* Set it up */ 662 RtlZeroMemory(VdmProcessObjects, sizeof(VDM_PROCESS_OBJECTS)); 663 VdmProcessObjects->VdmTib = VdmTib; 664 PsGetCurrentProcess()->VdmObjects = VdmProcessObjects; 665 666 /* Set the system affinity for the current thread */ 667 KeSetSystemAffinityThread(1); 668 669 /* Make sure there's space for two IOPMs, then copy & clear the current */ 670 ASSERT(((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / 8].LimitLow >= 671 (0x2000 + IOPM_OFFSET - 1)); 672 RtlCopyMemory(Ki386IopmSaveArea, &Tss->IoMaps[0].IoMap, IOPM_SIZE); 673 RtlZeroMemory(&Tss->IoMaps[0].IoMap, IOPM_SIZE); 674 675 /* Save the old offset and base, and set the new ones */ 676 OldOffset = Process->IopmOffset; 677 OldBase = Tss->IoMapBase; 678 Process->IopmOffset = (USHORT)IOPM_OFFSET; 679 Tss->IoMapBase = (USHORT)IOPM_OFFSET; 680 681 /* Switch stacks and work the magic */ 682 Ki386SetupAndExitToV86Mode(VdmTeb); 683 684 /* Restore IOPM */ 685 RtlCopyMemory(&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, IOPM_SIZE); 686 Process->IopmOffset = OldOffset; 687 Tss->IoMapBase = OldBase; 688 689 /* Restore affinity */ 690 KeRevertToUserAffinityThread(); 691 692 /* Restore context */ 693 RtlCopyMemory(Context, &VdmTib->VdmContext, ContextSize); 694 Context->ContextFlags = CONTEXT_FULL; 695 696 /* Free VDM objects */ 697 ExFreePoolWithTag(PsGetCurrentProcess()->VdmObjects, ' eK'); 698 PsGetCurrentProcess()->VdmObjects = NULL; 699 700 /* Return status */ 701 return STATUS_SUCCESS; 702 } 703 704 /* 705 * @implemented 706 */ 707 BOOLEAN 708 NTAPI 709 Ke386IoSetAccessProcess(IN PKPROCESS Process, 710 IN ULONG MapNumber) 711 { 712 USHORT MapOffset; 713 PKPRCB Prcb; 714 KAFFINITY TargetProcessors; 715 716 if(MapNumber > IOPM_COUNT) 717 return FALSE; 718 719 MapOffset = KiComputeIopmOffset(MapNumber); 720 721 Process->IopmOffset = MapOffset; 722 723 TargetProcessors = Process->ActiveProcessors; 724 Prcb = KeGetCurrentPrcb(); 725 if (TargetProcessors & Prcb->SetMember) 726 KeGetPcr()->TSS->IoMapBase = MapOffset; 727 728 return TRUE; 729 } 730 731 /* 732 * @implemented 733 */ 734 BOOLEAN 735 NTAPI 736 Ke386SetIoAccessMap(IN ULONG MapNumber, 737 IN PKIO_ACCESS_MAP IopmBuffer) 738 { 739 PKPROCESS CurrentProcess; 740 PKPRCB Prcb; 741 PVOID pt; 742 743 if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE)) 744 return FALSE; 745 746 Prcb = KeGetCurrentPrcb(); 747 748 // Copy the IOP map and load the map for the current process. 749 pt = &(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap); 750 RtlMoveMemory(pt, (PVOID)IopmBuffer, IOPM_SIZE); 751 CurrentProcess = Prcb->CurrentThread->ApcState.Process; 752 KeGetPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset; 753 754 return TRUE; 755 } 756 757 /* 758 * @implemented 759 */ 760 BOOLEAN 761 NTAPI 762 Ke386QueryIoAccessMap(IN ULONG MapNumber, 763 IN PKIO_ACCESS_MAP IopmBuffer) 764 { 765 ULONG i; 766 PVOID Map; 767 PUCHAR p; 768 769 if (MapNumber > IOPM_COUNT) 770 return FALSE; 771 772 if (MapNumber == IO_ACCESS_MAP_NONE) 773 { 774 // no access, simply return a map of all 1s 775 p = (PUCHAR)IopmBuffer; 776 for (i = 0; i < IOPM_SIZE; i++) { 777 p[i] = (UCHAR)-1; 778 } 779 } 780 else 781 { 782 // copy the bits 783 Map = (PVOID)&(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap); 784 RtlMoveMemory((PVOID)IopmBuffer, Map, IOPM_SIZE); 785 } 786 787 return TRUE; 788 } 789