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 /* GLOBALS ********************************************************************/
18 ULONG KeI386EFlagsAndMaskV86
= EFLAGS_USER_SANITIZE
;
19 ULONG KeI386EFlagsOrMaskV86
= EFLAGS_INTERRUPT_MASK
;
20 PVOID Ki386IopmSaveArea
;
21 BOOLEAN KeI386VirtualIntExtensions
= FALSE
;
22 const PULONG KiNtVdmState
= (PULONG
)FIXED_NTVDMSTATE_LINEAR_PC_AT
;
24 /* UNHANDLED OPCODES **********************************************************/
26 KiVdmUnhandledOpcode(F
);
27 KiVdmUnhandledOpcode(OUTSW
);
28 KiVdmUnhandledOpcode(OUTSB
);
29 KiVdmUnhandledOpcode(INSB
);
30 KiVdmUnhandledOpcode(INSW
);
31 KiVdmUnhandledOpcode(NPX
);
32 KiVdmUnhandledOpcode(INBimm
);
33 KiVdmUnhandledOpcode(INWimm
);
34 KiVdmUnhandledOpcode(OUTBimm
);
35 KiVdmUnhandledOpcode(OUTWimm
);
36 KiVdmUnhandledOpcode(INB
);
37 KiVdmUnhandledOpcode(INW
);
38 KiVdmUnhandledOpcode(OUTB
);
39 KiVdmUnhandledOpcode(OUTW
);
40 KiVdmUnhandledOpcode(HLT
);
41 KiVdmUnhandledOpcode(INTO
);
42 KiVdmUnhandledOpcode(INV
);
44 /* OPCODE HANDLERS ************************************************************/
48 KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame
,
51 ULONG Esp
, V86EFlags
, TrapEFlags
;
53 /* Get current V8086 flags and mask out interrupt flag */
54 V86EFlags
= *KiNtVdmState
;
55 V86EFlags
&= ~EFLAGS_INTERRUPT_MASK
;
57 /* Get trap frame EFLags and leave only align, nested task and interrupt */
58 TrapEFlags
= TrapFrame
->EFlags
;
59 TrapEFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
61 /* Add in those flags if they exist, and add in the IOPL flag */
62 V86EFlags
|= TrapEFlags
;
63 V86EFlags
|= EFLAGS_IOPL
;
66 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + (USHORT
)TrapFrame
->HardwareEsp
;
69 /* Check for OPER32 */
70 if (Flags
& PFX_FLAG_OPER32
)
74 *(PULONG
)(Esp
- 2) = V86EFlags
;
79 *(PUSHORT
)Esp
= (USHORT
)V86EFlags
;
82 /* Set new ESP and EIP */
83 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
84 TrapFrame
->Eip
+= (Flags
& 0xFF);
92 KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame
,
95 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
;
98 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + (USHORT
)TrapFrame
->HardwareEsp
;
101 EFlags
= *(PULONG
)Esp
;
104 /* Check for OPER32 */
105 if (!(Flags
& PFX_FLAG_OPER32
))
107 /* Read correct flags and use correct stack address */
113 TrapFrame
->HardwareEsp
= Esp
;
115 /* Mask out IOPL from the flags */
116 EFlags
&= ~EFLAGS_IOPL
;
118 /* Save the V86 flags, but mask out the nested task flag */
119 V86EFlags
= EFlags
& ~EFLAGS_NESTED_TASK
;
121 /* Now leave only alignment, nested task and interrupt flag */
122 EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
124 /* FIXME: Check for VME support */
126 /* Add V86 and Interrupt flag */
127 V86EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
129 /* Update EFlags in trap frame */
130 TrapEFlags
= TrapFrame
->EFlags
;
131 TrapFrame
->EFlags
= (TrapFrame
->EFlags
& EFLAGS_VIP
) | V86EFlags
;
133 /* Check if ESP0 needs to be fixed up */
134 if (TrapEFlags
& EFLAGS_V86_MASK
) Ki386AdjustEsp0(TrapFrame
);
136 /* Update the V8086 EFlags state */
137 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
138 KiVdmSetVdmEFlags(EFlags
);
140 /* FIXME: Check for VDM interrupts */
143 TrapFrame
->Eip
+= (Flags
& 0xFF);
151 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame
,
154 ULONG Esp
, V86EFlags
, TrapEFlags
, Eip
, Interrupt
;
156 /* Read trap frame EFlags */
157 TrapEFlags
= TrapFrame
->EFlags
;
159 /* Remove interrupt flag from V8086 EFlags */
160 V86EFlags
= *KiNtVdmState
;
161 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
163 /* Keep only alignment and interrupt flag from the V8086 state */
164 V86EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_INTERRUPT_MASK
);
166 /* FIXME: Support VME */
168 /* Mask in the relevant V86 EFlags into the trap flags */
169 V86EFlags
|= (TrapEFlags
& ~EFLAGS_INTERRUPT_MASK
);
171 /* And mask out the VIF, nested task and TF flag from the trap flags */
172 TrapFrame
->EFlags
= TrapEFlags
&~ (EFLAGS_VIF
| EFLAGS_NESTED_TASK
| EFLAGS_TF
);
174 /* Add the IOPL flag to the local trap flags */
175 V86EFlags
|= EFLAGS_IOPL
;
178 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
182 *(PUSHORT
)(Esp
) = (USHORT
)V86EFlags
;
186 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->SegCs
;
190 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->Eip
+ (Flags
& 0xFF) + 1;
193 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
196 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
198 /* Now get the *next* EIP address (current is original + the count - 1) */
199 Eip
+= (Flags
& 0xFF);
201 /* Now read the interrupt number */
202 Interrupt
= *(PUCHAR
)Eip
;
204 /* Read the EIP from its IVT entry */
205 Interrupt
= *(PULONG
)(Interrupt
* 4);
206 TrapFrame
->Eip
= (USHORT
)Interrupt
;
208 /* Now get the CS segment */
209 Interrupt
= (USHORT
)(Interrupt
>> 16);
211 /* Check if the trap was not V8086 trap */
212 if (!(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
214 /* Was it a kernel CS? */
215 Interrupt
|= RPL_MASK
;
216 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
218 /* Add the RPL mask */
219 TrapFrame
->SegCs
= Interrupt
;
224 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
230 TrapFrame
->SegCs
= Interrupt
;
239 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame
,
242 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
, Eip
;
245 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
247 /* Check for OPER32 */
248 if (Flags
& PFX_FLAG_OPER32
)
250 /* Build segmented EIP */
251 TrapFrame
->Eip
= *(PULONG
)Esp
;
252 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 4);
255 TrapFrame
->HardwareEsp
+= 12;
258 EFlags
= *(PULONG
)(Esp
+ 8);
262 /* Build segmented EIP */
263 TrapFrame
->Eip
= *(PUSHORT
)Esp
;
264 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 2);
267 TrapFrame
->HardwareEsp
+= 6;
270 EFlags
= *(PUSHORT
)(Esp
+ 4);
273 /* Mask out EFlags */
274 EFlags
&= ~(EFLAGS_IOPL
+ EFLAGS_VIF
+ EFLAGS_NESTED_TASK
+ EFLAGS_VIP
);
277 /* FIXME: Check for VME support */
279 /* Add V86 and Interrupt flag */
280 EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
282 /* Update EFlags in trap frame */
283 TrapEFlags
= TrapFrame
->EFlags
;
284 TrapFrame
->EFlags
= (TrapFrame
->EFlags
& EFLAGS_VIP
) | EFlags
;
286 /* Check if ESP0 needs to be fixed up */
287 if (!(TrapEFlags
& EFLAGS_V86_MASK
)) Ki386AdjustEsp0(TrapFrame
);
289 /* Update the V8086 EFlags state */
290 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
291 KiVdmSetVdmEFlags(V86EFlags
);
293 /* Build flat EIP and check if this is the BOP instruction */
294 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
295 if (*(PUSHORT
)Eip
== 0xC4C4)
297 /* Dispatch the BOP */
298 VdmDispatchBop(TrapFrame
);
302 /* FIXME: Check for VDM interrupts */
311 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame
,
314 /* FIXME: Support VME */
316 /* disable interrupts */
317 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
319 /* Skip instruction */
320 TrapFrame
->Eip
+= (Flags
& 0xFF);
328 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame
,
331 /* FIXME: Support VME */
333 /* Enable interrupts */
334 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK
);
336 /* Skip instruction */
337 TrapFrame
->Eip
+= (Flags
& 0xFF);
343 /* MASTER OPCODE HANDLER ******************************************************/
347 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame
,
352 /* Get flat EIP of the *current* instruction (not the original EIP) */
353 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
354 Eip
+= (Flags
& 0xFF) - 1;
356 /* Read the opcode entry */
357 switch (*(PUCHAR
)Eip
)
359 case 0xF: return KiCallVdmHandler(F
);
360 case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES
);
361 case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS
);
362 case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS
);
363 case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS
);
364 case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS
);
365 case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS
);
366 case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32
);
367 case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32
);
368 case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK
);
369 case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE
);
370 case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP
);
371 case 0x6C: return KiCallVdmHandler(INSB
);
372 case 0x6D: return KiCallVdmHandler(INSW
);
373 case 0x6E: return KiCallVdmHandler(OUTSB
);
374 case 0x6F: return KiCallVdmHandler(OUTSW
);
375 case 0x98: return KiCallVdmHandler(NPX
);
376 case 0xD8: return KiCallVdmHandler(NPX
);
377 case 0xD9: return KiCallVdmHandler(NPX
);
378 case 0xDA: return KiCallVdmHandler(NPX
);
379 case 0xDB: return KiCallVdmHandler(NPX
);
380 case 0xDC: return KiCallVdmHandler(NPX
);
381 case 0xDD: return KiCallVdmHandler(NPX
);
382 case 0xDE: return KiCallVdmHandler(NPX
);
383 case 0xDF: return KiCallVdmHandler(NPX
);
384 case 0x9C: return KiCallVdmHandler(PUSHF
);
385 case 0x9D: return KiCallVdmHandler(POPF
);
386 case 0xCD: return KiCallVdmHandler(INTnn
);
387 case 0xCE: return KiCallVdmHandler(INTO
);
388 case 0xCF: return KiCallVdmHandler(IRET
);
389 case 0xE4: return KiCallVdmHandler(INBimm
);
390 case 0xE5: return KiCallVdmHandler(INWimm
);
391 case 0xE6: return KiCallVdmHandler(OUTBimm
);
392 case 0xE7: return KiCallVdmHandler(OUTWimm
);
393 case 0xEC: return KiCallVdmHandler(INB
);
394 case 0xED: return KiCallVdmHandler(INW
);
395 case 0xEE: return KiCallVdmHandler(OUTB
);
396 case 0xEF: return KiCallVdmHandler(OUTW
);
397 case 0xF4: return KiCallVdmHandler(HLT
);
398 case 0xFA: return KiCallVdmHandler(CLI
);
399 case 0xFB: return KiCallVdmHandler(STI
);
400 default: return KiCallVdmHandler(INV
);
404 /* PREFIX HANDLER *************************************************************/
408 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame
,
411 /* Increase instruction size */
414 /* Handle the next opcode */
415 return KiVdmHandleOpcode(TrapFrame
, Flags
);
418 /* TRAP HANDLER ***************************************************************/
422 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame
)
425 TrapFrame
->Eip
&= 0xFFFF;
426 TrapFrame
->HardwareEsp
&= 0xFFFF;
428 /* We start with only 1 byte per instruction */
429 return KiVdmHandleOpcode(TrapFrame
, 1);
434 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame
)
436 PKV8086_STACK_FRAME StackFrame
;
439 PKTRAP_FRAME PmTrapFrame
;
440 PKV86_FRAME V86Frame
;
441 PFX_SAVE_AREA NpxFrame
;
443 /* Get the stack frame back */
444 StackFrame
= CONTAINING_RECORD(TrapFrame
->Esi
, KV8086_STACK_FRAME
, V86Frame
);
445 PmTrapFrame
= &StackFrame
->TrapFrame
;
446 V86Frame
= &StackFrame
->V86Frame
;
447 NpxFrame
= &StackFrame
->NpxArea
;
449 /* Copy the FPU frame back */
450 Thread
= KeGetCurrentThread();
451 RtlCopyMemory(KiGetThreadNpxArea(Thread
), NpxFrame
, sizeof(FX_SAVE_AREA
));
453 /* Set initial stack back */
454 Thread
->InitialStack
= (PVOID
)((ULONG_PTR
)V86Frame
->ThreadStack
+ sizeof(FX_SAVE_AREA
));
456 /* Set ESP0 back in the KTSS */
457 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&PmTrapFrame
->V86Es
;
459 /* Restore TEB addresses */
460 Thread
->Teb
= V86Frame
->ThreadTeb
;
461 KeGetPcr()->Tib
.Self
= V86Frame
->PcrTeb
;
463 /* Setup real TEB descriptor */
464 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
465 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Thread
->Teb
& 0xFFFF);
466 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 16);
467 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 24);
469 /* Enable interrupts and get back to protected mode */
471 KiV86TrapReturn(TrapFrame
->Edi
);
480 KV8086_STACK_FRAME StackFrameBuffer
;
481 PKV8086_STACK_FRAME StackFrame
= &StackFrameBuffer
;
482 PKTRAP_FRAME TrapFrame
= &StackFrame
->TrapFrame
;
483 PKV86_FRAME V86Frame
= &StackFrame
->V86Frame
;
484 PFX_SAVE_AREA NpxFrame
= &StackFrame
->NpxArea
;
486 /* Build fake user-mode trap frame */
487 TrapFrame
->SegCs
= KGDT_R0_CODE
| RPL_MASK
;
488 TrapFrame
->SegEs
= TrapFrame
->SegDs
= TrapFrame
->SegFs
= TrapFrame
->SegGs
= 0;
489 TrapFrame
->ErrCode
= 0;
491 /* Get the current thread's initial stack */
492 Thread
= KeGetCurrentThread();
493 V86Frame
->ThreadStack
= KiGetThreadNpxArea(Thread
);
495 /* Save TEB addresses */
496 V86Frame
->ThreadTeb
= Thread
->Teb
;
497 V86Frame
->PcrTeb
= KeGetPcr()->Tib
.Self
;
499 /* Save return EIP */
500 TrapFrame
->Eip
= (ULONG_PTR
)KiExitV86Mode
;
502 /* Save our stack (after the frames) */
503 TrapFrame
->Esi
= (ULONG_PTR
)V86Frame
;
504 TrapFrame
->Edi
= (ULONG_PTR
)_AddressOfReturnAddress() + 4;
506 /* Sanitize EFlags and enable interrupts */
507 TrapFrame
->EFlags
= __readeflags() & 0x60DD7;
508 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
510 /* Fill out the rest of the frame */
511 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
512 TrapFrame
->HardwareEsp
= 0x11FFE;
513 TrapFrame
->ExceptionList
= EXCEPTION_CHAIN_END
;
515 //TrapFrame->DbgArgMark = 0xBADB0D00;
516 TrapFrame
->PreviousPreviousMode
= -1;
518 /* Disable interrupts */
521 /* Copy the thread's NPX frame */
522 RtlCopyMemory(NpxFrame
, V86Frame
->ThreadStack
, sizeof(FX_SAVE_AREA
));
524 /* Clear exception list */
525 KeGetPcr()->Tib
.ExceptionList
= EXCEPTION_CHAIN_END
;
528 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&TrapFrame
->V86Es
;
530 /* Set new initial stack */
531 Thread
->InitialStack
= V86Frame
;
534 Thread
->Teb
= (PTEB
)TRAMPOLINE_TEB
;
535 KeGetPcr()->Tib
.Self
= (PVOID
)TRAMPOLINE_TEB
;
537 /* Setup VDM TEB descriptor */
538 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
539 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)TRAMPOLINE_TEB
& 0xFFFF);
540 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 16);
541 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 24);
543 /* Enable interrupts */
546 /* Start VDM execution */
547 NtVdmControl(VdmStartExecution
, NULL
);
549 /* Exit to V86 mode */
550 KiEoiHelper(TrapFrame
);
553 /* PUBLIC FUNCTIONS ***********************************************************/
560 Ke386CallBios(IN ULONG Int
,
561 OUT PCONTEXT Context
)
563 PUCHAR Trampoline
= (PUCHAR
)TRAMPOLINE_BASE
;
564 PTEB VdmTeb
= (PTEB
)TRAMPOLINE_TEB
;
565 PVDM_TIB VdmTib
= (PVDM_TIB
)TRAMPOLINE_TIB
;
566 ULONG ContextSize
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
567 PKTHREAD Thread
= KeGetCurrentThread();
568 PKTSS Tss
= KeGetPcr()->TSS
;
569 PKPROCESS Process
= Thread
->ApcState
.Process
;
570 PVDM_PROCESS_OBJECTS VdmProcessObjects
;
571 USHORT OldOffset
, OldBase
;
573 /* Start with a clean TEB */
574 RtlZeroMemory(VdmTeb
, sizeof(TEB
));
576 /* Write the interrupt and bop */
577 *Trampoline
++ = 0xCD;
578 *Trampoline
++ = (UCHAR
)Int
;
579 *(PULONG
)Trampoline
= TRAMPOLINE_BOP
;
581 /* Setup the VDM TEB and TIB */
582 VdmTeb
->Vdm
= (PVOID
)TRAMPOLINE_TIB
;
583 RtlZeroMemory(VdmTib
, sizeof(VDM_TIB
));
584 VdmTib
->Size
= sizeof(VDM_TIB
);
586 /* Set a blank VDM state */
589 /* Copy the context */
590 RtlCopyMemory(&VdmTib
->VdmContext
, Context
, ContextSize
);
591 VdmTib
->VdmContext
.SegCs
= (ULONG_PTR
)Trampoline
>> 4;
592 VdmTib
->VdmContext
.SegSs
= (ULONG_PTR
)Trampoline
>> 4;
593 VdmTib
->VdmContext
.Eip
= 0;
594 VdmTib
->VdmContext
.Esp
= 2 * PAGE_SIZE
- sizeof(ULONG_PTR
);
595 VdmTib
->VdmContext
.EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
596 VdmTib
->VdmContext
.ContextFlags
= CONTEXT_FULL
;
598 /* This can't be a real VDM process */
599 ASSERT(PsGetCurrentProcess()->VdmObjects
== NULL
);
601 /* Allocate VDM structure */
602 VdmProcessObjects
= ExAllocatePoolWithTag(NonPagedPool
,
603 sizeof(VDM_PROCESS_OBJECTS
),
605 if (!VdmProcessObjects
) return STATUS_NO_MEMORY
;
608 RtlZeroMemory(VdmProcessObjects
, sizeof(VDM_PROCESS_OBJECTS
));
609 VdmProcessObjects
->VdmTib
= VdmTib
;
610 PsGetCurrentProcess()->VdmObjects
= VdmProcessObjects
;
612 /* Set the system affinity for the current thread */
613 KeSetSystemAffinityThread(1);
615 /* Make sure there's space for two IOPMs, then copy & clear the current */
616 ASSERT(((PKIPCR
)KeGetPcr())->GDT
[KGDT_TSS
/ 8].LimitLow
>=
617 (0x2000 + IOPM_OFFSET
- 1));
618 RtlCopyMemory(Ki386IopmSaveArea
, &Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
619 RtlZeroMemory(&Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
621 /* Save the old offset and base, and set the new ones */
622 OldOffset
= Process
->IopmOffset
;
623 OldBase
= Tss
->IoMapBase
;
624 Process
->IopmOffset
= (USHORT
)IOPM_OFFSET
;
625 Tss
->IoMapBase
= (USHORT
)IOPM_OFFSET
;
627 /* Switch stacks and work the magic */
628 Ki386SetupAndExitToV86Mode(VdmTeb
);
631 RtlCopyMemory(&Tss
->IoMaps
[0].IoMap
, Ki386IopmSaveArea
, PAGE_SIZE
* 2);
632 Process
->IopmOffset
= OldOffset
;
633 Tss
->IoMapBase
= OldBase
;
635 /* Restore affinity */
636 KeRevertToUserAffinityThread();
638 /* Restore context */
639 RtlCopyMemory(Context
, &VdmTib
->VdmContext
, ContextSize
);
640 Context
->ContextFlags
= CONTEXT_FULL
;
642 /* Free VDM objects */
643 ExFreePool(PsGetCurrentProcess()->VdmObjects
);
644 PsGetCurrentProcess()->VdmObjects
= NULL
;
647 return STATUS_SUCCESS
;
655 Ke386IoSetAccessProcess(IN PKPROCESS Process
,
667 Ke386SetIoAccessMap(IN ULONG Flag
,
679 Ke386QueryIoAccessMap(IN ULONG Flag
,