ReactOS 0.4.16-dev-199-g898cc56
vdmexec.c
Go to the documentation of this file.
1/*
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)
7 */
8
9/* INCLUDES *****************************************************************/
10
11#include <ntoskrnl.h>
12#define NDEBUG
13#include <debug.h>
14
15/* GLOBALS *******************************************************************/
16
18
19/* FUNCTIONS *****************************************************************/
20
24{
25 PVDM_TIB Tib;
26 PAGED_CODE();
27
28 /* Assume vailure */
29 *VdmTib = NULL;
30
31 /* Get the current TIB */
32 Tib = NtCurrentTeb()->Vdm;
33 if (!Tib) return STATUS_INVALID_SYSTEM_SERVICE;
34
35 /* Validate the size */
36 if (Tib->Size != sizeof(VDM_TIB)) return STATUS_INVALID_SYSTEM_SERVICE;
37
38 /* Return it */
39 *VdmTib = Tib;
40 return STATUS_SUCCESS;
41}
42
43VOID
46 IN PCONTEXT OutContext,
47 IN PCONTEXT InContext)
48{
49 ULONG EFlags, OldEFlags;
50
51 /* Make sure that we're at APC_LEVEL and that this is a valid frame */
53 ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
54
55 /* Check if this is a V86 frame */
56 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
57 {
58 /* Copy segment registers */
59 OutContext->SegGs = TrapFrame->V86Gs;
60 OutContext->SegFs = TrapFrame->V86Fs;
61 OutContext->SegEs = TrapFrame->V86Es;
62 OutContext->SegDs = TrapFrame->V86Ds;
63 }
64 else if (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK))
65 {
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;
71 }
72
73 /* Copy CS and SS */
74 OutContext->SegCs = TrapFrame->SegCs;
75 OutContext->SegSs = TrapFrame->HardwareSegSs;
76
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;
84
85 /* Copy stack and counter */
86 OutContext->Ebp = TrapFrame->Ebp;
87 OutContext->Esp = TrapFrame->HardwareEsp;
88 OutContext->Eip = TrapFrame->Eip;
89
90 /* Finally the flags */
91 OutContext->EFlags = TrapFrame->EFlags;
92
93 /* Now copy from the in frame to the trap frame */
94 TrapFrame->SegCs = InContext->SegCs;
95 TrapFrame->HardwareSegSs = InContext->SegSs;
96
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;
104
105 /* Copy the stack and counter */
106 TrapFrame->Ebp = InContext->Ebp;
107 TrapFrame->HardwareEsp = InContext->Esp;
108 TrapFrame->Eip = InContext->Eip;
109
110 /* Check if the context is from V86 */
111 EFlags = InContext->EFlags;
112 if (EFlags & EFLAGS_V86_MASK)
113 {
114 /* Sanitize the flags for V86 */
115 EFlags &= KeI386EFlagsAndMaskV86;
116 EFlags |= KeI386EFlagsOrMaskV86;
117 }
118 else
119 {
120 /* Add RPL_MASK to segments */
121 TrapFrame->SegCs |= RPL_MASK;
122 TrapFrame->HardwareSegSs |= RPL_MASK;
123
124 /* Check for bogus CS */
125 if (TrapFrame->SegCs < KGDT_R0_CODE)
126 {
127 /* Set user-mode */
128 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
129 }
130
131 /* Sanitize flags and add interrupt mask */
132 EFlags &= EFLAGS_USER_SANITIZE;
133 EFlags |=EFLAGS_INTERRUPT_MASK;
134 }
135
136 /* Save the new eflags */
137 OldEFlags = TrapFrame->EFlags;
138 TrapFrame->EFlags = EFlags;
139
140 /* Check if we need to fixup ESP0 */
141 if ((OldEFlags ^ EFlags) & EFLAGS_V86_MASK)
142 {
143 /* Fix it up */
144 Ki386AdjustEsp0(TrapFrame);
145 }
146
147 /* Check if this is a V86 context */
148 if (InContext->EFlags & EFLAGS_V86_MASK)
149 {
150 /* Copy VDM segments */
151 TrapFrame->V86Gs = InContext->SegGs;
152 TrapFrame->V86Fs = InContext->SegFs;
153 TrapFrame->V86Es = InContext->SegEs;
154 TrapFrame->V86Ds = InContext->SegDs;
155 }
156 else
157 {
158 /* Copy monitor segments */
159 TrapFrame->SegGs = InContext->SegGs;
160 TrapFrame->SegFs = InContext->SegFs;
161 TrapFrame->SegEs = InContext->SegEs;
162 TrapFrame->SegDs = InContext->SegDs;
163 }
164
165 /* Clear the exception list and return */
166 TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
167}
168
170NTAPI
172{
174 PKTRAP_FRAME VdmFrame;
176 PVDM_TIB VdmTib;
177 BOOLEAN Interrupts;
179 CONTEXT VdmContext;
180 PAGED_CODE();
181
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);
188
189 /* Go to APC level */
191
192 /* Check if interrupts are enabled */
193 Interrupts = (BOOLEAN)(VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK);
194
195 /* We don't support full VDM yet, this shouldn't happen */
196 ASSERT(*VdmState == 0);
198
199 /* Check if VME is supported and V86 mode was enabled */
202 {
203 /* Check if interrupts are enabled */
204 if (Interrupts)
205 {
206 /* Set fake IF flag */
207 VdmTib->VdmContext.EFlags |= EFLAGS_VIF;
208 }
209 else
210 {
211 /* Remove fake IF flag, turn on real IF flag */
212 VdmTib->VdmContext.EFlags &= ~EFLAGS_VIF;
214 }
215 }
216 else
217 {
218 /* Set interrupt state in the VDM State */
220 {
221 /* Enable them as well */
223 }
224 else
225 {
226 /* Disable them */
228 }
229
230 /* Enable the interrupt flag */
232 }
233
234 /* Get the VDM context and make sure it's not an edited frame */
235 VdmContext = VdmTib->VdmContext;
236 if (!(VdmContext.SegCs & FRAME_EDITED))
237 {
238 /* Fail */
241 }
242
243 /* Now do the VDM Swap */
244 VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext);
245
246 /* Lower the IRQL and return EAX */
248 return VdmFrame->Eax;
249}
250
251VOID
252NTAPI
254 IN PVDM_TIB VdmTib)
255{
258 PAGED_CODE();
259
260 /* Sanity check */
261 ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
262 (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)));
263
264 /* Raise to APC_LEVEL */
266
267 /* Set success */
268 VdmTib->MonitorContext.Eax = STATUS_SUCCESS;
269
270 /* Make a copy of the monitor context */
271 Context = VdmTib->MonitorContext;
272
273 /* Check if V86 mode was enabled or the trap was edited */
274 if ((Context.EFlags & EFLAGS_V86_MASK) || (Context.SegCs & FRAME_EDITED))
275 {
276 /* Switch contexts */
277 VdmSwapContext(TrapFrame, &VdmTib->VdmContext, &Context);
278
279 /* Check if VME is supported and V86 mode was enabled */
281 (VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))
282 {
283 /* Check for VIF (virtual interrupt) flag state */
284 if (VdmTib->VdmContext.EFlags & EFLAGS_VIF)
285 {
286 /* Set real IF flag */
287 VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
288 }
289 else
290 {
291 /* Remove real IF flag */
292 VdmTib->VdmContext.EFlags &= ~EFLAGS_INTERRUPT_MASK;
293 }
294
295 /* Turn off VIP and VIF */
296 TrapFrame->EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
297 VdmTib->VdmContext.EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
298 }
299 else
300 {
301 /* Set the EFLAGS based on our software copy of EFLAGS */
302 VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~EFLAGS_INTERRUPT_MASK) |
304 }
305 }
306
307 /* Lower IRQL and reutrn */
309}
310
312NTAPI
314{
315 PUCHAR Eip;
316 PVDM_TIB VdmTib;
317
318 /* Check if this is from V86 mode */
319 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
320 {
321 /* Calculate flat EIP */
322 Eip = (PUCHAR)((TrapFrame->Eip & 0xFFFF) +
323 ((TrapFrame->SegCs & 0xFFFF) << 4));
324
325 /* Check if this is a BOP */
326 if (*(PUSHORT)Eip == 0xC4C4)
327 {
328 /* Check sure its the DOS Bop */
329 if (Eip[2] == 0x50)
330 {
331 /* FIXME: No VDM Support */
332 ASSERT(FALSE);
333 }
334
335 /* Increase the number of BOP operations */
336 VdmBopCount++;
337
338 /* Get the TIB */
339 VdmTib = NtCurrentTeb()->Vdm;
340
341 /* Fill out a VDM Event */
342 VdmTib->EventInfo.InstructionSize = 3;
343 VdmTib->EventInfo.BopNumber = Eip[2];
344 VdmTib->EventInfo.Event = VdmBop;
345
346 /* End VDM Execution */
347 VdmEndExecution(TrapFrame, VdmTib);
348 }
349 else
350 {
351 /* Not a BOP */
352 return FALSE;
353 }
354 }
355 else
356 {
357 /* FIXME: Shouldn't happen on ROS */
358 ASSERT(FALSE);
359 }
360
361 /* Return success */
362 return TRUE;
363}
364
366NTAPI
368 _In_ PKTRAP_FRAME TrapFrame)
369{
371 PVDM_TIB VdmTib;
372
373 PAGED_CODE();
374
375 /* Get the VDM TIB so we can terminate V86 execution */
376 Status = VdmpGetVdmTib(&VdmTib);
377 if (!NT_SUCCESS(Status))
378 {
379 /* Not a proper VDM fault, keep looking */
380 DPRINT1("VdmDispatchPageFault: no VDM TIB, Vdm=%p\n", NtCurrentTeb()->Vdm);
381 return FALSE;
382 }
383
384 /* Must be coming from V86 code */
385 ASSERT(TrapFrame->EFlags & EFLAGS_V86_MASK);
386
388 {
389 /* Fill out a VDM Event */
390 VdmTib->EventInfo.Event = VdmMemAccess;
391 VdmTib->EventInfo.InstructionSize = 0;
392
393 /* End VDM Execution */
394 VdmEndExecution(TrapFrame, VdmTib);
395 }
397 {
399 }
400 _SEH2_END;
401
402 /* Consider the exception handled if we succeeded */
403 DPRINT1("VdmDispatchPageFault EFlags %lx exit with 0x%lx\n", TrapFrame->EFlags, Status);
404 return NT_SUCCESS(Status);
405}
406
#define PAGED_CODE()
unsigned char BOOLEAN
#define EFLAGS_INTERRUPT_MASK
Definition: SystemCall.c:11
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
Status
Definition: gdiplustypes.h:25
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define InterlockedOr
Definition: interlocked.h:224
#define InterlockedAnd
Definition: interlocked.h:62
#define NtCurrentTeb
#define ASSERT(a)
Definition: mode.c:44
#define _In_
Definition: ms_sal.h:308
#define EFLAGS_USER_SANITIZE
Definition: ketypes.h:187
#define EFLAGS_V86_MASK
Definition: ketypes.h:182
#define EFLAGS_VIP
Definition: ketypes.h:185
#define EFLAGS_VIF
Definition: ketypes.h:184
#define RPL_MASK
Definition: ketypes.h:119
#define KGDT_R3_CODE
Definition: ketypes.h:125
struct _FX_SAVE_AREA FX_SAVE_AREA
#define KGDT_R0_CODE
Definition: ketypes.h:123
#define EXCEPTION_CHAIN_END
Definition: rtltypes.h:63
#define FRAME_EDITED
Definition: ke.h:68
BOOLEAN KeI386VirtualIntExtensions
Definition: v86vdm.c:24
ULONG KeI386EFlagsAndMaskV86
Definition: v86vdm.c:21
ULONG KeI386EFlagsOrMaskV86
Definition: v86vdm.c:22
VOID NTAPI Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame)
Definition: exp.c:280
@ VdmBop
Definition: vdm.h:60
@ VdmMemAccess
Definition: vdm.h:58
#define VdmState
Definition: vdm.h:48
#define STATUS_INVALID_SYSTEM_SERVICE
Definition: ntstatus.h:265
#define BOOLEAN
Definition: pedump.c:73
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:66
#define STATUS_SUCCESS
Definition: shellext.h:65
ULONG SegCs
Definition: nt_native.h:1477
ULONG EFlags
Definition: nt_native.h:1478
KTHREAD Tcb
Definition: pstypes.h:1104
PVOID InitialStack
Definition: ketypes.h:1664
ULONG Eax
Definition: ketypes.h:312
ULONG BopNumber
Definition: vdm.h:96
VDMEVENTCLASS Event
Definition: vdm.h:90
ULONG InstructionSize
Definition: vdm.h:91
Definition: vdm.h:135
ULONG Size
Definition: vdm.h:136
CONTEXT VdmContext
Definition: vdm.h:140
CONTEXT MonitorContext
Definition: vdm.h:139
VDMEVENTINFO EventInfo
Definition: vdm.h:141
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
uint16_t * PUSHORT
Definition: typedefs.h:56
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
int32_t * PLONG
Definition: typedefs.h:58
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
BOOLEAN NTAPI VdmDispatchPageFault(_In_ PKTRAP_FRAME TrapFrame)
Definition: vdmexec.c:367
BOOLEAN NTAPI VdmDispatchBop(IN PKTRAP_FRAME TrapFrame)
Definition: vdmexec.c:313
ULONG VdmBopCount
Definition: vdmexec.c:17
VOID NTAPI VdmEndExecution(IN PKTRAP_FRAME TrapFrame, IN PVDM_TIB VdmTib)
Definition: vdmexec.c:253
NTSTATUS NTAPI VdmpGetVdmTib(OUT PVDM_TIB *VdmTib)
Definition: vdmexec.c:23
VOID NTAPI VdmSwapContext(IN PKTRAP_FRAME TrapFrame, IN PCONTEXT OutContext, IN PCONTEXT InContext)
Definition: vdmexec.c:45
NTSTATUS NTAPI VdmpStartExecution(VOID)
Definition: vdmexec.c:171
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778