2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/vdm/vdmexec.c
5 * PURPOSE: Support for executing VDM code and context swapping.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
15 /* GLOBALS *******************************************************************/
19 /* FUNCTIONS *****************************************************************/
23 VdmpGetVdmTib(OUT PVDM_TIB
*VdmTib
)
31 /* Get the current TIB */
32 Tib
= NtCurrentTeb()->Vdm
;
33 if (!Tib
) return STATUS_INVALID_SYSTEM_SERVICE
;
35 /* Validate the size */
36 if (Tib
->Size
!= sizeof(VDM_TIB
)) return STATUS_INVALID_SYSTEM_SERVICE
;
40 return STATUS_SUCCESS
;
45 VdmSwapContext(IN PKTRAP_FRAME TrapFrame
,
46 IN PCONTEXT OutContext
,
47 IN PCONTEXT InContext
)
49 ULONG EFlags
, OldEFlags
;
51 /* Make sure that we're at APC_LEVEL and that this is a valid frame */
52 ASSERT(KeGetCurrentIrql() == APC_LEVEL
);
53 //ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
55 /* Check if this is a V86 frame */
56 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
58 /* Copy segment registers */
59 OutContext
->SegGs
= TrapFrame
->V86Gs
;
60 OutContext
->SegFs
= TrapFrame
->V86Fs
;
61 OutContext
->SegEs
= TrapFrame
->V86Es
;
62 OutContext
->SegDs
= TrapFrame
->V86Ds
;
64 else if (TrapFrame
->SegCs
!= (KGDT_R3_CODE
| RPL_MASK
))
66 /* This was kernel mode, copy segment registers */
67 OutContext
->SegGs
= TrapFrame
->SegGs
;
68 OutContext
->SegFs
= TrapFrame
->SegFs
;
69 OutContext
->SegEs
= TrapFrame
->SegEs
;
70 OutContext
->SegDs
= TrapFrame
->SegDs
;
74 OutContext
->SegCs
= TrapFrame
->SegCs
;
75 OutContext
->SegSs
= TrapFrame
->HardwareSegSs
;
77 /* Copy general purpose registers */
78 OutContext
->Eax
= TrapFrame
->Eax
;
79 OutContext
->Ebx
= TrapFrame
->Ebx
;
80 OutContext
->Ecx
= TrapFrame
->Ecx
;
81 OutContext
->Edx
= TrapFrame
->Edx
;
82 OutContext
->Esi
= TrapFrame
->Esi
;
83 OutContext
->Edi
= TrapFrame
->Edi
;
85 /* Copy stack and counter */
86 OutContext
->Ebp
= TrapFrame
->Ebp
;
87 OutContext
->Esp
= TrapFrame
->HardwareEsp
;
88 OutContext
->Eip
= TrapFrame
->Eip
;
90 /* Finally the flags */
91 OutContext
->EFlags
= TrapFrame
->EFlags
;
93 /* Now copy from the in frame to the trap frame */
94 TrapFrame
->SegCs
= InContext
->SegCs
;
95 TrapFrame
->HardwareSegSs
= InContext
->SegSs
;
97 /* Copy the general purpose registers */
98 TrapFrame
->Eax
= InContext
->Eax
;
99 TrapFrame
->Ebx
= InContext
->Ebx
;
100 TrapFrame
->Ecx
= InContext
->Ecx
;
101 TrapFrame
->Edx
= InContext
->Edx
;
102 TrapFrame
->Esi
= InContext
->Esi
;
103 TrapFrame
->Edi
= InContext
->Edi
;
105 /* Copy the stack and counter */
106 TrapFrame
->Ebp
= InContext
->Ebp
;
107 TrapFrame
->HardwareEsp
= InContext
->Esp
;
108 TrapFrame
->Eip
= InContext
->Eip
;
110 /* Check if the context is from V86 */
111 EFlags
= InContext
->EFlags
;
112 if (EFlags
& EFLAGS_V86_MASK
)
114 /* Sanitize the flags for V86 */
115 EFlags
&= KeI386EFlagsAndMaskV86
;
116 EFlags
|= KeI386EFlagsOrMaskV86
;
120 /* Add RPL_MASK to segments */
121 TrapFrame
->SegCs
|= RPL_MASK
;
122 TrapFrame
->HardwareSegSs
|= RPL_MASK
;
124 /* Check for bogus CS */
125 if (TrapFrame
->SegCs
< KGDT_R0_CODE
)
128 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
131 /* Sanitize flags and add interrupt mask */
132 EFlags
&= EFLAGS_USER_SANITIZE
;
133 EFlags
|=EFLAGS_INTERRUPT_MASK
;
136 /* Save the new eflags */
137 OldEFlags
= TrapFrame
->EFlags
;
138 TrapFrame
->EFlags
= EFlags
;
140 /* Check if we need to fixup ESP0 */
141 if ((OldEFlags
^ EFlags
) & EFLAGS_V86_MASK
)
144 Ki386AdjustEsp0(TrapFrame
);
147 /* Check if this is a V86 context */
148 if (InContext
->EFlags
& EFLAGS_V86_MASK
)
150 /* Copy VDM segments */
151 TrapFrame
->V86Gs
= InContext
->SegGs
;
152 TrapFrame
->V86Fs
= InContext
->SegFs
;
153 TrapFrame
->V86Es
= InContext
->SegEs
;
154 TrapFrame
->V86Ds
= InContext
->SegDs
;
158 /* Copy monitor segments */
159 TrapFrame
->SegGs
= InContext
->SegGs
;
160 TrapFrame
->SegFs
= InContext
->SegFs
;
161 TrapFrame
->SegEs
= InContext
->SegEs
;
162 TrapFrame
->SegDs
= InContext
->SegDs
;
165 /* Clear the exception list and return */
166 TrapFrame
->ExceptionList
= EXCEPTION_CHAIN_END
;
171 VdmpStartExecution(VOID
)
173 PETHREAD Thread
= PsGetCurrentThread();
174 PKTRAP_FRAME VdmFrame
;
182 /* Get the thread's VDM frame and TIB */
183 VdmFrame
= (PVOID
)((ULONG_PTR
)Thread
->Tcb
.InitialStack
-
184 sizeof(FX_SAVE_AREA
) -
185 sizeof(KTRAP_FRAME
));
186 Status
= VdmpGetVdmTib(&VdmTib
);
187 if (!NT_SUCCESS(Status
)) return STATUS_INVALID_SYSTEM_SERVICE
;
189 /* Go to APC level */
190 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
192 /* Check if interrupts are enabled */
193 Interrupts
= (BOOLEAN
)(VdmTib
->VdmContext
.EFlags
& EFLAGS_INTERRUPT_MASK
);
195 /* We don't support full VDM yet, this shouldn't happen */
196 ASSERT(*VdmState
== 0);
197 ASSERT(VdmTib
->VdmContext
.EFlags
& EFLAGS_V86_MASK
);
199 /* Check if VME is supported and V86 mode was enabled */
200 if ((KeI386VirtualIntExtensions
) &&
201 (VdmTib
->VdmContext
.EFlags
& EFLAGS_V86_MASK
))
203 /* Check if interrupts are enabled */
206 /* Set fake IF flag */
207 VdmTib
->VdmContext
.EFlags
|= EFLAGS_VIF
;
211 /* Remove fake IF flag, turn on real IF flag */
212 VdmTib
->VdmContext
.EFlags
&= ~EFLAGS_VIF
;
213 VdmTib
->VdmContext
.EFlags
|= EFLAGS_INTERRUPT_MASK
;
218 /* Set interrupt state in the VDM State */
219 if (VdmTib
->VdmContext
.EFlags
& EFLAGS_INTERRUPT_MASK
)
221 /* Enable them as well */
222 InterlockedOr((PLONG
)VdmState
, EFLAGS_INTERRUPT_MASK
);
227 InterlockedAnd((PLONG
)VdmState
, ~EFLAGS_INTERRUPT_MASK
);
230 /* Enable the interrupt flag */
231 VdmTib
->VdmContext
.EFlags
|= EFLAGS_INTERRUPT_MASK
;
234 /* Get the VDM context and make sure it's not an edited frame */
235 VdmContext
= VdmTib
->VdmContext
;
236 if (!(VdmContext
.SegCs
& FRAME_EDITED
))
239 KeLowerIrql(OldIrql
);
240 return STATUS_INVALID_SYSTEM_SERVICE
;
243 /* Now do the VDM Swap */
244 VdmSwapContext(VdmFrame
, &VdmTib
->MonitorContext
, &VdmContext
);
246 /* Lower the IRQL and return EAX */
247 KeLowerIrql(OldIrql
);
248 return VdmFrame
->Eax
;
253 VdmEndExecution(IN PKTRAP_FRAME TrapFrame
,
261 ASSERT((TrapFrame
->EFlags
& EFLAGS_V86_MASK
) ||
262 (TrapFrame
->SegCs
!= (KGDT_R3_CODE
| RPL_MASK
)));
264 /* Raise to APC_LEVEL */
265 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
268 VdmTib
->MonitorContext
.Eax
= STATUS_SUCCESS
;
270 /* Make a copy of the monitor context */
271 Context
= VdmTib
->MonitorContext
;
273 /* Check if V86 mode was enabled or the trap was edited */
274 if ((Context
.EFlags
& EFLAGS_V86_MASK
) || (Context
.SegCs
& FRAME_EDITED
))
276 /* Switch contexts */
277 VdmSwapContext(TrapFrame
, &VdmTib
->VdmContext
, &Context
);
279 /* Check if VME is supported and V86 mode was enabled */
280 if ((KeI386VirtualIntExtensions
) &&
281 (VdmTib
->VdmContext
.EFlags
& EFLAGS_V86_MASK
))
283 /* Check for VIF (virtual interrupt) flag state */
284 if (VdmTib
->VdmContext
.EFlags
& EFLAGS_VIF
)
286 /* Set real IF flag */
287 VdmTib
->VdmContext
.EFlags
|= EFLAGS_INTERRUPT_MASK
;
291 /* Remove real IF flag */
292 VdmTib
->VdmContext
.EFlags
&= ~EFLAGS_INTERRUPT_MASK
;
295 /* Turn off VIP and VIF */
296 TrapFrame
->EFlags
&= ~(EFLAGS_VIP
| EFLAGS_VIF
);
297 VdmTib
->VdmContext
.EFlags
&= ~(EFLAGS_VIP
| EFLAGS_VIF
);
301 /* Set the EFLAGS based on our software copy of EFLAGS */
302 VdmTib
->VdmContext
.EFlags
= (VdmTib
->VdmContext
.EFlags
& ~EFLAGS_INTERRUPT_MASK
) |
303 (*VdmState
& EFLAGS_INTERRUPT_MASK
);
307 /* Lower IRQL and reutrn */
308 KeLowerIrql(OldIrql
);
313 VdmDispatchBop(IN PKTRAP_FRAME TrapFrame
)
318 /* Check if this is from V86 mode */
319 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
321 /* Calculate flat EIP */
322 Eip
= (PUCHAR
)((TrapFrame
->Eip
& 0xFFFF) +
323 ((TrapFrame
->SegCs
& 0xFFFF) << 4));
325 /* Check if this is a BOP */
326 if (*(PUSHORT
)Eip
== 0xC4C4)
328 /* Check sure its the DOS Bop */
331 /* FIXME: No VDM Support */
335 /* Increase the number of BOP operations */
339 VdmTib
= NtCurrentTeb()->Vdm
;
341 /* Fill out a VDM Event */
342 VdmTib
->EventInfo
.InstructionSize
= 3;
343 VdmTib
->EventInfo
.BopNumber
= Eip
[2];
344 VdmTib
->EventInfo
.Event
= VdmBop
;
346 /* End VDM Execution */
347 VdmEndExecution(TrapFrame
, VdmTib
);
357 /* FIXME: Shouldn't happen on ROS */