ReactOS  0.4.12-dev-36-g472787f
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 
22 NTAPI
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 
43 VOID
44 NTAPI
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 
169 NTSTATUS
170 NTAPI
172 {
174  PKTRAP_FRAME VdmFrame;
176  PVDM_TIB VdmTib;
177  BOOLEAN Interrupts;
178  KIRQL OldIrql;
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);
187  if (!NT_SUCCESS(Status)) return STATUS_INVALID_SYSTEM_SERVICE;
188 
189  /* Go to APC level */
190  KeRaiseIrql(APC_LEVEL, &OldIrql);
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 */
201  (VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))
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 */
239  KeLowerIrql(OldIrql);
241  }
242 
243  /* Now do the VDM Swap */
244  VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext);
245 
246  /* Lower the IRQL and return EAX */
247  KeLowerIrql(OldIrql);
248  return VdmFrame->Eax;
249 }
250 
251 VOID
252 NTAPI
254  IN PVDM_TIB VdmTib)
255 {
256  KIRQL OldIrql;
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 */
265  KeRaiseIrql(APC_LEVEL, &OldIrql);
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 */
308  KeLowerIrql(OldIrql);
309 }
310 
311 BOOLEAN
312 NTAPI
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 
365 BOOLEAN
366 NTAPI
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 
387  _SEH2_TRY
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  {
398  Status = _SEH2_GetExceptionCode();
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 KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define IN
Definition: typedefs.h:38
#define InterlockedAnd
Definition: interlocked.h:62
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define TRUE
Definition: types.h:120
Definition: vdm.h:134
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
ULONG BopNumber
Definition: vdm.h:96
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define VdmState
Definition: vdm.h:48
VDMEVENTCLASS Event
Definition: vdm.h:90
unsigned char * PUCHAR
Definition: retypes.h:3
BOOLEAN NTAPI VdmDispatchPageFault(_In_ PKTRAP_FRAME TrapFrame)
Definition: vdmexec.c:367
CONTEXT VdmContext
Definition: vdm.h:140
LONG NTSTATUS
Definition: precomp.h:26
KTHREAD Tcb
Definition: pstypes.h:1034
ULONG KeI386EFlagsOrMaskV86
Definition: v86vdm.c:22
VOID NTAPI Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame)
Definition: exp.c:280
#define KGDT_R0_CODE
Definition: ketypes.h:74
ULONG VdmBopCount
Definition: vdmexec.c:17
ULONG Size
Definition: vdm.h:136
#define PAGED_CODE()
Definition: video.h:57
#define EFLAGS_V86_MASK
Definition: ketypes.h:129
_SEH2_TRY
Definition: create.c:4250
uint32_t ULONG_PTR
Definition: typedefs.h:63
BOOLEAN NTAPI VdmDispatchBop(IN PKTRAP_FRAME TrapFrame)
Definition: vdmexec.c:313
#define EFLAGS_VIP
Definition: ketypes.h:132
UCHAR KIRQL
Definition: env_spec_w32.h:591
ULONG Eax
Definition: ketypes.h:256
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define EFLAGS_USER_SANITIZE
Definition: ketypes.h:133
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define RPL_MASK
Definition: ketypes.h:69
ULONG SegCs
Definition: nt_native.h:1477
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
ULONG EFlags
Definition: nt_native.h:1478
void * PVOID
Definition: retypes.h:9
VDMEVENTINFO EventInfo
Definition: vdm.h:141
struct _FX_SAVE_AREA FX_SAVE_AREA
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
Definition: vdm.h:60
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
CONTEXT MonitorContext
Definition: vdm.h:139
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define EFLAGS_VIF
Definition: ketypes.h:131
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define InterlockedOr
Definition: interlocked.h:224
Status
Definition: gdiplustypes.h:24
#define _In_
Definition: no_sal2.h:204
_SEH2_END
Definition: create.c:4424
#define EXCEPTION_CHAIN_END
Definition: rtltypes.h:63
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
ULONG KeI386EFlagsAndMaskV86
Definition: v86vdm.c:21
VOID NTAPI VdmSwapContext(IN PKTRAP_FRAME TrapFrame, IN PCONTEXT OutContext, IN PCONTEXT InContext)
Definition: vdmexec.c:45
NTSTATUS NTAPI VdmpGetVdmTib(OUT PVDM_TIB *VdmTib)
Definition: vdmexec.c:23
#define DPRINT1
Definition: precomp.h:8
ULONG InstructionSize
Definition: vdm.h:91
#define KGDT_R3_CODE
Definition: ketypes.h:76
#define BOOLEAN
Definition: pedump.c:73
#define OUT
Definition: typedefs.h:39
struct tagContext Context
Definition: acpixf.h:1027
NTSTATUS NTAPI VdmpStartExecution(VOID)
Definition: vdmexec.c:171
unsigned int ULONG
Definition: retypes.h:1
#define STATUS_INVALID_SYSTEM_SERVICE
Definition: ntstatus.h:251
#define FRAME_EDITED
Definition: ke.h:64
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
return STATUS_SUCCESS
Definition: btrfs.c:2710
BOOLEAN KeI386VirtualIntExtensions
Definition: v86vdm.c:24
signed int * PLONG
Definition: retypes.h:5
PVOID InitialStack
Definition: ketypes.h:1554
VOID NTAPI VdmEndExecution(IN PKTRAP_FRAME TrapFrame, IN PVDM_TIB VdmTib)
Definition: vdmexec.c:253
#define APC_LEVEL
Definition: env_spec_w32.h:695
unsigned short * PUSHORT
Definition: retypes.h:2
#define EFLAGS_INTERRUPT_MASK
Definition: ketypes.h:126