ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

vdmexec.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/vdm/vdmexec.c
00005  * PURPOSE:         Support for executing VDM code and context swapping.
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  */
00008 
00009 /* INCLUDES *****************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* GLOBALS *******************************************************************/
00016 
00017 ULONG VdmBopCount;
00018 
00019 /* FUNCTIONS *****************************************************************/
00020 
00021 NTSTATUS
00022 NTAPI
00023 VdmpGetVdmTib(OUT PVDM_TIB *VdmTib)
00024 {
00025     PVDM_TIB Tib;
00026     PAGED_CODE();
00027 
00028     /* Assume vailure */
00029     *VdmTib = NULL;
00030 
00031     /* Get the current TIB */
00032     Tib = NtCurrentTeb()->Vdm;
00033     if (!Tib) return STATUS_INVALID_SYSTEM_SERVICE;
00034 
00035     /* Validate the size */
00036     if (Tib->Size != sizeof(VDM_TIB)) return STATUS_INVALID_SYSTEM_SERVICE;
00037 
00038     /* Return it */
00039     *VdmTib = Tib;
00040     return STATUS_SUCCESS;
00041 }
00042 
00043 VOID
00044 NTAPI
00045 VdmSwapContext(IN PKTRAP_FRAME TrapFrame,
00046                IN PCONTEXT OutContext,
00047                IN PCONTEXT InContext)
00048 {
00049     ULONG EFlags, OldEFlags;
00050 
00051     /* Make sure that we're at APC_LEVEL and that this is a valid frame */
00052     ASSERT(KeGetCurrentIrql() == APC_LEVEL);
00053     //ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
00054 
00055     /* Check if this is a V86 frame */
00056     if (TrapFrame->EFlags & EFLAGS_V86_MASK)
00057     {
00058         /* Copy segment registers */
00059         OutContext->SegGs = TrapFrame->V86Gs;
00060         OutContext->SegFs = TrapFrame->V86Fs;
00061         OutContext->SegEs = TrapFrame->V86Es;
00062         OutContext->SegDs = TrapFrame->V86Ds;
00063     }
00064     else if (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK))
00065     {
00066         /* This was kernel mode, copy segment registers */
00067         OutContext->SegGs = TrapFrame->SegGs;
00068         OutContext->SegFs = TrapFrame->SegFs;
00069         OutContext->SegEs = TrapFrame->SegEs;
00070         OutContext->SegDs = TrapFrame->SegDs;
00071     }
00072 
00073     /* Copy CS and SS */
00074     OutContext->SegCs = TrapFrame->SegCs;
00075     OutContext->SegSs = TrapFrame->HardwareSegSs;
00076 
00077     /* Copy general purpose registers */
00078     OutContext->Eax = TrapFrame->Eax;
00079     OutContext->Ebx = TrapFrame->Ebx;
00080     OutContext->Ecx = TrapFrame->Ecx;
00081     OutContext->Edx = TrapFrame->Edx;
00082     OutContext->Esi = TrapFrame->Esi;
00083     OutContext->Edi = TrapFrame->Edi;
00084 
00085     /* Copy stack and counter */
00086     OutContext->Ebp = TrapFrame->Ebp;
00087     OutContext->Esp = TrapFrame->HardwareEsp;
00088     OutContext->Eip = TrapFrame->Eip;
00089 
00090     /* Finally the flags */
00091     OutContext->EFlags = TrapFrame->EFlags;
00092 
00093     /* Now copy from the in frame to the trap frame */
00094     TrapFrame->SegCs = InContext->SegCs;
00095     TrapFrame->HardwareSegSs = InContext->SegSs;
00096 
00097     /* Copy the general purpose registers */
00098     TrapFrame->Eax = InContext->Eax;
00099     TrapFrame->Ebx = InContext->Ebx;
00100     TrapFrame->Ecx = InContext->Ecx;
00101     TrapFrame->Edx = InContext->Edx;
00102     TrapFrame->Esi = InContext->Esi;
00103     TrapFrame->Edi = InContext->Edi;
00104 
00105     /* Copy the stack and counter */
00106     TrapFrame->Ebp = InContext->Ebp;
00107     TrapFrame->HardwareEsp = InContext->Esp;
00108     TrapFrame->Eip = InContext->Eip;
00109 
00110     /* Check if the context is from V86 */
00111     EFlags = InContext->EFlags;
00112     if (EFlags & EFLAGS_V86_MASK)
00113     {
00114         /* Sanitize the flags for V86 */
00115         EFlags &= KeI386EFlagsAndMaskV86;
00116         EFlags |= KeI386EFlagsOrMaskV86;
00117     }
00118     else
00119     {
00120         /* Add RPL_MASK to segments */
00121         TrapFrame->SegCs |= RPL_MASK;
00122         TrapFrame->HardwareSegSs |= RPL_MASK;
00123 
00124         /* Check for bogus CS */
00125         if (TrapFrame->SegCs < KGDT_R0_CODE)
00126         {
00127             /* Set user-mode */
00128             TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
00129         }
00130 
00131         /* Sanitize flags and add interrupt mask */
00132         EFlags &= EFLAGS_USER_SANITIZE;
00133         EFlags |=EFLAGS_INTERRUPT_MASK;
00134     }
00135 
00136     /* Save the new eflags */
00137     OldEFlags = TrapFrame->EFlags;
00138     TrapFrame->EFlags = EFlags;
00139 
00140     /* Check if we need to fixup ESP0 */
00141     if ((OldEFlags ^ EFlags) & EFLAGS_V86_MASK)
00142     {
00143         /* Fix it up */
00144         Ki386AdjustEsp0(TrapFrame);
00145     }
00146 
00147     /* Check if this is a V86 context */
00148     if (InContext->EFlags & EFLAGS_V86_MASK)
00149     {
00150         /* Copy VDM segments */
00151         TrapFrame->V86Gs = InContext->SegGs;
00152         TrapFrame->V86Fs = InContext->SegFs;
00153         TrapFrame->V86Es = InContext->SegEs;
00154         TrapFrame->V86Ds = InContext->SegDs;
00155     }
00156     else
00157     {
00158         /* Copy monitor segments */
00159         TrapFrame->SegGs = InContext->SegGs;
00160         TrapFrame->SegFs = InContext->SegFs;
00161         TrapFrame->SegEs = InContext->SegEs;
00162         TrapFrame->SegDs = InContext->SegDs;
00163     }
00164 
00165     /* Clear the exception list and return */
00166     TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
00167 }
00168 
00169 NTSTATUS
00170 NTAPI
00171 VdmpStartExecution(VOID)
00172 {
00173     PETHREAD Thread = PsGetCurrentThread();
00174     PKTRAP_FRAME VdmFrame;
00175     NTSTATUS Status;
00176     PVDM_TIB VdmTib;
00177     BOOLEAN Interrupts;
00178     KIRQL OldIrql;
00179     CONTEXT VdmContext;
00180     PAGED_CODE();
00181 
00182     /* Get the thread's VDM frame and TIB */
00183     VdmFrame = (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -
00184                                   sizeof(FX_SAVE_AREA) -
00185                                   sizeof(KTRAP_FRAME));
00186     Status = VdmpGetVdmTib(&VdmTib);
00187     if (!NT_SUCCESS(Status)) return STATUS_INVALID_SYSTEM_SERVICE;
00188 
00189     /* Go to APC level */
00190     KeRaiseIrql(APC_LEVEL, &OldIrql);
00191 
00192     /* Check if interrupts are enabled */
00193     Interrupts = (BOOLEAN)(VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK);
00194 
00195     /* We don't support full VDM yet, this shouldn't happen */
00196     ASSERT(*VdmState == 0);
00197     ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK);
00198 
00199     /* Check if VME is supported and V86 mode was enabled */
00200     if ((KeI386VirtualIntExtensions) &&
00201         (VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))
00202     {
00203         /* Check if interrupts are enabled */
00204         if (Interrupts)
00205         {
00206             /* Set fake IF flag */
00207             VdmTib->VdmContext.EFlags |= EFLAGS_VIF;
00208         }
00209         else
00210         {
00211             /* Remove fake IF flag, turn on real IF flag */
00212             VdmTib->VdmContext.EFlags &= ~EFLAGS_VIF;
00213             VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
00214         }
00215     }
00216     else
00217     {
00218         /* Set interrupt state in the VDM State */
00219         if (VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK)
00220         {
00221             /* Enable them as well */
00222             InterlockedOr((PLONG)VdmState, EFLAGS_INTERRUPT_MASK);
00223         }
00224         else
00225         {
00226             /* Disable them */
00227             InterlockedAnd((PLONG)VdmState, ~EFLAGS_INTERRUPT_MASK);
00228         }
00229 
00230         /* Enable the interrupt flag */
00231         VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
00232     }
00233 
00234     /*  Get the VDM context and make sure it's not an edited frame */
00235     VdmContext = VdmTib->VdmContext;
00236     if (!(VdmContext.SegCs & FRAME_EDITED))
00237     {
00238         /* Fail */
00239         KeLowerIrql(OldIrql);
00240         return STATUS_INVALID_SYSTEM_SERVICE;
00241     }
00242     
00243     /* Now do the VDM Swap */
00244     VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext);
00245 
00246     /* Lower the IRQL and return EAX */
00247     KeLowerIrql(OldIrql);
00248     return VdmFrame->Eax;
00249 }
00250 
00251 VOID
00252 NTAPI
00253 VdmEndExecution(IN PKTRAP_FRAME TrapFrame,
00254                 IN PVDM_TIB VdmTib)
00255 {
00256     KIRQL OldIrql;
00257     CONTEXT Context;
00258     PAGED_CODE();
00259 
00260     /* Sanity check */
00261     ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
00262            (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)));
00263 
00264     /* Raise to APC_LEVEL */
00265     KeRaiseIrql(APC_LEVEL, &OldIrql);
00266 
00267     /* Set success */
00268     VdmTib->MonitorContext.Eax = STATUS_SUCCESS;
00269 
00270     /* Make a copy of the monitor context */
00271     Context = VdmTib->MonitorContext;
00272     
00273     /* Check if V86 mode was enabled or the trap was edited */
00274     if ((Context.EFlags & EFLAGS_V86_MASK) || (Context.SegCs & FRAME_EDITED))
00275     {
00276         /* Switch contexts */
00277         VdmSwapContext(TrapFrame, &VdmTib->VdmContext, &Context);
00278 
00279         /* Check if VME is supported and V86 mode was enabled */
00280         if ((KeI386VirtualIntExtensions) &&
00281             (VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))
00282         {
00283             /* Check for VIF (virtual interrupt) flag state */
00284             if (VdmTib->VdmContext.EFlags & EFLAGS_VIF)
00285             {
00286                 /* Set real IF flag */
00287                 VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
00288             }
00289             else
00290             {
00291                 /* Remove real IF flag */
00292                 VdmTib->VdmContext.EFlags &= ~EFLAGS_INTERRUPT_MASK;
00293             }
00294             
00295             /* Turn off VIP and VIF */
00296             TrapFrame->EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
00297             VdmTib->VdmContext.EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
00298         }
00299         else
00300         {
00301             /* Set the EFLAGS based on our software copy of EFLAGS */
00302             VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~EFLAGS_INTERRUPT_MASK) |
00303                                         (*VdmState & EFLAGS_INTERRUPT_MASK);
00304         }
00305     }
00306 
00307     /* Lower IRQL and reutrn */
00308     KeLowerIrql(OldIrql);
00309 }
00310 
00311 BOOLEAN
00312 NTAPI
00313 VdmDispatchBop(IN PKTRAP_FRAME TrapFrame)
00314 {
00315     PUCHAR Eip;
00316     PVDM_TIB VdmTib;
00317 
00318     /* Check if this is from V86 mode */
00319     if (TrapFrame->EFlags & EFLAGS_V86_MASK)
00320     {
00321         /* Calculate flat EIP */
00322         Eip = (PUCHAR)((TrapFrame->Eip & 0xFFFF) +
00323                       ((TrapFrame->SegCs & 0xFFFF) << 4));
00324 
00325         /* Check if this is a BOP */
00326         if (*(PUSHORT)Eip == 0xC4C4)
00327         {
00328             /* Check sure its the DOS Bop */
00329             if (Eip[2] == 0x50)
00330             {
00331                 /* FIXME: No VDM Support */
00332                 ASSERT(FALSE);
00333             }
00334 
00335             /* Increase the number of BOP operations */
00336             VdmBopCount++;
00337 
00338             /* Get the TIB */
00339             VdmTib = NtCurrentTeb()->Vdm;
00340 
00341             /* Fill out a VDM Event */
00342             VdmTib->EventInfo.InstructionSize = 3;
00343             VdmTib->EventInfo.BopNumber = Eip[2];
00344             VdmTib->EventInfo.Event = VdmBop;
00345 
00346             /* End VDM Execution */
00347             VdmEndExecution(TrapFrame, VdmTib);
00348         }
00349         else
00350         {
00351             /* Not a BOP */
00352             return FALSE;
00353         }
00354     }
00355     else
00356     {
00357         /* FIXME: Shouldn't happen on ROS */
00358         ASSERT(FALSE);
00359     }
00360 
00361     /* Return success */
00362     return TRUE;
00363 }
00364 
00365 

Generated on Sat May 26 2012 04:36:33 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.