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)
10 /* INCLUDES *******************************************************************/
16 #define KiVdmGetInstructionSize(x) ((x) & 0xFF)
17 #define KiVdmGetPrefixFlags(x) ((x) & 0xFFFFFF00)
19 /* GLOBALS ********************************************************************/
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
;
27 /* UNHANDLED OPCODES **********************************************************/
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
);
47 /* OPCODE HANDLERS ************************************************************/
51 KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame
,
54 ULONG Esp
, V86EFlags
, TrapEFlags
;
56 /* Get current V8086 flags and mask out interrupt flag */
57 DbgPrint("VDM: Handling PUSHF (PREFIX [0x%lx])\n", KiVdmGetPrefixFlags(Flags
));
58 V86EFlags
= *KiNtVdmState
;
59 V86EFlags
&= ~EFLAGS_INTERRUPT_MASK
;
61 /* Get trap frame EFLags and leave only align, nested task and interrupt */
62 TrapEFlags
= TrapFrame
->EFlags
;
63 TrapEFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
65 /* Add in those flags if they exist, and add in the IOPL flag */
66 V86EFlags
|= TrapEFlags
;
67 V86EFlags
|= EFLAGS_IOPL
;
70 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + (USHORT
)TrapFrame
->HardwareEsp
;
73 /* Check for OPER32 */
74 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
78 *(PULONG
)(Esp
- 2) = V86EFlags
;
83 *(PUSHORT
)Esp
= (USHORT
)V86EFlags
;
86 /* Set new ESP and EIP */
87 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
88 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
96 KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame
,
99 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
;
102 DbgPrint("VDM: Handling POPF (PREFIX [0x%lx])\n", KiVdmGetPrefixFlags(Flags
));
103 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + (USHORT
)TrapFrame
->HardwareEsp
;
106 EFlags
= *(PULONG
)Esp
;
109 /* Check for OPER32 */
110 if (!(KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
))
112 /* Read correct flags and use correct stack address */
118 TrapFrame
->HardwareEsp
= Esp
;
120 /* Mask out IOPL from the flags */
121 EFlags
&= ~EFLAGS_IOPL
;
123 /* Save the V86 flags, but mask out the nested task flag */
124 V86EFlags
= EFlags
& ~EFLAGS_NESTED_TASK
;
126 /* Now leave only alignment, nested task and interrupt flag */
127 EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
129 /* FIXME: Check for VME support */
131 /* Add V86 and Interrupt flag */
132 V86EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
134 /* Update EFlags in trap frame */
135 TrapEFlags
= TrapFrame
->EFlags
;
136 TrapFrame
->EFlags
= (TrapFrame
->EFlags
& EFLAGS_VIP
) | V86EFlags
;
138 /* Check if ESP0 needs to be fixed up */
139 if (TrapEFlags
& EFLAGS_V86_MASK
) Ki386AdjustEsp0(TrapFrame
);
141 /* Update the V8086 EFlags state */
142 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
143 KiVdmSetVdmEFlags(EFlags
);
145 /* FIXME: Check for VDM interrupts */
148 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
156 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame
,
159 ULONG Esp
, V86EFlags
, TrapEFlags
, Eip
, Interrupt
;
161 /* Read trap frame EFlags */
162 TrapEFlags
= TrapFrame
->EFlags
;
164 /* Remove interrupt flag from V8086 EFlags */
165 V86EFlags
= *KiNtVdmState
;
166 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
168 /* Keep only alignment and interrupt flag from the V8086 state */
169 V86EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_INTERRUPT_MASK
);
171 /* FIXME: Support VME */
173 /* Mask in the relevant V86 EFlags into the trap flags */
174 V86EFlags
|= (TrapEFlags
& ~EFLAGS_INTERRUPT_MASK
);
176 /* And mask out the VIF, nested task and TF flag from the trap flags */
177 TrapFrame
->EFlags
= TrapEFlags
&~ (EFLAGS_VIF
| EFLAGS_NESTED_TASK
| EFLAGS_TF
);
179 /* Add the IOPL flag to the local trap flags */
180 V86EFlags
|= EFLAGS_IOPL
;
183 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
187 *(PUSHORT
)(Esp
) = (USHORT
)V86EFlags
;
191 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->SegCs
;
195 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->Eip
+ KiVdmGetInstructionSize(Flags
) + 1;
198 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
201 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
203 /* Now get the *next* EIP address (current is original + the count - 1) */
204 Eip
+= KiVdmGetInstructionSize(Flags
);
206 /* Now read the interrupt number */
207 Interrupt
= *(PUCHAR
)Eip
;
208 DbgPrint("VDM: Handling INT [0x%lx]\n", Interrupt
);
210 /* Read the EIP from its IVT entry */
211 Interrupt
= *(PULONG
)(Interrupt
* 4);
212 TrapFrame
->Eip
= (USHORT
)Interrupt
;
214 /* Now get the CS segment */
215 Interrupt
= (USHORT
)(Interrupt
>> 16);
217 /* Check if the trap was not V8086 trap */
218 if (!(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
220 /* Was it a kernel CS? */
221 Interrupt
|= RPL_MASK
;
222 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
224 /* Add the RPL mask */
225 TrapFrame
->SegCs
= Interrupt
;
230 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
236 TrapFrame
->SegCs
= Interrupt
;
245 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame
,
248 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
, Eip
;
251 DbgPrint("VDM: Handling IRET (PREFIX [0x%lx])\n", KiVdmGetPrefixFlags(Flags
));
252 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
254 /* Check for OPER32 */
255 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
257 /* Build segmented EIP */
258 TrapFrame
->Eip
= *(PULONG
)Esp
;
259 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 4);
262 TrapFrame
->HardwareEsp
+= 12;
265 EFlags
= *(PULONG
)(Esp
+ 8);
269 /* Build segmented EIP */
270 TrapFrame
->Eip
= *(PUSHORT
)Esp
;
271 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 2);
274 TrapFrame
->HardwareEsp
+= 6;
277 EFlags
= *(PUSHORT
)(Esp
+ 4);
280 /* Mask out EFlags */
281 EFlags
&= ~(EFLAGS_IOPL
+ EFLAGS_VIF
+ EFLAGS_NESTED_TASK
+ EFLAGS_VIP
);
284 /* FIXME: Check for VME support */
286 /* Add V86 and Interrupt flag */
287 EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
289 /* Update EFlags in trap frame */
290 TrapEFlags
= TrapFrame
->EFlags
;
291 TrapFrame
->EFlags
= (TrapFrame
->EFlags
& EFLAGS_VIP
) | EFlags
;
293 /* Check if ESP0 needs to be fixed up */
294 if (!(TrapEFlags
& EFLAGS_V86_MASK
)) Ki386AdjustEsp0(TrapFrame
);
296 /* Update the V8086 EFlags state */
297 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
298 KiVdmSetVdmEFlags(V86EFlags
);
300 /* Build flat EIP and check if this is the BOP instruction */
301 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
302 DbgPrint("VDM: Handling IRET EIP @ 0x%p [OPCODE: %lx]\n", Eip
, *(PUSHORT
)Eip
);
303 if (*(PUSHORT
)Eip
== 0xC4C4)
305 /* Dispatch the BOP */
306 VdmDispatchBop(TrapFrame
);
310 /* FIXME: Check for VDM interrupts */
319 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame
,
322 /* FIXME: Support VME */
324 /* Disable interrupts */
325 DbgPrint("VDM: Handling CLI\n");
326 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
328 /* Skip instruction */
329 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
337 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame
,
340 /* FIXME: Support VME */
342 /* Enable interrupts */
343 DbgPrint("VDM: Handling STI\n");
344 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK
);
346 /* Skip instruction */
347 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
353 /* MASTER OPCODE HANDLER ******************************************************/
357 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame
,
362 /* Get flat EIP of the *current* instruction (not the original EIP) */
363 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
364 DbgPrint("VDM: Handling Opcode @ 0x%p\n", Eip
);
365 Eip
+= KiVdmGetInstructionSize(Flags
) - 1;
367 /* Read the opcode entry */
368 switch (*(PUCHAR
)Eip
)
370 case 0xF: return KiCallVdmHandler(F
);
371 case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES
);
372 case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS
);
373 case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS
);
374 case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS
);
375 case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS
);
376 case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS
);
377 case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32
);
378 case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32
);
379 case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK
);
380 case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE
);
381 case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP
);
382 case 0x6C: return KiCallVdmHandler(INSB
);
383 case 0x6D: return KiCallVdmHandler(INSW
);
384 case 0x6E: return KiCallVdmHandler(OUTSB
);
385 case 0x6F: return KiCallVdmHandler(OUTSW
);
386 case 0x98: return KiCallVdmHandler(NPX
);
387 case 0xD8: return KiCallVdmHandler(NPX
);
388 case 0xD9: return KiCallVdmHandler(NPX
);
389 case 0xDA: return KiCallVdmHandler(NPX
);
390 case 0xDB: return KiCallVdmHandler(NPX
);
391 case 0xDC: return KiCallVdmHandler(NPX
);
392 case 0xDD: return KiCallVdmHandler(NPX
);
393 case 0xDE: return KiCallVdmHandler(NPX
);
394 case 0xDF: return KiCallVdmHandler(NPX
);
395 case 0x9C: return KiCallVdmHandler(PUSHF
);
396 case 0x9D: return KiCallVdmHandler(POPF
);
397 case 0xCD: return KiCallVdmHandler(INTnn
);
398 case 0xCE: return KiCallVdmHandler(INTO
);
399 case 0xCF: return KiCallVdmHandler(IRET
);
400 case 0xE4: return KiCallVdmHandler(INBimm
);
401 case 0xE5: return KiCallVdmHandler(INWimm
);
402 case 0xE6: return KiCallVdmHandler(OUTBimm
);
403 case 0xE7: return KiCallVdmHandler(OUTWimm
);
404 case 0xEC: return KiCallVdmHandler(INB
);
405 case 0xED: return KiCallVdmHandler(INW
);
406 case 0xEE: return KiCallVdmHandler(OUTB
);
407 case 0xEF: return KiCallVdmHandler(OUTW
);
408 case 0xF4: return KiCallVdmHandler(HLT
);
409 case 0xFA: return KiCallVdmHandler(CLI
);
410 case 0xFB: return KiCallVdmHandler(STI
);
411 default: return KiCallVdmHandler(INV
);
415 /* PREFIX HANDLER *************************************************************/
419 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame
,
422 /* Increase instruction size */
423 DbgPrint("VDM: Handling PREFIX [%lx] Opcode @ 0x%p\n", KiVdmGetPrefixFlags(Flags
), TrapFrame
->Eip
);
426 /* Handle the next opcode */
427 return KiVdmHandleOpcode(TrapFrame
, Flags
);
430 /* TRAP HANDLER ***************************************************************/
434 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame
)
437 TrapFrame
->Eip
&= 0xFFFF;
438 TrapFrame
->HardwareEsp
&= 0xFFFF;
440 /* We start with only 1 byte per instruction */
441 return KiVdmHandleOpcode(TrapFrame
, 1);
446 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame
)
448 PKV8086_STACK_FRAME StackFrame
;
451 PKTRAP_FRAME PmTrapFrame
;
452 PKV86_FRAME V86Frame
;
453 PFX_SAVE_AREA NpxFrame
;
455 /* Get the stack frame back */
456 StackFrame
= CONTAINING_RECORD(TrapFrame
->Esi
, KV8086_STACK_FRAME
, V86Frame
);
457 PmTrapFrame
= &StackFrame
->TrapFrame
;
458 V86Frame
= &StackFrame
->V86Frame
;
459 NpxFrame
= &StackFrame
->NpxArea
;
461 /* Copy the FPU frame back */
462 Thread
= KeGetCurrentThread();
463 RtlCopyMemory(KiGetThreadNpxArea(Thread
), NpxFrame
, sizeof(FX_SAVE_AREA
));
465 /* Set initial stack back */
466 Thread
->InitialStack
= (PVOID
)((ULONG_PTR
)V86Frame
->ThreadStack
+ sizeof(FX_SAVE_AREA
));
468 /* Set ESP0 back in the KTSS */
469 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&PmTrapFrame
->V86Es
;
471 /* Restore TEB addresses */
472 Thread
->Teb
= V86Frame
->ThreadTeb
;
473 KeGetPcr()->Tib
.Self
= V86Frame
->PcrTeb
;
475 /* Setup real TEB descriptor */
476 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
477 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Thread
->Teb
& 0xFFFF);
478 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 16);
479 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 24);
481 /* Enable interrupts and return a pointer to the trap frame */
483 return (ULONG
)PmTrapFrame
;
488 KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame
)
492 PKTRAP_FRAME TrapFrame
= &StackFrame
->TrapFrame
;
493 PKV86_FRAME V86Frame
= &StackFrame
->V86Frame
;
494 PFX_SAVE_AREA NpxFrame
= &StackFrame
->NpxArea
;
496 /* Build fake user-mode trap frame */
497 TrapFrame
->SegCs
= KGDT_R0_CODE
| RPL_MASK
;
498 TrapFrame
->SegEs
= TrapFrame
->SegDs
= TrapFrame
->SegFs
= TrapFrame
->SegGs
= 0;
499 TrapFrame
->ErrCode
= 0;
501 /* Get the current thread's initial stack */
502 Thread
= KeGetCurrentThread();
503 V86Frame
->ThreadStack
= KiGetThreadNpxArea(Thread
);
505 /* Save TEB addresses */
506 V86Frame
->ThreadTeb
= Thread
->Teb
;
507 V86Frame
->PcrTeb
= KeGetPcr()->Tib
.Self
;
509 /* Save return EIP */
510 TrapFrame
->Eip
= (ULONG_PTR
)Ki386BiosCallReturnAddress
;
512 /* Save our stack (after the frames) */
513 TrapFrame
->Esi
= (ULONG_PTR
)V86Frame
;
514 TrapFrame
->Edi
= (ULONG_PTR
)_AddressOfReturnAddress() + 4;
516 /* Sanitize EFlags and enable interrupts */
517 TrapFrame
->EFlags
= __readeflags() & 0x60DD7;
518 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
520 /* Fill out the rest of the frame */
521 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
522 TrapFrame
->HardwareEsp
= 0x11FFE;
523 TrapFrame
->ExceptionList
= EXCEPTION_CHAIN_END
;
525 //TrapFrame->DbgArgMark = 0xBADB0D00;
526 TrapFrame
->PreviousPreviousMode
= -1;
528 /* Disable interrupts */
531 /* Copy the thread's NPX frame */
532 RtlCopyMemory(NpxFrame
, V86Frame
->ThreadStack
, sizeof(FX_SAVE_AREA
));
534 /* Clear exception list */
535 KeGetPcr()->Tib
.ExceptionList
= EXCEPTION_CHAIN_END
;
538 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&TrapFrame
->V86Es
;
540 /* Set new initial stack */
541 Thread
->InitialStack
= V86Frame
;
544 Thread
->Teb
= (PTEB
)TRAMPOLINE_TEB
;
545 KeGetPcr()->Tib
.Self
= (PVOID
)TRAMPOLINE_TEB
;
547 /* Setup VDM TEB descriptor */
548 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
549 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)TRAMPOLINE_TEB
& 0xFFFF);
550 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 16);
551 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 24);
553 /* Enable interrupts */
556 /* Start VDM execution */
557 NtVdmControl(VdmStartExecution
, NULL
);
559 /* Exit to V86 mode */
560 KiEoiHelper(TrapFrame
);
563 /* PUBLIC FUNCTIONS ***********************************************************/
570 Ke386CallBios(IN ULONG Int
,
571 OUT PCONTEXT Context
)
573 PUCHAR Trampoline
= (PUCHAR
)TRAMPOLINE_BASE
;
574 PTEB VdmTeb
= (PTEB
)TRAMPOLINE_TEB
;
575 PVDM_TIB VdmTib
= (PVDM_TIB
)TRAMPOLINE_TIB
;
576 ULONG ContextSize
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
577 PKTHREAD Thread
= KeGetCurrentThread();
578 PKTSS Tss
= KeGetPcr()->TSS
;
579 PKPROCESS Process
= Thread
->ApcState
.Process
;
580 PVDM_PROCESS_OBJECTS VdmProcessObjects
;
581 USHORT OldOffset
, OldBase
;
583 /* Start with a clean TEB */
584 RtlZeroMemory(VdmTeb
, sizeof(TEB
));
586 /* Write the interrupt and bop */
587 *Trampoline
++ = 0xCD;
588 *Trampoline
++ = (UCHAR
)Int
;
589 *(PULONG
)Trampoline
= TRAMPOLINE_BOP
;
591 /* Setup the VDM TEB and TIB */
592 VdmTeb
->Vdm
= (PVOID
)TRAMPOLINE_TIB
;
593 RtlZeroMemory(VdmTib
, sizeof(VDM_TIB
));
594 VdmTib
->Size
= sizeof(VDM_TIB
);
596 /* Set a blank VDM state */
599 /* Copy the context */
600 RtlCopyMemory(&VdmTib
->VdmContext
, Context
, ContextSize
);
601 VdmTib
->VdmContext
.SegCs
= (ULONG_PTR
)Trampoline
>> 4;
602 VdmTib
->VdmContext
.SegSs
= (ULONG_PTR
)Trampoline
>> 4;
603 VdmTib
->VdmContext
.Eip
= 0;
604 VdmTib
->VdmContext
.Esp
= 2 * PAGE_SIZE
- sizeof(ULONG_PTR
);
605 VdmTib
->VdmContext
.EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
606 VdmTib
->VdmContext
.ContextFlags
= CONTEXT_FULL
;
608 /* This can't be a real VDM process */
609 ASSERT(PsGetCurrentProcess()->VdmObjects
== NULL
);
611 /* Allocate VDM structure */
612 VdmProcessObjects
= ExAllocatePoolWithTag(NonPagedPool
,
613 sizeof(VDM_PROCESS_OBJECTS
),
615 if (!VdmProcessObjects
) return STATUS_NO_MEMORY
;
618 RtlZeroMemory(VdmProcessObjects
, sizeof(VDM_PROCESS_OBJECTS
));
619 VdmProcessObjects
->VdmTib
= VdmTib
;
620 PsGetCurrentProcess()->VdmObjects
= VdmProcessObjects
;
622 /* Set the system affinity for the current thread */
623 KeSetSystemAffinityThread(1);
625 /* Make sure there's space for two IOPMs, then copy & clear the current */
626 ASSERT(((PKIPCR
)KeGetPcr())->GDT
[KGDT_TSS
/ 8].LimitLow
>=
627 (0x2000 + IOPM_OFFSET
- 1));
628 RtlCopyMemory(Ki386IopmSaveArea
, &Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
629 RtlZeroMemory(&Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
631 /* Save the old offset and base, and set the new ones */
632 OldOffset
= Process
->IopmOffset
;
633 OldBase
= Tss
->IoMapBase
;
634 Process
->IopmOffset
= (USHORT
)IOPM_OFFSET
;
635 Tss
->IoMapBase
= (USHORT
)IOPM_OFFSET
;
637 /* Switch stacks and work the magic */
638 DbgPrint("VDM: Entering V8086 Mode\n");
639 Ki386SetupAndExitToV86Mode(VdmTeb
);
640 DbgPrint("VDM: Exiting V8086 Mode\n");
643 RtlCopyMemory(&Tss
->IoMaps
[0].IoMap
, Ki386IopmSaveArea
, PAGE_SIZE
* 2);
644 Process
->IopmOffset
= OldOffset
;
645 Tss
->IoMapBase
= OldBase
;
647 /* Restore affinity */
648 KeRevertToUserAffinityThread();
650 /* Restore context */
651 RtlCopyMemory(Context
, &VdmTib
->VdmContext
, ContextSize
);
652 Context
->ContextFlags
= CONTEXT_FULL
;
654 /* Free VDM objects */
655 ExFreePool(PsGetCurrentProcess()->VdmObjects
);
656 PsGetCurrentProcess()->VdmObjects
= NULL
;
659 return STATUS_SUCCESS
;
667 Ke386IoSetAccessProcess(IN PKPROCESS Process
,
679 Ke386SetIoAccessMap(IN ULONG Flag
,
691 Ke386QueryIoAccessMap(IN ULONG Flag
,