Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenvdmexec.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
1.7.6.1
|