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 /* Check for VME support */
57 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
59 /* Get current V8086 flags and mask out interrupt flag */
60 V86EFlags
= *KiNtVdmState
;
61 V86EFlags
&= ~EFLAGS_INTERRUPT_MASK
;
63 /* Get trap frame EFLags and leave only align, nested task and interrupt */
64 TrapEFlags
= TrapFrame
->EFlags
;
65 V86EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
67 /* Add in those flags if they exist, and add in the IOPL flag */
68 V86EFlags
|= TrapEFlags
;
69 V86EFlags
|= EFLAGS_IOPL
;
72 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + (USHORT
)TrapFrame
->HardwareEsp
;
74 /* Check for OPER32 */
75 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
79 *(PULONG
)Esp
= V86EFlags
;
85 *(PUSHORT
)Esp
= (USHORT
)V86EFlags
;
88 /* Set new ESP and EIP */
89 TrapFrame
->HardwareEsp
= Esp
- (TrapFrame
->HardwareSegSs
<< 4);
90 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
98 KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame
,
101 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
;
104 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + (USHORT
)TrapFrame
->HardwareEsp
;
106 /* Check for OPER32 */
107 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
110 EFlags
= *(PULONG
)Esp
;
116 EFlags
= *(PUSHORT
)Esp
;
121 TrapFrame
->HardwareEsp
= Esp
- (TrapFrame
->HardwareSegSs
<< 4);
123 /* Mask out IOPL from the flags */
124 EFlags
&= ~EFLAGS_IOPL
;
126 /* Save the V86 flags, but mask out the nested task flag */
127 V86EFlags
= EFlags
& ~EFLAGS_NESTED_TASK
;
129 /* Now leave only alignment, nested task and interrupt flag */
130 EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
132 /* Get trap EFlags */
133 TrapEFlags
= TrapFrame
->EFlags
;
135 /* Check for VME support */
136 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
138 /* Add V86 and Interrupt flag */
139 V86EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
141 /* Update EFlags in trap frame */
142 TrapFrame
->EFlags
= V86EFlags
;
144 /* Check if ESP0 needs to be fixed up */
145 if (TrapEFlags
& EFLAGS_V86_MASK
) Ki386AdjustEsp0(TrapFrame
);
147 /* Update the V8086 EFlags state */
148 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
149 KiVdmSetVdmEFlags(EFlags
);
151 /* FIXME: Check for VDM interrupts */
154 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
162 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame
,
165 ULONG Esp
, V86EFlags
, TrapEFlags
, Eip
, Interrupt
;
167 /* Read trap frame EFlags */
168 TrapEFlags
= TrapFrame
->EFlags
;
170 /* Remove interrupt flag from V8086 EFlags */
171 V86EFlags
= *KiNtVdmState
;
172 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
174 /* Keep only alignment and interrupt flag from the V8086 state */
175 V86EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_INTERRUPT_MASK
);
177 /* Check for VME support */
178 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
180 /* Mask in the relevant V86 EFlags into the trap flags */
181 V86EFlags
|= (TrapEFlags
& ~EFLAGS_INTERRUPT_MASK
);
183 /* And mask out the VIF, nested task and TF flag from the trap flags */
184 TrapFrame
->EFlags
= TrapEFlags
&~ (EFLAGS_VIF
| EFLAGS_NESTED_TASK
| EFLAGS_TF
);
186 /* Add the IOPL flag to the local trap flags */
187 V86EFlags
|= EFLAGS_IOPL
;
190 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
194 *(PUSHORT
)(Esp
) = (USHORT
)V86EFlags
;
198 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->SegCs
;
202 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->Eip
+ KiVdmGetInstructionSize(Flags
) + 1;
205 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
208 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
210 /* Now get the *next* EIP address (current is original + the count - 1) */
211 Eip
+= KiVdmGetInstructionSize(Flags
);
213 /* Now read the interrupt number */
214 Interrupt
= *(PUCHAR
)Eip
;
216 /* Read the EIP from its IVT entry */
217 Interrupt
= *(PULONG
)(Interrupt
* 4);
218 TrapFrame
->Eip
= (USHORT
)Interrupt
;
220 /* Now get the CS segment */
221 Interrupt
= (USHORT
)(Interrupt
>> 16);
223 /* Check if the trap was not V8086 trap */
224 if (!(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
226 /* Was it a kernel CS? */
227 Interrupt
|= RPL_MASK
;
228 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
230 /* Add the RPL mask */
231 TrapFrame
->SegCs
= Interrupt
;
236 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
242 TrapFrame
->SegCs
= Interrupt
;
251 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame
,
254 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
, Eip
;
257 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
259 /* Check for OPER32 */
260 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
262 /* Build segmented EIP */
263 TrapFrame
->Eip
= *(PULONG
)Esp
;
264 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 4);
267 TrapFrame
->HardwareEsp
+= 12;
270 EFlags
= *(PULONG
)(Esp
+ 8);
274 /* Build segmented EIP */
275 TrapFrame
->Eip
= *(PUSHORT
)Esp
;
276 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 2);
279 TrapFrame
->HardwareEsp
+= 6;
282 EFlags
= *(PUSHORT
)(Esp
+ 4);
285 /* Mask out EFlags */
286 EFlags
&= ~(EFLAGS_IOPL
+ EFLAGS_VIF
+ EFLAGS_NESTED_TASK
+ EFLAGS_VIP
);
289 /* Check for VME support */
290 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
292 /* Add V86 and Interrupt flag */
293 EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
295 /* Update EFlags in trap frame */
296 TrapEFlags
= TrapFrame
->EFlags
;
297 TrapFrame
->EFlags
= (TrapFrame
->EFlags
& EFLAGS_VIP
) | EFlags
;
299 /* Check if ESP0 needs to be fixed up */
300 if (!(TrapEFlags
& EFLAGS_V86_MASK
)) Ki386AdjustEsp0(TrapFrame
);
302 /* Update the V8086 EFlags state */
303 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
304 KiVdmSetVdmEFlags(V86EFlags
);
306 /* Build flat EIP and check if this is the BOP instruction */
307 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
308 if (*(PUSHORT
)Eip
== 0xC4C4)
310 /* Dispatch the BOP */
311 VdmDispatchBop(TrapFrame
);
315 /* FIXME: Check for VDM interrupts */
316 DPRINT("FIXME: Check for VDM interrupts\n");
325 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame
,
328 /* Check for VME support */
329 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
331 /* Disable interrupts */
332 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
334 /* Skip instruction */
335 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
343 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame
,
346 /* Check for VME support */
347 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
349 /* Enable interrupts */
350 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK
);
352 /* Skip instruction */
353 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
359 /* MASTER OPCODE HANDLER ******************************************************/
363 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame
,
368 /* Get flat EIP of the *current* instruction (not the original EIP) */
369 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
370 Eip
+= KiVdmGetInstructionSize(Flags
) - 1;
372 /* Read the opcode entry */
373 switch (*(PUCHAR
)Eip
)
375 case 0xF: return KiCallVdmHandler(F
);
376 case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES
);
377 case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS
);
378 case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS
);
379 case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS
);
380 case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS
);
381 case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS
);
382 case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32
);
383 case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32
);
384 case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK
);
385 case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE
);
386 case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP
);
387 case 0x6C: return KiCallVdmHandler(INSB
);
388 case 0x6D: return KiCallVdmHandler(INSW
);
389 case 0x6E: return KiCallVdmHandler(OUTSB
);
390 case 0x6F: return KiCallVdmHandler(OUTSW
);
391 case 0x98: return KiCallVdmHandler(NPX
);
392 case 0xD8: return KiCallVdmHandler(NPX
);
393 case 0xD9: return KiCallVdmHandler(NPX
);
394 case 0xDA: return KiCallVdmHandler(NPX
);
395 case 0xDB: return KiCallVdmHandler(NPX
);
396 case 0xDC: return KiCallVdmHandler(NPX
);
397 case 0xDD: return KiCallVdmHandler(NPX
);
398 case 0xDE: return KiCallVdmHandler(NPX
);
399 case 0xDF: return KiCallVdmHandler(NPX
);
400 case 0x9C: return KiCallVdmHandler(PUSHF
);
401 case 0x9D: return KiCallVdmHandler(POPF
);
402 case 0xCD: return KiCallVdmHandler(INTnn
);
403 case 0xCE: return KiCallVdmHandler(INTO
);
404 case 0xCF: return KiCallVdmHandler(IRET
);
405 case 0xE4: return KiCallVdmHandler(INBimm
);
406 case 0xE5: return KiCallVdmHandler(INWimm
);
407 case 0xE6: return KiCallVdmHandler(OUTBimm
);
408 case 0xE7: return KiCallVdmHandler(OUTWimm
);
409 case 0xEC: return KiCallVdmHandler(INB
);
410 case 0xED: return KiCallVdmHandler(INW
);
411 case 0xEE: return KiCallVdmHandler(OUTB
);
412 case 0xEF: return KiCallVdmHandler(OUTW
);
413 case 0xF4: return KiCallVdmHandler(HLT
);
414 case 0xFA: return KiCallVdmHandler(CLI
);
415 case 0xFB: return KiCallVdmHandler(STI
);
416 default: return KiCallVdmHandler(INV
);
420 /* PREFIX HANDLER *************************************************************/
424 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame
,
427 /* Increase instruction size */
430 /* Handle the next opcode */
431 return KiVdmHandleOpcode(TrapFrame
, Flags
);
434 /* TRAP HANDLER ***************************************************************/
438 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame
)
441 TrapFrame
->Eip
&= 0xFFFF;
442 TrapFrame
->HardwareEsp
&= 0xFFFF;
444 /* We start with only 1 byte per instruction */
445 return KiVdmHandleOpcode(TrapFrame
, 1);
450 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame
)
452 PKV8086_STACK_FRAME StackFrame
;
455 PKTRAP_FRAME PmTrapFrame
;
456 PKV86_FRAME V86Frame
;
457 PFX_SAVE_AREA NpxFrame
;
459 /* Get the stack frame back */
460 StackFrame
= CONTAINING_RECORD(TrapFrame
->Esi
, KV8086_STACK_FRAME
, V86Frame
);
461 PmTrapFrame
= &StackFrame
->TrapFrame
;
462 V86Frame
= &StackFrame
->V86Frame
;
463 NpxFrame
= &StackFrame
->NpxArea
;
465 /* Copy the FPU frame back */
466 Thread
= KeGetCurrentThread();
467 RtlCopyMemory(KiGetThreadNpxArea(Thread
), NpxFrame
, sizeof(FX_SAVE_AREA
));
469 /* Set initial stack back */
470 Thread
->InitialStack
= (PVOID
)((ULONG_PTR
)V86Frame
->ThreadStack
+ sizeof(FX_SAVE_AREA
));
472 /* Set ESP0 back in the KTSS */
473 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&PmTrapFrame
->V86Es
;
475 /* Restore TEB addresses */
476 Thread
->Teb
= V86Frame
->ThreadTeb
;
477 KeGetPcr()->NtTib
.Self
= V86Frame
->PcrTeb
;
479 /* Setup real TEB descriptor */
480 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
481 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Thread
->Teb
& 0xFFFF);
482 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 16);
483 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 24);
485 /* Enable interrupts and return a pointer to the trap frame */
487 return (ULONG
)PmTrapFrame
;
492 KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame
)
496 PKTRAP_FRAME TrapFrame
= &StackFrame
->TrapFrame
;
497 PKV86_FRAME V86Frame
= &StackFrame
->V86Frame
;
498 PFX_SAVE_AREA NpxFrame
= &StackFrame
->NpxArea
;
500 /* Build fake user-mode trap frame */
501 TrapFrame
->SegCs
= KGDT_R0_CODE
| RPL_MASK
;
502 TrapFrame
->SegEs
= TrapFrame
->SegDs
= TrapFrame
->SegFs
= TrapFrame
->SegGs
= 0;
503 TrapFrame
->ErrCode
= 0;
505 /* Get the current thread's initial stack */
506 Thread
= KeGetCurrentThread();
507 V86Frame
->ThreadStack
= KiGetThreadNpxArea(Thread
);
509 /* Save TEB addresses */
510 V86Frame
->ThreadTeb
= Thread
->Teb
;
511 V86Frame
->PcrTeb
= KeGetPcr()->NtTib
.Self
;
513 /* Save return EIP */
514 TrapFrame
->Eip
= (ULONG_PTR
)Ki386BiosCallReturnAddress
;
516 /* Save our stack (after the frames) */
517 TrapFrame
->Esi
= (ULONG_PTR
)V86Frame
;
518 TrapFrame
->Edi
= (ULONG_PTR
)_AddressOfReturnAddress() + 4;
520 /* Sanitize EFlags and enable interrupts */
521 TrapFrame
->EFlags
= __readeflags() & 0x60DD7;
522 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
524 /* Fill out the rest of the frame */
525 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
526 TrapFrame
->HardwareEsp
= 0x11FFE;
527 TrapFrame
->ExceptionList
= EXCEPTION_CHAIN_END
;
529 //TrapFrame->DbgArgMark = 0xBADB0D00;
530 TrapFrame
->PreviousPreviousMode
= -1;
532 /* Disable interrupts */
535 /* Copy the thread's NPX frame */
536 RtlCopyMemory(NpxFrame
, V86Frame
->ThreadStack
, sizeof(FX_SAVE_AREA
));
538 /* Clear exception list */
539 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
542 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&TrapFrame
->V86Es
;
544 /* Set new initial stack */
545 Thread
->InitialStack
= V86Frame
;
548 Thread
->Teb
= (PTEB
)TRAMPOLINE_TEB
;
549 KeGetPcr()->NtTib
.Self
= (PVOID
)TRAMPOLINE_TEB
;
551 /* Setup VDM TEB descriptor */
552 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
553 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)TRAMPOLINE_TEB
& 0xFFFF);
554 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 16);
555 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 24);
557 /* Enable interrupts */
560 /* Start VDM execution */
561 NtVdmControl(VdmStartExecution
, NULL
);
563 /* Exit to V86 mode */
564 KiEoiHelper(TrapFrame
);
567 /* PUBLIC FUNCTIONS ***********************************************************/
574 Ke386CallBios(IN ULONG Int
,
575 OUT PCONTEXT Context
)
577 PUCHAR Trampoline
= (PUCHAR
)TRAMPOLINE_BASE
;
578 PTEB VdmTeb
= (PTEB
)TRAMPOLINE_TEB
;
579 PVDM_TIB VdmTib
= (PVDM_TIB
)TRAMPOLINE_TIB
;
580 ULONG ContextSize
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
581 PKTHREAD Thread
= KeGetCurrentThread();
582 PKTSS Tss
= KeGetPcr()->TSS
;
583 PKPROCESS Process
= Thread
->ApcState
.Process
;
584 PVDM_PROCESS_OBJECTS VdmProcessObjects
;
585 USHORT OldOffset
, OldBase
;
587 /* Start with a clean TEB */
588 RtlZeroMemory(VdmTeb
, sizeof(TEB
));
590 /* Write the interrupt and bop */
591 *Trampoline
++ = 0xCD;
592 *Trampoline
++ = (UCHAR
)Int
;
593 *(PULONG
)Trampoline
= TRAMPOLINE_BOP
;
595 /* Setup the VDM TEB and TIB */
596 VdmTeb
->Vdm
= (PVOID
)TRAMPOLINE_TIB
;
597 RtlZeroMemory(VdmTib
, sizeof(VDM_TIB
));
598 VdmTib
->Size
= sizeof(VDM_TIB
);
600 /* Set a blank VDM state */
603 /* Copy the context */
604 RtlCopyMemory(&VdmTib
->VdmContext
, Context
, ContextSize
);
605 VdmTib
->VdmContext
.SegCs
= (ULONG_PTR
)Trampoline
>> 4;
606 VdmTib
->VdmContext
.SegSs
= (ULONG_PTR
)Trampoline
>> 4;
607 VdmTib
->VdmContext
.Eip
= 0;
608 VdmTib
->VdmContext
.Esp
= 2 * PAGE_SIZE
- sizeof(ULONG_PTR
);
609 VdmTib
->VdmContext
.EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
610 VdmTib
->VdmContext
.ContextFlags
= CONTEXT_FULL
;
612 /* This can't be a real VDM process */
613 ASSERT(PsGetCurrentProcess()->VdmObjects
== NULL
);
615 /* Allocate VDM structure */
616 VdmProcessObjects
= ExAllocatePoolWithTag(NonPagedPool
,
617 sizeof(VDM_PROCESS_OBJECTS
),
619 if (!VdmProcessObjects
) return STATUS_NO_MEMORY
;
622 RtlZeroMemory(VdmProcessObjects
, sizeof(VDM_PROCESS_OBJECTS
));
623 VdmProcessObjects
->VdmTib
= VdmTib
;
624 PsGetCurrentProcess()->VdmObjects
= VdmProcessObjects
;
626 /* Set the system affinity for the current thread */
627 KeSetSystemAffinityThread(1);
629 /* Make sure there's space for two IOPMs, then copy & clear the current */
630 ASSERT(((PKIPCR
)KeGetPcr())->GDT
[KGDT_TSS
/ 8].LimitLow
>=
631 (0x2000 + IOPM_OFFSET
- 1));
632 RtlCopyMemory(Ki386IopmSaveArea
, &Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
633 RtlZeroMemory(&Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
635 /* Save the old offset and base, and set the new ones */
636 OldOffset
= Process
->IopmOffset
;
637 OldBase
= Tss
->IoMapBase
;
638 Process
->IopmOffset
= (USHORT
)IOPM_OFFSET
;
639 Tss
->IoMapBase
= (USHORT
)IOPM_OFFSET
;
641 /* Switch stacks and work the magic */
642 Ki386SetupAndExitToV86Mode(VdmTeb
);
645 RtlCopyMemory(&Tss
->IoMaps
[0].IoMap
, Ki386IopmSaveArea
, PAGE_SIZE
* 2);
646 Process
->IopmOffset
= OldOffset
;
647 Tss
->IoMapBase
= OldBase
;
649 /* Restore affinity */
650 KeRevertToUserAffinityThread();
652 /* Restore context */
653 RtlCopyMemory(Context
, &VdmTib
->VdmContext
, ContextSize
);
654 Context
->ContextFlags
= CONTEXT_FULL
;
656 /* Free VDM objects */
657 ExFreePool(PsGetCurrentProcess()->VdmObjects
);
658 PsGetCurrentProcess()->VdmObjects
= NULL
;
661 return STATUS_SUCCESS
;
669 Ke386IoSetAccessProcess(IN PKPROCESS Process
,
674 KAFFINITY TargetProcessors
;
676 if(MapNumber
> IOPM_COUNT
)
679 MapOffset
= KiComputeIopmOffset(MapNumber
);
681 Process
->IopmOffset
= MapOffset
;
683 TargetProcessors
= Process
->ActiveProcessors
;
684 Prcb
= KeGetCurrentPrcb();
685 if (TargetProcessors
& Prcb
->SetMember
)
686 KeGetPcr()->TSS
->IoMapBase
= MapOffset
;
696 Ke386SetIoAccessMap(IN ULONG MapNumber
,
697 IN PKIO_ACCESS_MAP IopmBuffer
)
699 PKPROCESS CurrentProcess
;
703 if ((MapNumber
> IOPM_COUNT
) || (MapNumber
== IO_ACCESS_MAP_NONE
))
706 Prcb
= KeGetCurrentPrcb();
708 // Copy the IOP map and load the map for the current process.
709 pt
= &(KeGetPcr()->TSS
->IoMaps
[MapNumber
-1].IoMap
);
710 RtlMoveMemory(pt
, (PVOID
)IopmBuffer
, IOPM_SIZE
);
711 CurrentProcess
= Prcb
->CurrentThread
->ApcState
.Process
;
712 KeGetPcr()->TSS
->IoMapBase
= CurrentProcess
->IopmOffset
;
722 Ke386QueryIoAccessMap(IN ULONG MapNumber
,
723 IN PKIO_ACCESS_MAP IopmBuffer
)
729 if (MapNumber
> IOPM_COUNT
)
732 if (MapNumber
== IO_ACCESS_MAP_NONE
)
734 // no access, simply return a map of all 1s
735 p
= (PUCHAR
)IopmBuffer
;
736 for (i
= 0; i
< IOPM_SIZE
; i
++) {
743 Map
= (PVOID
)&(KeGetPcr()->TSS
->IoMaps
[MapNumber
-1].IoMap
);
744 RtlMoveMemory((PVOID
)IopmBuffer
, Map
, IOPM_SIZE
);