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
- 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
;
106 /* Check for OPER32 */
107 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
110 EFlags
= *(PULONG
)Esp
;
116 EFlags
= *(PUSHORT
)Esp
;
118 /* Read correct flags and use correct stack address */
123 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
125 /* Mask out IOPL from the flags */
126 EFlags
&= ~EFLAGS_IOPL
;
128 /* Save the V86 flags, but mask out the nested task flag */
129 V86EFlags
= EFlags
& ~EFLAGS_NESTED_TASK
;
131 /* Now leave only alignment, nested task and interrupt flag */
132 EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
134 /* Get trap EFlags */
135 TrapEFlags
= TrapFrame
->EFlags
;
137 /* Check for VME support */
138 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
140 /* Add V86 and Interrupt flag */
141 V86EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
143 /* Update EFlags in trap frame */
144 TrapFrame
->EFlags
= V86EFlags
;
146 /* Check if ESP0 needs to be fixed up */
147 if (TrapEFlags
& EFLAGS_V86_MASK
) Ki386AdjustEsp0(TrapFrame
);
149 /* Update the V8086 EFlags state */
150 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK
| EFLAGS_NESTED_TASK
| EFLAGS_INTERRUPT_MASK
);
151 KiVdmSetVdmEFlags(EFlags
);
153 /* FIXME: Check for VDM interrupts */
156 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
164 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame
,
167 ULONG Esp
, V86EFlags
, TrapEFlags
, Eip
, Interrupt
;
169 /* Read trap frame EFlags */
170 TrapEFlags
= TrapFrame
->EFlags
;
172 /* Remove interrupt flag from V8086 EFlags */
173 V86EFlags
= *KiNtVdmState
;
174 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
176 /* Keep only alignment and interrupt flag from the V8086 state */
177 V86EFlags
&= (EFLAGS_ALIGN_CHECK
| EFLAGS_INTERRUPT_MASK
);
179 /* Check for VME support */
180 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
182 /* Mask in the relevant V86 EFlags into the trap flags */
183 V86EFlags
|= (TrapEFlags
& ~EFLAGS_INTERRUPT_MASK
);
185 /* And mask out the VIF, nested task and TF flag from the trap flags */
186 TrapFrame
->EFlags
= TrapEFlags
&~ (EFLAGS_VIF
| EFLAGS_NESTED_TASK
| EFLAGS_TF
);
188 /* Add the IOPL flag to the local trap flags */
189 V86EFlags
|= EFLAGS_IOPL
;
192 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
196 *(PUSHORT
)(Esp
) = (USHORT
)V86EFlags
;
200 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->SegCs
;
204 *(PUSHORT
)(Esp
) = (USHORT
)TrapFrame
->Eip
+ KiVdmGetInstructionSize(Flags
) + 1;
207 TrapFrame
->HardwareEsp
= (USHORT
)Esp
;
210 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
212 /* Now get the *next* EIP address (current is original + the count - 1) */
213 Eip
+= KiVdmGetInstructionSize(Flags
);
215 /* Now read the interrupt number */
216 Interrupt
= *(PUCHAR
)Eip
;
218 /* Read the EIP from its IVT entry */
219 Interrupt
= *(PULONG
)(Interrupt
* 4);
220 TrapFrame
->Eip
= (USHORT
)Interrupt
;
222 /* Now get the CS segment */
223 Interrupt
= (USHORT
)(Interrupt
>> 16);
225 /* Check if the trap was not V8086 trap */
226 if (!(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
228 /* Was it a kernel CS? */
229 Interrupt
|= RPL_MASK
;
230 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
232 /* Add the RPL mask */
233 TrapFrame
->SegCs
= Interrupt
;
238 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
244 TrapFrame
->SegCs
= Interrupt
;
253 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame
,
256 ULONG Esp
, V86EFlags
, EFlags
, TrapEFlags
, Eip
;
259 Esp
= (TrapFrame
->HardwareSegSs
<< 4) + TrapFrame
->HardwareEsp
;
261 /* Check for OPER32 */
262 if (KiVdmGetPrefixFlags(Flags
) & PFX_FLAG_OPER32
)
264 /* Build segmented EIP */
265 TrapFrame
->Eip
= *(PULONG
)Esp
;
266 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 4);
269 TrapFrame
->HardwareEsp
+= 12;
272 EFlags
= *(PULONG
)(Esp
+ 8);
276 /* Build segmented EIP */
277 TrapFrame
->Eip
= *(PUSHORT
)Esp
;
278 TrapFrame
->SegCs
= *(PUSHORT
)(Esp
+ 2);
281 TrapFrame
->HardwareEsp
+= 6;
284 EFlags
= *(PUSHORT
)(Esp
+ 4);
287 /* Mask out EFlags */
288 EFlags
&= ~(EFLAGS_IOPL
+ EFLAGS_VIF
+ EFLAGS_NESTED_TASK
+ EFLAGS_VIP
);
291 /* Check for VME support */
292 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
294 /* Add V86 and Interrupt flag */
295 EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
297 /* Update EFlags in trap frame */
298 TrapEFlags
= TrapFrame
->EFlags
;
299 TrapFrame
->EFlags
= (TrapFrame
->EFlags
& EFLAGS_VIP
) | EFlags
;
301 /* Check if ESP0 needs to be fixed up */
302 if (!(TrapEFlags
& EFLAGS_V86_MASK
)) Ki386AdjustEsp0(TrapFrame
);
304 /* Update the V8086 EFlags state */
305 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
306 KiVdmSetVdmEFlags(V86EFlags
);
308 /* Build flat EIP and check if this is the BOP instruction */
309 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
310 if (*(PUSHORT
)Eip
== 0xC4C4)
312 /* Dispatch the BOP */
313 VdmDispatchBop(TrapFrame
);
317 /* FIXME: Check for VDM interrupts */
318 DPRINT("FIXME: Check for VDM interrupts\n");
327 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame
,
330 /* Check for VME support */
331 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
333 /* Disable interrupts */
334 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK
);
336 /* Skip instruction */
337 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
345 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame
,
348 /* Check for VME support */
349 ASSERT(KeI386VirtualIntExtensions
== FALSE
);
351 /* Enable interrupts */
352 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK
);
354 /* Skip instruction */
355 TrapFrame
->Eip
+= KiVdmGetInstructionSize(Flags
);
361 /* MASTER OPCODE HANDLER ******************************************************/
365 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame
,
370 /* Get flat EIP of the *current* instruction (not the original EIP) */
371 Eip
= (TrapFrame
->SegCs
<< 4) + TrapFrame
->Eip
;
372 Eip
+= KiVdmGetInstructionSize(Flags
) - 1;
374 /* Read the opcode entry */
375 switch (*(PUCHAR
)Eip
)
377 case 0xF: return KiCallVdmHandler(F
);
378 case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES
);
379 case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS
);
380 case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS
);
381 case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS
);
382 case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS
);
383 case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS
);
384 case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32
);
385 case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32
);
386 case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK
);
387 case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE
);
388 case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP
);
389 case 0x6C: return KiCallVdmHandler(INSB
);
390 case 0x6D: return KiCallVdmHandler(INSW
);
391 case 0x6E: return KiCallVdmHandler(OUTSB
);
392 case 0x6F: return KiCallVdmHandler(OUTSW
);
393 case 0x98: return KiCallVdmHandler(NPX
);
394 case 0xD8: return KiCallVdmHandler(NPX
);
395 case 0xD9: return KiCallVdmHandler(NPX
);
396 case 0xDA: return KiCallVdmHandler(NPX
);
397 case 0xDB: return KiCallVdmHandler(NPX
);
398 case 0xDC: return KiCallVdmHandler(NPX
);
399 case 0xDD: return KiCallVdmHandler(NPX
);
400 case 0xDE: return KiCallVdmHandler(NPX
);
401 case 0xDF: return KiCallVdmHandler(NPX
);
402 case 0x9C: return KiCallVdmHandler(PUSHF
);
403 case 0x9D: return KiCallVdmHandler(POPF
);
404 case 0xCD: return KiCallVdmHandler(INTnn
);
405 case 0xCE: return KiCallVdmHandler(INTO
);
406 case 0xCF: return KiCallVdmHandler(IRET
);
407 case 0xE4: return KiCallVdmHandler(INBimm
);
408 case 0xE5: return KiCallVdmHandler(INWimm
);
409 case 0xE6: return KiCallVdmHandler(OUTBimm
);
410 case 0xE7: return KiCallVdmHandler(OUTWimm
);
411 case 0xEC: return KiCallVdmHandler(INB
);
412 case 0xED: return KiCallVdmHandler(INW
);
413 case 0xEE: return KiCallVdmHandler(OUTB
);
414 case 0xEF: return KiCallVdmHandler(OUTW
);
415 case 0xF4: return KiCallVdmHandler(HLT
);
416 case 0xFA: return KiCallVdmHandler(CLI
);
417 case 0xFB: return KiCallVdmHandler(STI
);
418 default: return KiCallVdmHandler(INV
);
422 /* PREFIX HANDLER *************************************************************/
426 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame
,
429 /* Increase instruction size */
432 /* Handle the next opcode */
433 return KiVdmHandleOpcode(TrapFrame
, Flags
);
436 /* TRAP HANDLER ***************************************************************/
440 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame
)
443 TrapFrame
->Eip
&= 0xFFFF;
444 TrapFrame
->HardwareEsp
&= 0xFFFF;
446 /* We start with only 1 byte per instruction */
447 return KiVdmHandleOpcode(TrapFrame
, 1);
452 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame
)
454 PKV8086_STACK_FRAME StackFrame
;
457 PKTRAP_FRAME PmTrapFrame
;
458 PKV86_FRAME V86Frame
;
459 PFX_SAVE_AREA NpxFrame
;
461 /* Get the stack frame back */
462 StackFrame
= CONTAINING_RECORD(TrapFrame
->Esi
, KV8086_STACK_FRAME
, V86Frame
);
463 PmTrapFrame
= &StackFrame
->TrapFrame
;
464 V86Frame
= &StackFrame
->V86Frame
;
465 NpxFrame
= &StackFrame
->NpxArea
;
467 /* Copy the FPU frame back */
468 Thread
= KeGetCurrentThread();
469 RtlCopyMemory(KiGetThreadNpxArea(Thread
), NpxFrame
, sizeof(FX_SAVE_AREA
));
471 /* Set initial stack back */
472 Thread
->InitialStack
= (PVOID
)((ULONG_PTR
)V86Frame
->ThreadStack
+ sizeof(FX_SAVE_AREA
));
474 /* Set ESP0 back in the KTSS */
475 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&PmTrapFrame
->V86Es
;
477 /* Restore TEB addresses */
478 Thread
->Teb
= V86Frame
->ThreadTeb
;
479 KeGetPcr()->NtTib
.Self
= V86Frame
->PcrTeb
;
481 /* Setup real TEB descriptor */
482 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
483 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Thread
->Teb
& 0xFFFF);
484 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 16);
485 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Thread
->Teb
>> 24);
487 /* Enable interrupts and return a pointer to the trap frame */
489 return (ULONG
)PmTrapFrame
;
494 KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame
)
498 PKTRAP_FRAME TrapFrame
= &StackFrame
->TrapFrame
;
499 PKV86_FRAME V86Frame
= &StackFrame
->V86Frame
;
500 PFX_SAVE_AREA NpxFrame
= &StackFrame
->NpxArea
;
502 /* Build fake user-mode trap frame */
503 TrapFrame
->SegCs
= KGDT_R0_CODE
| RPL_MASK
;
504 TrapFrame
->SegEs
= TrapFrame
->SegDs
= TrapFrame
->SegFs
= TrapFrame
->SegGs
= 0;
505 TrapFrame
->ErrCode
= 0;
507 /* Get the current thread's initial stack */
508 Thread
= KeGetCurrentThread();
509 V86Frame
->ThreadStack
= KiGetThreadNpxArea(Thread
);
511 /* Save TEB addresses */
512 V86Frame
->ThreadTeb
= Thread
->Teb
;
513 V86Frame
->PcrTeb
= KeGetPcr()->NtTib
.Self
;
515 /* Save return EIP */
516 TrapFrame
->Eip
= (ULONG_PTR
)Ki386BiosCallReturnAddress
;
518 /* Save our stack (after the frames) */
519 TrapFrame
->Esi
= (ULONG_PTR
)V86Frame
;
520 TrapFrame
->Edi
= (ULONG_PTR
)_AddressOfReturnAddress() + 4;
522 /* Sanitize EFlags and enable interrupts */
523 TrapFrame
->EFlags
= __readeflags() & 0x60DD7;
524 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
526 /* Fill out the rest of the frame */
527 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
528 TrapFrame
->HardwareEsp
= 0x11FFE;
529 TrapFrame
->ExceptionList
= EXCEPTION_CHAIN_END
;
531 //TrapFrame->DbgArgMark = 0xBADB0D00;
532 TrapFrame
->PreviousPreviousMode
= -1;
534 /* Disable interrupts */
537 /* Copy the thread's NPX frame */
538 RtlCopyMemory(NpxFrame
, V86Frame
->ThreadStack
, sizeof(FX_SAVE_AREA
));
540 /* Clear exception list */
541 KeGetPcr()->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
544 KeGetPcr()->TSS
->Esp0
= (ULONG_PTR
)&TrapFrame
->V86Es
;
546 /* Set new initial stack */
547 Thread
->InitialStack
= V86Frame
;
550 Thread
->Teb
= (PTEB
)TRAMPOLINE_TEB
;
551 KeGetPcr()->NtTib
.Self
= (PVOID
)TRAMPOLINE_TEB
;
553 /* Setup VDM TEB descriptor */
554 GdtEntry
= &((PKIPCR
)KeGetPcr())->GDT
[KGDT_R3_TEB
/ sizeof(KGDTENTRY
)];
555 GdtEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)TRAMPOLINE_TEB
& 0xFFFF);
556 GdtEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 16);
557 GdtEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)TRAMPOLINE_TEB
>> 24);
559 /* Enable interrupts */
562 /* Start VDM execution */
563 NtVdmControl(VdmStartExecution
, NULL
);
565 /* Exit to V86 mode */
566 KiEoiHelper(TrapFrame
);
569 /* PUBLIC FUNCTIONS ***********************************************************/
576 Ke386CallBios(IN ULONG Int
,
577 OUT PCONTEXT Context
)
579 PUCHAR Trampoline
= (PUCHAR
)TRAMPOLINE_BASE
;
580 PTEB VdmTeb
= (PTEB
)TRAMPOLINE_TEB
;
581 PVDM_TIB VdmTib
= (PVDM_TIB
)TRAMPOLINE_TIB
;
582 ULONG ContextSize
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
583 PKTHREAD Thread
= KeGetCurrentThread();
584 PKTSS Tss
= KeGetPcr()->TSS
;
585 PKPROCESS Process
= Thread
->ApcState
.Process
;
586 PVDM_PROCESS_OBJECTS VdmProcessObjects
;
587 USHORT OldOffset
, OldBase
;
589 /* Start with a clean TEB */
590 RtlZeroMemory(VdmTeb
, sizeof(TEB
));
592 /* Write the interrupt and bop */
593 *Trampoline
++ = 0xCD;
594 *Trampoline
++ = (UCHAR
)Int
;
595 *(PULONG
)Trampoline
= TRAMPOLINE_BOP
;
597 /* Setup the VDM TEB and TIB */
598 VdmTeb
->Vdm
= (PVOID
)TRAMPOLINE_TIB
;
599 RtlZeroMemory(VdmTib
, sizeof(VDM_TIB
));
600 VdmTib
->Size
= sizeof(VDM_TIB
);
602 /* Set a blank VDM state */
605 /* Copy the context */
606 RtlCopyMemory(&VdmTib
->VdmContext
, Context
, ContextSize
);
607 VdmTib
->VdmContext
.SegCs
= (ULONG_PTR
)Trampoline
>> 4;
608 VdmTib
->VdmContext
.SegSs
= (ULONG_PTR
)Trampoline
>> 4;
609 VdmTib
->VdmContext
.Eip
= 0;
610 VdmTib
->VdmContext
.Esp
= 2 * PAGE_SIZE
- sizeof(ULONG_PTR
);
611 VdmTib
->VdmContext
.EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
612 VdmTib
->VdmContext
.ContextFlags
= CONTEXT_FULL
;
614 /* This can't be a real VDM process */
615 ASSERT(PsGetCurrentProcess()->VdmObjects
== NULL
);
617 /* Allocate VDM structure */
618 VdmProcessObjects
= ExAllocatePoolWithTag(NonPagedPool
,
619 sizeof(VDM_PROCESS_OBJECTS
),
621 if (!VdmProcessObjects
) return STATUS_NO_MEMORY
;
624 RtlZeroMemory(VdmProcessObjects
, sizeof(VDM_PROCESS_OBJECTS
));
625 VdmProcessObjects
->VdmTib
= VdmTib
;
626 PsGetCurrentProcess()->VdmObjects
= VdmProcessObjects
;
628 /* Set the system affinity for the current thread */
629 KeSetSystemAffinityThread(1);
631 /* Make sure there's space for two IOPMs, then copy & clear the current */
632 ASSERT(((PKIPCR
)KeGetPcr())->GDT
[KGDT_TSS
/ 8].LimitLow
>=
633 (0x2000 + IOPM_OFFSET
- 1));
634 RtlCopyMemory(Ki386IopmSaveArea
, &Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
635 RtlZeroMemory(&Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
637 /* Save the old offset and base, and set the new ones */
638 OldOffset
= Process
->IopmOffset
;
639 OldBase
= Tss
->IoMapBase
;
640 Process
->IopmOffset
= (USHORT
)IOPM_OFFSET
;
641 Tss
->IoMapBase
= (USHORT
)IOPM_OFFSET
;
643 /* Switch stacks and work the magic */
644 Ki386SetupAndExitToV86Mode(VdmTeb
);
647 RtlCopyMemory(&Tss
->IoMaps
[0].IoMap
, Ki386IopmSaveArea
, PAGE_SIZE
* 2);
648 Process
->IopmOffset
= OldOffset
;
649 Tss
->IoMapBase
= OldBase
;
651 /* Restore affinity */
652 KeRevertToUserAffinityThread();
654 /* Restore context */
655 RtlCopyMemory(Context
, &VdmTib
->VdmContext
, ContextSize
);
656 Context
->ContextFlags
= CONTEXT_FULL
;
658 /* Free VDM objects */
659 ExFreePool(PsGetCurrentProcess()->VdmObjects
);
660 PsGetCurrentProcess()->VdmObjects
= NULL
;
663 return STATUS_SUCCESS
;
671 Ke386IoSetAccessProcess(IN PKPROCESS Process
,
676 KAFFINITY TargetProcessors
;
678 if(MapNumber
> IOPM_COUNT
)
681 MapOffset
= KiComputeIopmOffset(MapNumber
);
683 Process
->IopmOffset
= MapOffset
;
685 TargetProcessors
= Process
->ActiveProcessors
;
686 Prcb
= KeGetCurrentPrcb();
687 if (TargetProcessors
& Prcb
->SetMember
)
688 KeGetPcr()->TSS
->IoMapBase
= MapOffset
;
698 Ke386SetIoAccessMap(IN ULONG MapNumber
,
699 IN PKIO_ACCESS_MAP IopmBuffer
)
701 PKPROCESS CurrentProcess
;
705 if ((MapNumber
> IOPM_COUNT
) || (MapNumber
== IO_ACCESS_MAP_NONE
))
708 Prcb
= KeGetCurrentPrcb();
710 // Copy the IOP map and load the map for the current process.
711 pt
= &(KeGetPcr()->TSS
->IoMaps
[MapNumber
-1].IoMap
);
712 RtlMoveMemory(pt
, (PVOID
)IopmBuffer
, IOPM_SIZE
);
713 CurrentProcess
= Prcb
->CurrentThread
->ApcState
.Process
;
714 KeGetPcr()->TSS
->IoMapBase
= CurrentProcess
->IopmOffset
;
724 Ke386QueryIoAccessMap(IN ULONG MapNumber
,
725 IN PKIO_ACCESS_MAP IopmBuffer
)
731 if (MapNumber
> IOPM_COUNT
)
734 if (MapNumber
== IO_ACCESS_MAP_NONE
)
736 // no access, simply return a map of all 1s
737 p
= (PUCHAR
)IopmBuffer
;
738 for (i
= 0; i
< IOPM_SIZE
; i
++) {
745 Map
= (PVOID
)&(KeGetPcr()->TSS
->IoMaps
[MapNumber
-1].IoMap
);
746 RtlMoveMemory((PVOID
)IopmBuffer
, Map
, IOPM_SIZE
);