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 ULONG_PTR StackFrameUnaligned; 471 PKV8086_STACK_FRAME StackFrame; 472 PKTHREAD Thread; 473 PKTRAP_FRAME PmTrapFrame; 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 PmTrapFrame = &StackFrame->TrapFrame; 481 V86Frame = &StackFrame->V86Frame; 482 NpxFrame = &StackFrame->NpxArea; 483 ASSERT((ULONG_PTR)NpxFrame % 16 == 0); 484 485 /* Copy the FPU frame back */ 486 Thread = KeGetCurrentThread(); 487 RtlCopyMemory(KiGetThreadNpxArea(Thread), NpxFrame, sizeof(FX_SAVE_AREA)); 488 489 /* Set initial stack back */ 490 Thread->InitialStack = (PVOID)((ULONG_PTR)V86Frame->ThreadStack + sizeof(FX_SAVE_AREA)); 491 492 /* Set ESP0 back in the KTSS */ 493 KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&PmTrapFrame->V86Es; 494 495 /* Restore TEB addresses */ 496 Thread->Teb = V86Frame->ThreadTeb; 497 KiSetTebBase(KeGetPcr(), V86Frame->ThreadTeb); 498 499 /* Enable interrupts and return a pointer to the trap frame */ 500 _enable(); 501 return StackFrameUnaligned; 502 } 503 504 VOID 505 FASTCALL 506 KiEnterV86Mode(IN ULONG_PTR StackFrameUnaligned) 507 { 508 PKTHREAD Thread; 509 PKV8086_STACK_FRAME StackFrame = (PKV8086_STACK_FRAME)(ROUND_UP(StackFrameUnaligned - 4, 16) + 4); 510 PKTRAP_FRAME TrapFrame = &StackFrame->TrapFrame; 511 PKV86_FRAME V86Frame = &StackFrame->V86Frame; 512 PFX_SAVE_AREA NpxFrame = &StackFrame->NpxArea; 513 514 ASSERT((ULONG_PTR)NpxFrame % 16 == 0); 515 516 /* Build fake user-mode trap frame */ 517 TrapFrame->SegCs = KGDT_R0_CODE | RPL_MASK; 518 TrapFrame->SegEs = TrapFrame->SegDs = TrapFrame->SegFs = TrapFrame->SegGs = 0; 519 TrapFrame->ErrCode = 0; 520 521 /* Get the current thread's initial stack */ 522 Thread = KeGetCurrentThread(); 523 V86Frame->ThreadStack = KiGetThreadNpxArea(Thread); 524 525 /* Save TEB addresses */ 526 V86Frame->ThreadTeb = Thread->Teb; 527 V86Frame->PcrTeb = KeGetPcr()->NtTib.Self; 528 529 /* Save return EIP */ 530 TrapFrame->Eip = (ULONG_PTR)Ki386BiosCallReturnAddress; 531 532 /* Save our stack (after the frames) */ 533 TrapFrame->Esi = StackFrameUnaligned; 534 TrapFrame->Edi = (ULONG_PTR)_AddressOfReturnAddress() + 4; 535 536 /* Sanitize EFlags and enable interrupts */ 537 TrapFrame->EFlags = __readeflags() & 0x60DD7; 538 TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK; 539 540 /* Fill out the rest of the frame */ 541 TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK; 542 TrapFrame->HardwareEsp = 0x11FFE; 543 TrapFrame->ExceptionList = EXCEPTION_CHAIN_END; 544 TrapFrame->Dr7 = 0; 545 546 /* Set some debug fields if trap debugging is enabled */ 547 KiFillTrapFrameDebug(TrapFrame); 548 549 /* Disable interrupts */ 550 _disable(); 551 552 /* Copy the thread's NPX frame */ 553 RtlCopyMemory(NpxFrame, V86Frame->ThreadStack, sizeof(FX_SAVE_AREA)); 554 555 /* Clear exception list */ 556 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 557 558 /* Set new ESP0 */ 559 KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&TrapFrame->V86Es; 560 561 /* Set new initial stack */ 562 Thread->InitialStack = V86Frame; 563 564 /* Set VDM TEB */ 565 Thread->Teb = (PTEB)TRAMPOLINE_TEB; 566 KiSetTebBase(KeGetPcr(), (PVOID)TRAMPOLINE_TEB); 567 568 /* Enable interrupts */ 569 _enable(); 570 571 /* Start VDM execution */ 572 NtVdmControl(VdmStartExecution, NULL); 573 574 /* Exit to V86 mode */ 575 KiEoiHelper(TrapFrame); 576 } 577 578 VOID 579 NTAPI 580 Ke386SetIOPL(VOID) 581 { 582 583 PKTHREAD Thread = KeGetCurrentThread(); 584 PKPROCESS Process = Thread->ApcState.Process; 585 PKTRAP_FRAME TrapFrame; 586 CONTEXT Context; 587 588 /* IOPL was enabled for this process/thread */ 589 Process->Iopl = TRUE; 590 Thread->Iopl = TRUE; 591 592 /* Get the trap frame on exit */ 593 TrapFrame = KeGetTrapFrame(Thread); 594 595 /* Convert to a context */ 596 Context.ContextFlags = CONTEXT_CONTROL; 597 KeTrapFrameToContext(TrapFrame, NULL, &Context); 598 599 /* Set the IOPL flag */ 600 Context.EFlags |= EFLAGS_IOPL; 601 602 /* Convert back to a trap frame */ 603 KeContextToTrapFrame(&Context, NULL, TrapFrame, CONTEXT_CONTROL, UserMode); 604 } 605 606 /* PUBLIC FUNCTIONS ***********************************************************/ 607 608 /* 609 * @implemented 610 */ 611 NTSTATUS 612 NTAPI 613 Ke386CallBios(IN ULONG Int, 614 OUT PCONTEXT Context) 615 { 616 PUCHAR Trampoline = (PUCHAR)TRAMPOLINE_BASE; 617 PTEB VdmTeb = (PTEB)TRAMPOLINE_TEB; 618 PVDM_TIB VdmTib = (PVDM_TIB)TRAMPOLINE_TIB; 619 ULONG ContextSize = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 620 PKTHREAD Thread = KeGetCurrentThread(); 621 PKTSS Tss = KeGetPcr()->TSS; 622 PKPROCESS Process = Thread->ApcState.Process; 623 PVDM_PROCESS_OBJECTS VdmProcessObjects; 624 USHORT OldOffset, OldBase; 625 626 /* Start with a clean TEB */ 627 RtlZeroMemory(VdmTeb, sizeof(TEB)); 628 629 /* Write the interrupt and bop */ 630 *Trampoline++ = 0xCD; 631 *Trampoline++ = (UCHAR)Int; 632 *(PULONG)Trampoline = TRAMPOLINE_BOP; 633 634 /* Setup the VDM TEB and TIB */ 635 VdmTeb->Vdm = (PVOID)TRAMPOLINE_TIB; 636 RtlZeroMemory(VdmTib, sizeof(VDM_TIB)); 637 VdmTib->Size = sizeof(VDM_TIB); 638 639 /* Set a blank VDM state */ 640 *VdmState = 0; 641 642 /* Copy the context */ 643 RtlCopyMemory(&VdmTib->VdmContext, Context, ContextSize); 644 VdmTib->VdmContext.SegCs = (ULONG_PTR)Trampoline >> 4; 645 VdmTib->VdmContext.SegSs = (ULONG_PTR)Trampoline >> 4; 646 VdmTib->VdmContext.Eip = 0; 647 VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG_PTR); 648 VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; 649 VdmTib->VdmContext.ContextFlags = CONTEXT_FULL; 650 651 /* This can't be a real VDM process */ 652 ASSERT(PsGetCurrentProcess()->VdmObjects == NULL); 653 654 /* Allocate VDM structure */ 655 VdmProcessObjects = ExAllocatePoolWithTag(NonPagedPool, 656 sizeof(VDM_PROCESS_OBJECTS), 657 ' eK'); 658 if (!VdmProcessObjects) return STATUS_NO_MEMORY; 659 660 /* Set it up */ 661 RtlZeroMemory(VdmProcessObjects, sizeof(VDM_PROCESS_OBJECTS)); 662 VdmProcessObjects->VdmTib = VdmTib; 663 PsGetCurrentProcess()->VdmObjects = VdmProcessObjects; 664 665 /* Set the system affinity for the current thread */ 666 KeSetSystemAffinityThread(1); 667 668 /* Make sure there's space for two IOPMs, then copy & clear the current */ 669 ASSERT(((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / 8].LimitLow >= 670 (0x2000 + IOPM_OFFSET - 1)); 671 RtlCopyMemory(Ki386IopmSaveArea, &Tss->IoMaps[0].IoMap, PAGE_SIZE * 2); 672 RtlZeroMemory(&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2); 673 674 /* Save the old offset and base, and set the new ones */ 675 OldOffset = Process->IopmOffset; 676 OldBase = Tss->IoMapBase; 677 Process->IopmOffset = (USHORT)IOPM_OFFSET; 678 Tss->IoMapBase = (USHORT)IOPM_OFFSET; 679 680 /* Switch stacks and work the magic */ 681 Ki386SetupAndExitToV86Mode(VdmTeb); 682 683 /* Restore IOPM */ 684 RtlCopyMemory(&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, PAGE_SIZE * 2); 685 Process->IopmOffset = OldOffset; 686 Tss->IoMapBase = OldBase; 687 688 /* Restore affinity */ 689 KeRevertToUserAffinityThread(); 690 691 /* Restore context */ 692 RtlCopyMemory(Context, &VdmTib->VdmContext, ContextSize); 693 Context->ContextFlags = CONTEXT_FULL; 694 695 /* Free VDM objects */ 696 ExFreePoolWithTag(PsGetCurrentProcess()->VdmObjects, ' eK'); 697 PsGetCurrentProcess()->VdmObjects = NULL; 698 699 /* Return status */ 700 return STATUS_SUCCESS; 701 } 702 703 /* 704 * @implemented 705 */ 706 BOOLEAN 707 NTAPI 708 Ke386IoSetAccessProcess(IN PKPROCESS Process, 709 IN ULONG MapNumber) 710 { 711 USHORT MapOffset; 712 PKPRCB Prcb; 713 KAFFINITY TargetProcessors; 714 715 if(MapNumber > IOPM_COUNT) 716 return FALSE; 717 718 MapOffset = KiComputeIopmOffset(MapNumber); 719 720 Process->IopmOffset = MapOffset; 721 722 TargetProcessors = Process->ActiveProcessors; 723 Prcb = KeGetCurrentPrcb(); 724 if (TargetProcessors & Prcb->SetMember) 725 KeGetPcr()->TSS->IoMapBase = MapOffset; 726 727 return TRUE; 728 } 729 730 /* 731 * @implemented 732 */ 733 BOOLEAN 734 NTAPI 735 Ke386SetIoAccessMap(IN ULONG MapNumber, 736 IN PKIO_ACCESS_MAP IopmBuffer) 737 { 738 PKPROCESS CurrentProcess; 739 PKPRCB Prcb; 740 PVOID pt; 741 742 if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE)) 743 return FALSE; 744 745 Prcb = KeGetCurrentPrcb(); 746 747 // Copy the IOP map and load the map for the current process. 748 pt = &(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap); 749 RtlMoveMemory(pt, (PVOID)IopmBuffer, IOPM_SIZE); 750 CurrentProcess = Prcb->CurrentThread->ApcState.Process; 751 KeGetPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset; 752 753 return TRUE; 754 } 755 756 /* 757 * @implemented 758 */ 759 BOOLEAN 760 NTAPI 761 Ke386QueryIoAccessMap(IN ULONG MapNumber, 762 IN PKIO_ACCESS_MAP IopmBuffer) 763 { 764 ULONG i; 765 PVOID Map; 766 PUCHAR p; 767 768 if (MapNumber > IOPM_COUNT) 769 return FALSE; 770 771 if (MapNumber == IO_ACCESS_MAP_NONE) 772 { 773 // no access, simply return a map of all 1s 774 p = (PUCHAR)IopmBuffer; 775 for (i = 0; i < IOPM_SIZE; i++) { 776 p[i] = (UCHAR)-1; 777 } 778 } 779 else 780 { 781 // copy the bits 782 Map = (PVOID)&(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap); 783 RtlMoveMemory((PVOID)IopmBuffer, Map, IOPM_SIZE); 784 } 785 786 return TRUE; 787 } 788