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 V86EFlags
= *KiNtVdmState
;
58 V86EFlags
&= ~EFLAGS_INTERRUPT_MASK
;
60 /* Get trap frame EFLags */
61 TrapEFlags
= TrapFrame
->EFlags
;
62 /* Check for VME support */
63 if(KeI386VirtualIntExtensions
)
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
;
70 /* Leave only align, nested task and interrupt */
71 TrapEFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
73 /* Add in those flags if they exist, and add in the IOPL flag */
74 V86EFlags
|= TrapEFlags
;
75 V86EFlags
|= EFLAGS_IOPL
;
78 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + (USHORT
)TrapFrame
->HardwareEsp
;
80 /* Check for OPER32 */
81 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
85 *(PULONG
)Esp
= V86EFlags
;
91 *(PUSHORT
)Esp
= (USHORT
)V86EFlags
;
94 /* Set new ESP and EIP */
95 TrapFrame
->HardwareEsp
= Esp
- (TrapFrame
->HardwareSegSs
<< 4);
96 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
104 KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame
,
107 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
;
110 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + (USHORT
)TrapFrame
->HardwareEsp
;
112 /* Check for OPER32 */
113 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
116 EFlags
= *(PULONG
)Esp
;
122 EFlags
= *(PUSHORT
)Esp
;
127 TrapFrame
->HardwareEsp
= Esp
- (TrapFrame
->HardwareSegSs
<< 4);
129 /* Mask out IOPL from the flags */
130 EFlags
&= ~EFLAGS_IOPL
;
132 /* Save the V86 flags, but mask out the nested task flag */
133 V86EFlags
= EFlags
& ~EFLAGS_NESTED_TASK
;
135 /* Now leave only alignment, nested task and interrupt flag */
136 EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
138 /* Get trap EFlags */
139 TrapEFlags
= TrapFrame
->EFlags
;
141 /* Check for VME support */
142 if(KeI386VirtualIntExtensions
)
144 /* Copy the IF flag into the VIF one */
145 V86EFlags
&= ~EFLAGS_VIF
;
146 if(V86EFlags
& EFLAGS_INTERRUPT_MASK
)
148 V86EFlags
|= EFLAGS_VIF
;
149 /* Don't set the interrupt flag */
150 V86EFlags
&= ~EFLAGS_INTERRUPT_MASK
;
155 V86EFlags
|= EFLAGS_V86_MASK
;
157 /* Update EFlags in trap frame */
158 TrapFrame
->EFlags
|= V86EFlags
;
160 /* Check if ESP0 needs to be fixed up */
161 if (TrapEFlags
& EFLAGS_V86_MASK
) Ki386AdjustEsp0(TrapFrame
);
163 /* Update the V8086 EFlags state */
164 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
165 KiVdmSetVdmEFlags(EFlags
);
167 /* FIXME: Check for VDM interrupts */
170 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
178 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame
,
181 ULONG Esp
, V86EFlags
, TrapEFlags
, Eip
, Interrupt
;
183 /* Read trap frame EFlags */
184 TrapEFlags
= TrapFrame
->EFlags
;
186 /* Remove interrupt flag from V8086 EFlags */
187 V86EFlags
= *KiNtVdmState
;
188 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
190 /* Keep only alignment and interrupt flag from the V8086 state */
191 V86EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_INTERRUPT_MASK
);
193 /* Check for VME support */
194 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
196 /* Mask in the relevant V86 EFlags into the trap flags */
197 V86EFlags
|= (TrapEFlags
& ~EFLAGS_INTERRUPT_MASK
);
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
);
202 /* Add the IOPL flag to the local trap flags */
203 V86EFlags
|= EFLAGS_IOPL
;
206 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
210 *(PUSHORT
)(Esp
) = (USHORT
)V86EFlags
;
214 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->SegCs
;
218 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->Eip
+ KiVdmGetInstructionSize(Flags
) + 1;
221 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
224 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
226 /* Now get the *next* EIP address (current is original + the count - 1) */
227 Eip
+= KiVdmGetInstructionSize(Flags
);
229 /* Now read the interrupt number */
230 Interrupt
= *(PUCHAR
)Eip
;
232 /* Read the EIP from its IVT entry */
233 Interrupt
= *(PULONG
)(Interrupt
* 4);
234 TrapFrame
->Eip
= (USHORT
)Interrupt
;
236 /* Now get the CS segment */
237 Interrupt
= (USHORT
)(Interrupt
>> 16);
239 /* Check if the trap was not V8086 trap */
240 if (!(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
242 /* Was it a kernel CS? */
243 Interrupt
|= RPL_MASK
;
244 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
246 /* Add the RPL mask */
247 TrapFrame
->SegCs
= Interrupt
;
252 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
258 TrapFrame
->SegCs
= Interrupt
;
267 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame
,
270 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
, Eip
;
273 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
275 /* Check for OPER32 */
276 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
278 /* Build segmented EIP */
279 TrapFrame
->Eip
= *(PULONG
)Esp
;
280 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 4);
283 TrapFrame
->HardwareEsp
+= 12;
286 EFlags
= *(PULONG
)(Esp
+ 8);
290 /* Build segmented EIP */
291 TrapFrame
->Eip
= *(PUSHORT
)Esp
;
292 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 2);
295 TrapFrame
->HardwareEsp
+= 6;
298 EFlags
= *(PUSHORT
)(Esp
+ 4);
301 /* Mask out EFlags */
302 EFlags
&= ~(EFLAGS_IOPL
+ EFLAGS_VIF
+ EFLAGS_NESTED_TASK
+ EFLAGS_VIP
);
305 /* Check for VME support */
306 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
308 /* Add V86 and Interrupt flag */
309 EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
311 /* Update EFlags in trap frame */
312 TrapEFlags
= TrapFrame
->EFlags
;
313 TrapFrame
->EFlags
= (TrapFrame
->EFlags
& EFLAGS_VIP
) | EFlags
;
315 /* Check if ESP0 needs to be fixed up */
316 if (!(TrapEFlags
& EFLAGS_V86_MASK
)) Ki386AdjustEsp0(TrapFrame
);
318 /* Update the V8086 EFlags state */
319 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
320 KiVdmSetVdmEFlags(V86EFlags
);
322 /* Build flat EIP and check if this is the BOP instruction */
323 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
324 if (*(PUSHORT
)Eip
== 0xC4C4)
326 /* Dispatch the BOP */
327 VdmDispatchBop(TrapFrame
);
331 /* FIXME: Check for VDM interrupts */
332 DPRINT("FIXME: Check for VDM interrupts\n");
341 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame
,
344 /* Check for VME support */
345 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
347 /* Disable interrupts */
348 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
350 /* Skip instruction */
351 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
359 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame
,
362 /* Check for VME support */
363 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
365 /* Enable interrupts */
366 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK
);
368 /* Skip instruction */
369 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
375 /* MASTER OPCODE HANDLER ******************************************************/
379 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame
,
384 /* Get flat EIP of the *current* instruction (not the original EIP) */
385 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
386 Eip
+= KiVdmGetInstructionSize(Flags
) - 1;
388 /* Read the opcode entry */
389 switch (*(PUCHAR
)Eip
)
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: return KiCallVdmHandler(INV
);
436 /* PREFIX HANDLER *************************************************************/
440 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame
,
443 /* Increase instruction size */
446 /* Handle the next opcode */
447 return KiVdmHandleOpcode(TrapFrame
, Flags
);
450 /* TRAP HANDLER ***************************************************************/
454 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame
)
457 TrapFrame
->Eip
&= 0xFFFF;
458 TrapFrame
->HardwareEsp
&= 0xFFFF;
460 /* We start with only 1 byte per instruction */
461 return KiVdmHandleOpcode(TrapFrame
, 1);
466 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame
)
468 ULONG_PTR StackFrameUnaligned
;
469 PKV8086_STACK_FRAME StackFrame
;
471 PKTRAP_FRAME PmTrapFrame
;
472 PKV86_FRAME V86Frame
;
473 PFX_SAVE_AREA NpxFrame
;
475 /* Get the stack frame back */
476 StackFrameUnaligned
= TrapFrame
->Esi
;
477 StackFrame
= (PKV8086_STACK_FRAME
)(ROUND_UP(StackFrameUnaligned
- 4, 16) + 4);
478 PmTrapFrame
= &StackFrame
->TrapFrame
;
479 V86Frame
= &StackFrame
->V86Frame
;
480 NpxFrame
= &StackFrame
->NpxArea
;
481 ASSERT((ULONG_PTR
)NpxFrame
% 16 == 0);
483 /* Copy the FPU frame back */
484 Thread
= KeGetCurrentThread();
485 RtlCopyMemory(KiGetThreadNpxArea(Thread
), NpxFrame
, sizeof(FX_SAVE_AREA
));
487 /* Set initial stack back */
488 Thread
->InitialStack
= (PVOID
)((ULONG_PTR
)V86Frame
->ThreadStack
+ sizeof(FX_SAVE_AREA
));
490 /* Set ESP0 back in the KTSS */
491 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&PmTrapFrame
->V86Es
;
493 /* Restore TEB addresses */
494 Thread
->Teb
= V86Frame
->ThreadTeb
;
495 KiSetTebBase(KeGetPcr(), V86Frame
->ThreadTeb
);
497 /* Enable interrupts and return a pointer to the trap frame */
499 return StackFrameUnaligned
;
504 KiEnterV86Mode(IN ULONG_PTR StackFrameUnaligned
)
507 PKV8086_STACK_FRAME StackFrame
= (PKV8086_STACK_FRAME
)(ROUND_UP(StackFrameUnaligned
- 4, 16) + 4);
508 PKTRAP_FRAME TrapFrame
= &StackFrame
->TrapFrame
;
509 PKV86_FRAME V86Frame
= &StackFrame
->V86Frame
;
510 PFX_SAVE_AREA NpxFrame
= &StackFrame
->NpxArea
;
512 ASSERT((ULONG_PTR
)NpxFrame
% 16 == 0);
514 /* Build fake user-mode trap frame */
515 TrapFrame
->SegCs
= KGDT_R0_CODE
| RPL_MASK
;
516 TrapFrame
->SegEs
= TrapFrame
->SegDs
= TrapFrame
->SegFs
= TrapFrame
->SegGs
= 0;
517 TrapFrame
->ErrCode
= 0;
519 /* Get the current thread's initial stack */
520 Thread
= KeGetCurrentThread();
521 V86Frame
->ThreadStack
= KiGetThreadNpxArea(Thread
);
523 /* Save TEB addresses */
524 V86Frame
->ThreadTeb
= Thread
->Teb
;
525 V86Frame
->PcrTeb
= KeGetPcr()->NtTib
.Self
;
527 /* Save return EIP */
528 TrapFrame
->Eip
= (ULONG_PTR
)Ki386BiosCallReturnAddress
;
530 /* Save our stack (after the frames) */
531 TrapFrame
->Esi
= StackFrameUnaligned
;
532 TrapFrame
->Edi
= (ULONG_PTR
)_AddressOfReturnAddress() + 4;
534 /* Sanitize EFlags and enable interrupts */
535 TrapFrame
->EFlags
= __readeflags() & 0x60DD7;
536 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
538 /* Fill out the rest of the frame */
539 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
540 TrapFrame
->HardwareEsp
= 0x11FFE;
541 TrapFrame
->ExceptionList
= EXCEPTION_CHAIN_END
;
544 /* Set some debug fields if trap debugging is enabled */
545 KiFillTrapFrameDebug(TrapFrame
);
547 /* Disable interrupts */
550 /* Copy the thread's NPX frame */
551 RtlCopyMemory(NpxFrame
, V86Frame
->ThreadStack
, sizeof(FX_SAVE_AREA
));
553 /* Clear exception list */
554 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
557 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&TrapFrame
->V86Es
;
559 /* Set new initial stack */
560 Thread
->InitialStack
= V86Frame
;
563 Thread
->Teb
= (PTEB
)TRAMPOLINE_TEB
;
564 KiSetTebBase(KeGetPcr(), (PVOID
)TRAMPOLINE_TEB
);
566 /* Enable interrupts */
569 /* Start VDM execution */
570 NtVdmControl(VdmStartExecution
, NULL
);
572 /* Exit to V86 mode */
573 KiEoiHelper(TrapFrame
);
581 PKTHREAD Thread
= KeGetCurrentThread();
582 PKPROCESS Process
= Thread
->ApcState
.Process
;
583 PKTRAP_FRAME TrapFrame
;
586 /* IOPL was enabled for this process/thread */
587 Process
->Iopl
= TRUE
;
590 /* Get the trap frame on exit */
591 TrapFrame
= KeGetTrapFrame(Thread
);
593 /* Convert to a context */
594 Context
.ContextFlags
= CONTEXT_CONTROL
;
595 KeTrapFrameToContext(TrapFrame
, NULL
, &Context
);
597 /* Set the IOPL flag */
598 Context
.EFlags
|= EFLAGS_IOPL
;
600 /* Convert back to a trap frame */
601 KeContextToTrapFrame(&Context
, NULL
, TrapFrame
, CONTEXT_CONTROL
, UserMode
);
604 /* PUBLIC FUNCTIONS ***********************************************************/
611 Ke386CallBios(IN ULONG Int
,
612 OUT PCONTEXT Context
)
614 PUCHAR Trampoline
= (PUCHAR
)TRAMPOLINE_BASE
;
615 PTEB VdmTeb
= (PTEB
)TRAMPOLINE_TEB
;
616 PVDM_TIB VdmTib
= (PVDM_TIB
)TRAMPOLINE_TIB
;
617 ULONG ContextSize
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
618 PKTHREAD Thread
= KeGetCurrentThread();
619 PKTSS Tss
= KeGetPcr()->TSS
;
620 PKPROCESS Process
= Thread
->ApcState
.Process
;
621 PVDM_PROCESS_OBJECTS VdmProcessObjects
;
622 USHORT OldOffset
, OldBase
;
624 /* Start with a clean TEB */
625 RtlZeroMemory(VdmTeb
, sizeof(TEB
));
627 /* Write the interrupt and bop */
628 *Trampoline
++ = 0xCD;
629 *Trampoline
++ = (UCHAR
)Int
;
630 *(PULONG
)Trampoline
= TRAMPOLINE_BOP
;
632 /* Setup the VDM TEB and TIB */
633 VdmTeb
->Vdm
= (PVOID
)TRAMPOLINE_TIB
;
634 RtlZeroMemory(VdmTib
, sizeof(VDM_TIB
));
635 VdmTib
->Size
= sizeof(VDM_TIB
);
637 /* Set a blank VDM state */
640 /* Copy the context */
641 RtlCopyMemory(&VdmTib
->VdmContext
, Context
, ContextSize
);
642 VdmTib
->VdmContext
.SegCs
= (ULONG_PTR
)Trampoline
>> 4;
643 VdmTib
->VdmContext
.SegSs
= (ULONG_PTR
)Trampoline
>> 4;
644 VdmTib
->VdmContext
.Eip
= 0;
645 VdmTib
->VdmContext
.Esp
= 2 * PAGE_SIZE
- sizeof(ULONG_PTR
);
646 VdmTib
->VdmContext
.EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
647 VdmTib
->VdmContext
.ContextFlags
= CONTEXT_FULL
;
649 /* This can't be a real VDM process */
650 ASSERT(PsGetCurrentProcess()->VdmObjects
== NULL
);
652 /* Allocate VDM structure */
653 VdmProcessObjects
= ExAllocatePoolWithTag(NonPagedPool
,
654 sizeof(VDM_PROCESS_OBJECTS
),
656 if (!VdmProcessObjects
) return STATUS_NO_MEMORY
;
659 RtlZeroMemory(VdmProcessObjects
, sizeof(VDM_PROCESS_OBJECTS
));
660 VdmProcessObjects
->VdmTib
= VdmTib
;
661 PsGetCurrentProcess()->VdmObjects
= VdmProcessObjects
;
663 /* Set the system affinity for the current thread */
664 KeSetSystemAffinityThread(1);
666 /* Make sure there's space for two IOPMs, then copy & clear the current */
667 ASSERT(((PKIPCR
)KeGetPcr())->GDT
[KGDT_TSS
/ 8].LimitLow
>=
668 (0x2000 + IOPM_OFFSET
- 1));
669 RtlCopyMemory(Ki386IopmSaveArea
, &Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
670 RtlZeroMemory(&Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
672 /* Save the old offset and base, and set the new ones */
673 OldOffset
= Process
->IopmOffset
;
674 OldBase
= Tss
->IoMapBase
;
675 Process
->IopmOffset
= (USHORT
)IOPM_OFFSET
;
676 Tss
->IoMapBase
= (USHORT
)IOPM_OFFSET
;
678 /* Switch stacks and work the magic */
679 Ki386SetupAndExitToV86Mode(VdmTeb
);
682 RtlCopyMemory(&Tss
->IoMaps
[0].IoMap
, Ki386IopmSaveArea
, PAGE_SIZE
* 2);
683 Process
->IopmOffset
= OldOffset
;
684 Tss
->IoMapBase
= OldBase
;
686 /* Restore affinity */
687 KeRevertToUserAffinityThread();
689 /* Restore context */
690 RtlCopyMemory(Context
, &VdmTib
->VdmContext
, ContextSize
);
691 Context
->ContextFlags
= CONTEXT_FULL
;
693 /* Free VDM objects */
694 ExFreePool(PsGetCurrentProcess()->VdmObjects
);
695 PsGetCurrentProcess()->VdmObjects
= NULL
;
698 return STATUS_SUCCESS
;
706 Ke386IoSetAccessProcess(IN PKPROCESS Process
,
711 KAFFINITY TargetProcessors
;
713 if(MapNumber
> IOPM_COUNT
)
716 MapOffset
= KiComputeIopmOffset(MapNumber
);
718 Process
->IopmOffset
= MapOffset
;
720 TargetProcessors
= Process
->ActiveProcessors
;
721 Prcb
= KeGetCurrentPrcb();
722 if (TargetProcessors
& Prcb
->SetMember
)
723 KeGetPcr()->TSS
->IoMapBase
= MapOffset
;
733 Ke386SetIoAccessMap(IN ULONG MapNumber
,
734 IN PKIO_ACCESS_MAP IopmBuffer
)
736 PKPROCESS CurrentProcess
;
740 if ((MapNumber
> IOPM_COUNT
) || (MapNumber
== IO_ACCESS_MAP_NONE
))
743 Prcb
= KeGetCurrentPrcb();
745 // Copy the IOP map and load the map for the current process.
746 pt
= &(KeGetPcr()->TSS
->IoMaps
[MapNumber
-1].IoMap
);
747 RtlMoveMemory(pt
, (PVOID
)IopmBuffer
, IOPM_SIZE
);
748 CurrentProcess
= Prcb
->CurrentThread
->ApcState
.Process
;
749 KeGetPcr()->TSS
->IoMapBase
= CurrentProcess
->IopmOffset
;
759 Ke386QueryIoAccessMap(IN ULONG MapNumber
,
760 IN PKIO_ACCESS_MAP IopmBuffer
)
766 if (MapNumber
> IOPM_COUNT
)
769 if (MapNumber
== IO_ACCESS_MAP_NONE
)
771 // no access, simply return a map of all 1s
772 p
= (PUCHAR
)IopmBuffer
;
773 for (i
= 0; i
< IOPM_SIZE
; i
++) {
780 Map
= (PVOID
)&(KeGetPcr()->TSS
->IoMaps
[MapNumber
-1].IoMap
);
781 RtlMoveMemory((PVOID
)IopmBuffer
, Map
, IOPM_SIZE
);