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
;
75 /* Check for OPER32 */
76 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
80 *(PULONG
)(Esp
- 2) = V86EFlags
;
85 *(PUSHORT
)Esp
= (USHORT
)V86EFlags
;
88 /* Set new ESP and EIP */
89 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
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
;
107 EFlags
= *(PULONG
)Esp
;
110 /* Check for OPER32 */
111 if (!(KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
))
113 /* Read correct flags and use correct stack address */
119 TrapFrame
->HardwareEsp
= Esp
;
121 /* Mask out IOPL from the flags */
122 EFlags
&= ~EFLAGS_IOPL
;
124 /* Save the V86 flags, but mask out the nested task flag */
125 V86EFlags
= EFlags
& ~EFLAGS_NESTED_TASK
;
127 /* Now leave only alignment, nested task and interrupt flag */
128 EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
130 /* Get trap EFlags */
131 TrapEFlags
= TrapFrame
->EFlags
;
133 /* Check for VME support */
134 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
136 /* Add V86 and Interrupt flag */
137 V86EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
139 /* Update EFlags in trap frame */
140 TrapFrame
->EFlags
|= V86EFlags
;
142 /* Check if ESP0 needs to be fixed up */
143 if (TrapEFlags
& EFLAGS_V86_MASK
) Ki386AdjustEsp0(TrapFrame
);
145 /* Update the V8086 EFlags state */
146 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
147 KiVdmSetVdmEFlags(EFlags
);
149 /* FIXME: Check for VDM interrupts */
152 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
160 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame
,
163 ULONG Esp
, V86EFlags
, TrapEFlags
, Eip
, Interrupt
;
165 /* Read trap frame EFlags */
166 TrapEFlags
= TrapFrame
->EFlags
;
168 /* Remove interrupt flag from V8086 EFlags */
169 V86EFlags
= *KiNtVdmState
;
170 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
172 /* Keep only alignment and interrupt flag from the V8086 state */
173 V86EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_INTERRUPT_MASK
);
175 /* Check for VME support */
176 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
178 /* Mask in the relevant V86 EFlags into the trap flags */
179 V86EFlags
|= (TrapEFlags
& ~EFLAGS_INTERRUPT_MASK
);
181 /* And mask out the VIF, nested task and TF flag from the trap flags */
182 TrapFrame
->EFlags
= TrapEFlags
&~ (EFLAGS_VIF
| EFLAGS_NESTED_TASK
| EFLAGS_TF
);
184 /* Add the IOPL flag to the local trap flags */
185 V86EFlags
|= EFLAGS_IOPL
;
188 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
192 *(PUSHORT
)(Esp
) = (USHORT
)V86EFlags
;
196 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->SegCs
;
200 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->Eip
+ KiVdmGetInstructionSize(Flags
) + 1;
203 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
206 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
208 /* Now get the *next* EIP address (current is original + the count - 1) */
209 Eip
+= KiVdmGetInstructionSize(Flags
);
211 /* Now read the interrupt number */
212 Interrupt
= *(PUCHAR
)Eip
;
214 /* Read the EIP from its IVT entry */
215 Interrupt
= *(PULONG
)(Interrupt
* 4);
216 TrapFrame
->Eip
= (USHORT
)Interrupt
;
218 /* Now get the CS segment */
219 Interrupt
= (USHORT
)(Interrupt
>> 16);
221 /* Check if the trap was not V8086 trap */
222 if (!(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
224 /* Was it a kernel CS? */
225 Interrupt
|= RPL_MASK
;
226 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
228 /* Add the RPL mask */
229 TrapFrame
->SegCs
= Interrupt
;
234 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
240 TrapFrame
->SegCs
= Interrupt
;
249 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame
,
252 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
, Eip
;
255 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
257 /* Check for OPER32 */
258 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
260 /* Build segmented EIP */
261 TrapFrame
->Eip
= *(PULONG
)Esp
;
262 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 4);
265 TrapFrame
->HardwareEsp
+= 12;
268 EFlags
= *(PULONG
)(Esp
+ 8);
272 /* Build segmented EIP */
273 TrapFrame
->Eip
= *(PUSHORT
)Esp
;
274 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 2);
277 TrapFrame
->HardwareEsp
+= 6;
280 EFlags
= *(PUSHORT
)(Esp
+ 4);
283 /* Mask out EFlags */
284 EFlags
&= ~(EFLAGS_IOPL
+ EFLAGS_VIF
+ EFLAGS_NESTED_TASK
+ EFLAGS_VIP
);
287 /* Check for VME support */
288 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
290 /* Add V86 and Interrupt flag */
291 EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
293 /* Update EFlags in trap frame */
294 TrapEFlags
= TrapFrame
->EFlags
;
295 TrapFrame
->EFlags
= (TrapFrame
->EFlags
& EFLAGS_VIP
) | EFlags
;
297 /* Check if ESP0 needs to be fixed up */
298 if (!(TrapEFlags
& EFLAGS_V86_MASK
)) Ki386AdjustEsp0(TrapFrame
);
300 /* Update the V8086 EFlags state */
301 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
302 KiVdmSetVdmEFlags(V86EFlags
);
304 /* Build flat EIP and check if this is the BOP instruction */
305 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
306 if (*(PUSHORT
)Eip
== 0xC4C4)
308 /* Dispatch the BOP */
309 VdmDispatchBop(TrapFrame
);
313 /* FIXME: Check for VDM interrupts */
322 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame
,
325 /* Check for VME support */
326 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
328 /* Disable interrupts */
329 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
331 /* Skip instruction */
332 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
340 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame
,
343 /* Check for VME support */
344 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
346 /* Enable interrupts */
347 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK
);
349 /* Skip instruction */
350 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
356 /* MASTER OPCODE HANDLER ******************************************************/
360 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame
,
365 /* Get flat EIP of the *current* instruction (not the original EIP) */
366 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
367 Eip
+= KiVdmGetInstructionSize(Flags
) - 1;
369 /* Read the opcode entry */
370 switch (*(PUCHAR
)Eip
)
372 case 0xF: return KiCallVdmHandler(F
);
373 case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES
);
374 case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS
);
375 case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS
);
376 case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS
);
377 case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS
);
378 case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS
);
379 case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32
);
380 case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32
);
381 case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK
);
382 case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE
);
383 case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP
);
384 case 0x6C: return KiCallVdmHandler(INSB
);
385 case 0x6D: return KiCallVdmHandler(INSW
);
386 case 0x6E: return KiCallVdmHandler(OUTSB
);
387 case 0x6F: return KiCallVdmHandler(OUTSW
);
388 case 0x98: return KiCallVdmHandler(NPX
);
389 case 0xD8: return KiCallVdmHandler(NPX
);
390 case 0xD9: return KiCallVdmHandler(NPX
);
391 case 0xDA: return KiCallVdmHandler(NPX
);
392 case 0xDB: return KiCallVdmHandler(NPX
);
393 case 0xDC: return KiCallVdmHandler(NPX
);
394 case 0xDD: return KiCallVdmHandler(NPX
);
395 case 0xDE: return KiCallVdmHandler(NPX
);
396 case 0xDF: return KiCallVdmHandler(NPX
);
397 case 0x9C: return KiCallVdmHandler(PUSHF
);
398 case 0x9D: return KiCallVdmHandler(POPF
);
399 case 0xCD: return KiCallVdmHandler(INTnn
);
400 case 0xCE: return KiCallVdmHandler(INTO
);
401 case 0xCF: return KiCallVdmHandler(IRET
);
402 case 0xE4: return KiCallVdmHandler(INBimm
);
403 case 0xE5: return KiCallVdmHandler(INWimm
);
404 case 0xE6: return KiCallVdmHandler(OUTBimm
);
405 case 0xE7: return KiCallVdmHandler(OUTWimm
);
406 case 0xEC: return KiCallVdmHandler(INB
);
407 case 0xED: return KiCallVdmHandler(INW
);
408 case 0xEE: return KiCallVdmHandler(OUTB
);
409 case 0xEF: return KiCallVdmHandler(OUTW
);
410 case 0xF4: return KiCallVdmHandler(HLT
);
411 case 0xFA: return KiCallVdmHandler(CLI
);
412 case 0xFB: return KiCallVdmHandler(STI
);
413 default: return KiCallVdmHandler(INV
);
417 /* PREFIX HANDLER *************************************************************/
421 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame
,
424 /* Increase instruction size */
427 /* Handle the next opcode */
428 return KiVdmHandleOpcode(TrapFrame
, Flags
);
431 /* TRAP HANDLER ***************************************************************/
435 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame
)
438 TrapFrame
->Eip
&= 0xFFFF;
439 TrapFrame
->HardwareEsp
&= 0xFFFF;
441 /* We start with only 1 byte per instruction */
442 return KiVdmHandleOpcode(TrapFrame
, 1);
447 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame
)
449 PKV8086_STACK_FRAME StackFrame
;
452 PKTRAP_FRAME PmTrapFrame
;
453 PKV86_FRAME V86Frame
;
454 PFX_SAVE_AREA NpxFrame
;
456 /* Get the stack frame back */
457 StackFrame
= CONTAINING_RECORD(TrapFrame
->Esi
, KV8086_STACK_FRAME
, V86Frame
);
458 PmTrapFrame
= &StackFrame
->TrapFrame
;
459 V86Frame
= &StackFrame
->V86Frame
;
460 NpxFrame
= &StackFrame
->NpxArea
;
462 /* Copy the FPU frame back */
463 Thread
= KeGetCurrentThread();
464 RtlCopyMemory(KiGetThreadNpxArea(Thread
), NpxFrame
, sizeof(FX_SAVE_AREA
));
466 /* Set initial stack back */
467 Thread
->InitialStack
= (PVOID
)((ULONG_PTR
)V86Frame
->ThreadStack
+ sizeof(FX_SAVE_AREA
));
469 /* Set ESP0 back in the KTSS */
470 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&PmTrapFrame
->V86Es
;
472 /* Restore TEB addresses */
473 Thread
->Teb
= V86Frame
->ThreadTeb
;
474 KeGetPcr()->NtTib
.Self
= V86Frame
->PcrTeb
;
476 /* Setup real TEB descriptor */
477 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
478 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Thread
->Teb
& 0xFFFF);
479 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 16);
480 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 24);
482 /* Enable interrupts and return a pointer to the trap frame */
484 return (ULONG
)PmTrapFrame
;
489 KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame
)
493 PKTRAP_FRAME TrapFrame
= &StackFrame
->TrapFrame
;
494 PKV86_FRAME V86Frame
= &StackFrame
->V86Frame
;
495 PFX_SAVE_AREA NpxFrame
= &StackFrame
->NpxArea
;
497 /* Build fake user-mode trap frame */
498 TrapFrame
->SegCs
= KGDT_R0_CODE
| RPL_MASK
;
499 TrapFrame
->SegEs
= TrapFrame
->SegDs
= TrapFrame
->SegFs
= TrapFrame
->SegGs
= 0;
500 TrapFrame
->ErrCode
= 0;
502 /* Get the current thread's initial stack */
503 Thread
= KeGetCurrentThread();
504 V86Frame
->ThreadStack
= KiGetThreadNpxArea(Thread
);
506 /* Save TEB addresses */
507 V86Frame
->ThreadTeb
= Thread
->Teb
;
508 V86Frame
->PcrTeb
= KeGetPcr()->NtTib
.Self
;
510 /* Save return EIP */
511 TrapFrame
->Eip
= (ULONG_PTR
)Ki386BiosCallReturnAddress
;
513 /* Save our stack (after the frames) */
514 TrapFrame
->Esi
= (ULONG_PTR
)V86Frame
;
515 TrapFrame
->Edi
= (ULONG_PTR
)_AddressOfReturnAddress() + 4;
517 /* Sanitize EFlags and enable interrupts */
518 TrapFrame
->EFlags
= __readeflags() & 0x60DD7;
519 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
521 /* Fill out the rest of the frame */
522 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
523 TrapFrame
->HardwareEsp
= 0x11FFE;
524 TrapFrame
->ExceptionList
= EXCEPTION_CHAIN_END
;
526 //TrapFrame->DbgArgMark = 0xBADB0D00;
527 TrapFrame
->PreviousPreviousMode
= -1;
529 /* Disable interrupts */
532 /* Copy the thread's NPX frame */
533 RtlCopyMemory(NpxFrame
, V86Frame
->ThreadStack
, sizeof(FX_SAVE_AREA
));
535 /* Clear exception list */
536 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
539 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&TrapFrame
->V86Es
;
541 /* Set new initial stack */
542 Thread
->InitialStack
= V86Frame
;
545 Thread
->Teb
= (PTEB
)TRAMPOLINE_TEB
;
546 KeGetPcr()->NtTib
.Self
= (PVOID
)TRAMPOLINE_TEB
;
548 /* Setup VDM TEB descriptor */
549 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
550 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)TRAMPOLINE_TEB
& 0xFFFF);
551 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 16);
552 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 24);
554 /* Enable interrupts */
557 /* Start VDM execution */
558 NtVdmControl(VdmStartExecution
, NULL
);
560 /* Exit to V86 mode */
561 KiEoiHelper(TrapFrame
);
564 /* PUBLIC FUNCTIONS ***********************************************************/
571 Ke386CallBios(IN ULONG Int
,
572 OUT PCONTEXT Context
)
574 PUCHAR Trampoline
= (PUCHAR
)TRAMPOLINE_BASE
;
575 PTEB VdmTeb
= (PTEB
)TRAMPOLINE_TEB
;
576 PVDM_TIB VdmTib
= (PVDM_TIB
)TRAMPOLINE_TIB
;
577 ULONG ContextSize
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
578 PKTHREAD Thread
= KeGetCurrentThread();
579 PKTSS Tss
= KeGetPcr()->TSS
;
580 PKPROCESS Process
= Thread
->ApcState
.Process
;
581 PVDM_PROCESS_OBJECTS VdmProcessObjects
;
582 USHORT OldOffset
, OldBase
;
584 /* Start with a clean TEB */
585 RtlZeroMemory(VdmTeb
, sizeof(TEB
));
587 /* Write the interrupt and bop */
588 *Trampoline
++ = 0xCD;
589 *Trampoline
++ = (UCHAR
)Int
;
590 *(PULONG
)Trampoline
= TRAMPOLINE_BOP
;
592 /* Setup the VDM TEB and TIB */
593 VdmTeb
->Vdm
= (PVOID
)TRAMPOLINE_TIB
;
594 RtlZeroMemory(VdmTib
, sizeof(VDM_TIB
));
595 VdmTib
->Size
= sizeof(VDM_TIB
);
597 /* Set a blank VDM state */
600 /* Copy the context */
601 RtlCopyMemory(&VdmTib
->VdmContext
, Context
, ContextSize
);
602 VdmTib
->VdmContext
.SegCs
= (ULONG_PTR
)Trampoline
>> 4;
603 VdmTib
->VdmContext
.SegSs
= (ULONG_PTR
)Trampoline
>> 4;
604 VdmTib
->VdmContext
.Eip
= 0;
605 VdmTib
->VdmContext
.Esp
= 2 * PAGE_SIZE
- sizeof(ULONG_PTR
);
606 VdmTib
->VdmContext
.EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
607 VdmTib
->VdmContext
.ContextFlags
= CONTEXT_FULL
;
609 /* This can't be a real VDM process */
610 ASSERT(PsGetCurrentProcess()->VdmObjects
== NULL
);
612 /* Allocate VDM structure */
613 VdmProcessObjects
= ExAllocatePoolWithTag(NonPagedPool
,
614 sizeof(VDM_PROCESS_OBJECTS
),
616 if (!VdmProcessObjects
) return STATUS_NO_MEMORY
;
619 RtlZeroMemory(VdmProcessObjects
, sizeof(VDM_PROCESS_OBJECTS
));
620 VdmProcessObjects
->VdmTib
= VdmTib
;
621 PsGetCurrentProcess()->VdmObjects
= VdmProcessObjects
;
623 /* Set the system affinity for the current thread */
624 KeSetSystemAffinityThread(1);
626 /* Make sure there's space for two IOPMs, then copy & clear the current */
627 ASSERT(((PKIPCR
)KeGetPcr())->GDT
[KGDT_TSS
/ 8].LimitLow
>=
628 (0x2000 + IOPM_OFFSET
- 1));
629 RtlCopyMemory(Ki386IopmSaveArea
, &Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
630 RtlZeroMemory(&Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
632 /* Save the old offset and base, and set the new ones */
633 OldOffset
= Process
->IopmOffset
;
634 OldBase
= Tss
->IoMapBase
;
635 Process
->IopmOffset
= (USHORT
)IOPM_OFFSET
;
636 Tss
->IoMapBase
= (USHORT
)IOPM_OFFSET
;
638 /* Switch stacks and work the magic */
639 Ki386SetupAndExitToV86Mode(VdmTeb
);
642 RtlCopyMemory(&Tss
->IoMaps
[0].IoMap
, Ki386IopmSaveArea
, PAGE_SIZE
* 2);
643 Process
->IopmOffset
= OldOffset
;
644 Tss
->IoMapBase
= OldBase
;
646 /* Restore affinity */
647 KeRevertToUserAffinityThread();
649 /* Restore context */
650 RtlCopyMemory(Context
, &VdmTib
->VdmContext
, ContextSize
);
651 Context
->ContextFlags
= CONTEXT_FULL
;
653 /* Free VDM objects */
654 ExFreePool(PsGetCurrentProcess()->VdmObjects
);
655 PsGetCurrentProcess()->VdmObjects
= NULL
;
658 return STATUS_SUCCESS
;
666 Ke386IoSetAccessProcess(IN PKPROCESS Process
,
678 Ke386SetIoAccessMap(IN ULONG Flag
,
690 Ke386QueryIoAccessMap(IN ULONG Flag
,