Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

507 lines
13 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. strtexec.c
  5. Abstract:
  6. This module contains routines for switching to and from application
  7. mode in a VDM.
  8. Author:
  9. Dave Hastings (daveh) 24-Apr-1992
  10. Revision History:
  11. --*/
  12. #include "vdmp.h"
  13. VOID
  14. Ki386AdjustEsp0 (
  15. PKTRAP_FRAME TrapFrame
  16. );
  17. VOID
  18. VdmSwapContexts (
  19. PKTRAP_FRAME TrapFrame,
  20. IN PCONTEXT OutContextUserSpace,
  21. IN PCONTEXT InContext
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, VdmpStartExecution)
  25. #pragma alloc_text(PAGE, VdmEndExecution)
  26. #pragma alloc_text(PAGE, VdmSwapContexts)
  27. #endif
  28. NTSTATUS
  29. VdmpStartExecution (
  30. VOID
  31. )
  32. /*++
  33. Routine Description:
  34. This routine causes execution of dos application code to begin. The
  35. Dos application executes on the thread. The Vdms context is loaded
  36. from the VDM_TIB for the thread. The 32 bit context is stored into
  37. the MonitorContext. Execution in the VDM context will continue until
  38. an event occurs that the monitor needs to service. At that point,
  39. the information will be put into the VDM_TIB, and the call will
  40. return.
  41. Arguments:
  42. None.
  43. Return Value:
  44. TrapFrame->Eax for application mode, required for system sevices exit.
  45. --*/
  46. {
  47. PVDM_TIB VdmTib;
  48. PKTRAP_FRAME TrapFrame;
  49. PETHREAD Thread;
  50. KIRQL OldIrql;
  51. BOOLEAN IntsEnabled;
  52. NTSTATUS Status;
  53. CONTEXT VdmContext;
  54. PAGED_CODE();
  55. //
  56. // Form a pointer to the trap frame for the current thread
  57. //
  58. Thread = PsGetCurrentThread ();
  59. TrapFrame = VdmGetTrapFrame (&Thread->Tcb);
  60. //
  61. // Get the VdmTib
  62. //
  63. Status = VdmpGetVdmTib (&VdmTib);
  64. if (!NT_SUCCESS(Status)) {
  65. return STATUS_INVALID_SYSTEM_SERVICE;
  66. }
  67. KeRaiseIrql (APC_LEVEL, &OldIrql);
  68. try {
  69. //
  70. // Determine if interrupts are on or off
  71. //
  72. IntsEnabled = VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK
  73. ? TRUE : FALSE;
  74. //
  75. // Check for timer ints to dispatch, However if interrupts are disabled
  76. // or there are hardware ints pending we postpone dispatching the timer
  77. // interrupt until interrupts are enabled.
  78. //
  79. if ((*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_INT_TIMER) &&
  80. IntsEnabled &&
  81. !(*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_INT_HARDWARE)) {
  82. VdmTib->EventInfo.Event = VdmIntAck;
  83. VdmTib->EventInfo.InstructionSize = 0;
  84. VdmTib->EventInfo.IntAckInfo = 0;
  85. KeLowerIrql(OldIrql);
  86. return STATUS_SUCCESS;
  87. }
  88. //
  89. // Perform IF to VIF translation if the processor
  90. // supports IF virtualization
  91. //
  92. if ((VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK) &&
  93. (KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS)) {
  94. //
  95. // Translate IF to VIF
  96. //
  97. if (IntsEnabled) {
  98. VdmTib->VdmContext.EFlags |= EFLAGS_VIF;
  99. } else {
  100. VdmTib->VdmContext.EFlags &= ~EFLAGS_VIF;
  101. VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
  102. }
  103. if (*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_INT_HARDWARE)
  104. VdmTib->VdmContext.EFlags |= EFLAGS_VIP;
  105. else
  106. VdmTib->VdmContext.EFlags &= ~EFLAGS_VIP;
  107. } else {
  108. //
  109. // Translate the real interrupt flag in the VdmContext to the
  110. // virtual interrupt flag in the VdmTib, and force real
  111. // interrupts enabled.
  112. //
  113. ASSERT(VDM_VIRTUAL_INTERRUPTS == EFLAGS_INTERRUPT_MASK);
  114. if (VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK) {
  115. InterlockedOr (FIXED_NTVDMSTATE_LINEAR_PC_AT, VDM_VIRTUAL_INTERRUPTS);
  116. } else {
  117. InterlockedAnd (FIXED_NTVDMSTATE_LINEAR_PC_AT, ~VDM_VIRTUAL_INTERRUPTS);
  118. }
  119. //
  120. // Insure that real interrupts are always enabled.
  121. //
  122. VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
  123. }
  124. //
  125. // Before working on a trap frame, make sure that it's our own structure
  126. //
  127. VdmContext = VdmTib->VdmContext;
  128. if (!(VdmContext.EFlags & EFLAGS_V86_MASK) && !(VdmContext.SegCs & FRAME_EDITED)) {
  129. //
  130. // We will crash in KiServiceExit
  131. //
  132. KeLowerIrql(OldIrql);
  133. return(STATUS_INVALID_SYSTEM_SERVICE);
  134. }
  135. //
  136. // Switch from MonitorContext to VdmContext
  137. //
  138. VdmSwapContexts (TrapFrame,
  139. &VdmTib->MonitorContext,
  140. &VdmContext);
  141. //
  142. // Check for pending interrupts
  143. //
  144. if (IntsEnabled && (*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_INT_HARDWARE)) {
  145. VdmDispatchInterrupts(TrapFrame, VdmTib);
  146. }
  147. }
  148. except(EXCEPTION_EXECUTE_HANDLER) {
  149. KeLowerIrql (OldIrql);
  150. Status = GetExceptionCode();
  151. return Status;
  152. }
  153. KeLowerIrql(OldIrql);
  154. return (NTSTATUS) TrapFrame->Eax;
  155. }
  156. VOID
  157. VdmEndExecution (
  158. PKTRAP_FRAME TrapFrame,
  159. PVDM_TIB VdmTib
  160. )
  161. /*++
  162. Routine Description:
  163. This routine does the core work to end the execution
  164. Arguments:
  165. None
  166. Return Value:
  167. VOID, but exceptions can be thrown due to the user space accesses.
  168. --*/
  169. {
  170. CONTEXT VdmContext;
  171. KIRQL OldIrql;
  172. PAGED_CODE();
  173. ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
  174. (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)) );
  175. //
  176. // Raise to APC_LEVEL to synchronize modification to the trap frame.
  177. //
  178. KeRaiseIrql (APC_LEVEL, &OldIrql);
  179. try {
  180. //
  181. // The return value must be put into the Monitorcontext, and set,
  182. // since we are probably returning to user mode via EXIT_ALL, and
  183. // the volatile registers will be restored.
  184. //
  185. VdmTib->MonitorContext.Eax = STATUS_SUCCESS;
  186. VdmContext = VdmTib->MonitorContext;
  187. if (!(VdmContext.EFlags & EFLAGS_V86_MASK) && !(VdmContext.SegCs & FRAME_EDITED)) {
  188. //
  189. // We will crash in KiServiceExit
  190. //
  191. leave;
  192. }
  193. //
  194. // Switch from MonitorContext to VdmContext
  195. //
  196. VdmSwapContexts (TrapFrame,
  197. &VdmTib->VdmContext,
  198. &VdmContext);
  199. //
  200. // Perform IF to VIF translation
  201. //
  202. //
  203. // If the processor supports IF virtualization
  204. //
  205. if ((VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK) &&
  206. (KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS)) {
  207. //
  208. // Translate VIF to IF
  209. //
  210. if (VdmTib->VdmContext.EFlags & EFLAGS_VIF) {
  211. VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
  212. } else {
  213. VdmTib->VdmContext.EFlags &= ~EFLAGS_INTERRUPT_MASK;
  214. }
  215. //
  216. // Turn off VIP and VIF to insure that nothing strange happens
  217. //
  218. TrapFrame->EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
  219. VdmTib->VdmContext.EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
  220. } else {
  221. //
  222. // Translate the virtual interrupt flag from the VdmTib back to the
  223. // real interrupt flag in the VdmContext
  224. //
  225. VdmTib->VdmContext.EFlags =
  226. (VdmTib->VdmContext.EFlags & ~EFLAGS_INTERRUPT_MASK)
  227. | (*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_VIRTUAL_INTERRUPTS);
  228. }
  229. } except (EXCEPTION_EXECUTE_HANDLER) {
  230. }
  231. KeLowerIrql (OldIrql);
  232. return;
  233. }
  234. VOID
  235. VdmSwapContexts (
  236. PKTRAP_FRAME TrapFrame,
  237. IN PCONTEXT OutContextUserSpace,
  238. IN PCONTEXT InContext
  239. )
  240. /*++
  241. Routine Description:
  242. This routine unloads a CONTEXT from a KFRAME, and loads a different
  243. context in its place.
  244. ASSUMES that entry irql is APC_LEVEL, if it is not this routine
  245. may produce incorrect trapframes.
  246. BUGBUG: Could this routine be folded into KeContextToKframes ?
  247. Arguments:
  248. TrapFrame - Supplies the trapframe to copy registers from.
  249. OutContextUserSpace - Supplies the context record to fill - this is a user
  250. space argument that has been probed. Our caller MUST
  251. use an exception handler when calling us.
  252. InContext - Supplies the captured context record to copy from.
  253. Return Value:
  254. VOID. Exceptions may be thrown due to user space accesses.
  255. --*/
  256. {
  257. ULONG Eflags;
  258. ULONG V86Change;
  259. ASSERT (KeGetCurrentIrql () == APC_LEVEL);
  260. //
  261. // Move context from trap frame to outgoing context.
  262. //
  263. ASSERT (TrapFrame->DbgArgMark == 0xBADB0D00);
  264. if (TrapFrame->EFlags & EFLAGS_V86_MASK) {
  265. //
  266. // Move segment registers.
  267. //
  268. OutContextUserSpace->SegGs = TrapFrame->V86Gs;
  269. OutContextUserSpace->SegFs = TrapFrame->V86Fs;
  270. OutContextUserSpace->SegEs = TrapFrame->V86Es;
  271. OutContextUserSpace->SegDs = TrapFrame->V86Ds;
  272. }
  273. else if ((USHORT)TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)) {
  274. OutContextUserSpace->SegGs = TrapFrame->SegGs;
  275. OutContextUserSpace->SegFs = TrapFrame->SegFs;
  276. OutContextUserSpace->SegEs = TrapFrame->SegEs;
  277. OutContextUserSpace->SegDs = TrapFrame->SegDs;
  278. }
  279. OutContextUserSpace->SegCs = TrapFrame->SegCs;
  280. OutContextUserSpace->SegSs = TrapFrame->HardwareSegSs;
  281. //
  282. // Move General Registers.
  283. //
  284. OutContextUserSpace->Eax = TrapFrame->Eax;
  285. OutContextUserSpace->Ebx = TrapFrame->Ebx;
  286. OutContextUserSpace->Ecx = TrapFrame->Ecx;
  287. OutContextUserSpace->Edx = TrapFrame->Edx;
  288. OutContextUserSpace->Esi = TrapFrame->Esi;
  289. OutContextUserSpace->Edi = TrapFrame->Edi;
  290. //
  291. // Move Pointer registers.
  292. //
  293. OutContextUserSpace->Ebp = TrapFrame->Ebp;
  294. OutContextUserSpace->Esp = TrapFrame->HardwareEsp;
  295. OutContextUserSpace->Eip = TrapFrame->Eip;
  296. //
  297. // Move Flags.
  298. //
  299. OutContextUserSpace->EFlags = TrapFrame->EFlags;
  300. //
  301. // Move incoming context to trap frame.
  302. //
  303. TrapFrame->SegCs = InContext->SegCs;
  304. TrapFrame->HardwareSegSs = InContext->SegSs;
  305. //
  306. // Move General Registers.
  307. //
  308. TrapFrame->Eax = InContext->Eax;
  309. TrapFrame->Ebx = InContext->Ebx;
  310. TrapFrame->Ecx = InContext->Ecx;
  311. TrapFrame->Edx = InContext->Edx;
  312. TrapFrame->Esi = InContext->Esi;
  313. TrapFrame->Edi = InContext->Edi;
  314. //
  315. // Move Pointer registers.
  316. //
  317. TrapFrame->Ebp = InContext->Ebp;
  318. TrapFrame->HardwareEsp = InContext->Esp;
  319. TrapFrame->Eip = InContext->Eip;
  320. //
  321. // Move Flags.
  322. //
  323. Eflags = InContext->EFlags;
  324. if (Eflags & EFLAGS_V86_MASK) {
  325. Eflags &= KeI386EFlagsAndMaskV86;
  326. Eflags |= KeI386EFlagsOrMaskV86;
  327. }
  328. else {
  329. TrapFrame->SegCs |= 3; // RPL 3 only
  330. TrapFrame->HardwareSegSs |= 3; // RPL 3 only
  331. if (TrapFrame->SegCs < 8) {
  332. //
  333. // Create edited trap frame.
  334. //
  335. TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
  336. }
  337. Eflags &= EFLAGS_USER_SANITIZE;
  338. Eflags |= EFLAGS_INTERRUPT_MASK;
  339. }
  340. //
  341. // See if we are changing the EFLAGS_V86_MASK.
  342. //
  343. V86Change = Eflags ^ TrapFrame->EFlags;
  344. TrapFrame->EFlags = Eflags;
  345. if (V86Change & EFLAGS_V86_MASK) {
  346. //
  347. // Fix Esp 0 as necessary.
  348. //
  349. Ki386AdjustEsp0 (TrapFrame);
  350. if (TrapFrame->EFlags & EFLAGS_V86_MASK) {
  351. //
  352. // Move segment registers for the VDM.
  353. //
  354. TrapFrame->V86Gs = InContext->SegGs;
  355. TrapFrame->V86Fs = InContext->SegFs;
  356. TrapFrame->V86Es = InContext->SegEs;
  357. TrapFrame->V86Ds = InContext->SegDs;
  358. return;
  359. }
  360. }
  361. //
  362. // Move segment registers for the monitor.
  363. //
  364. TrapFrame->SegGs = InContext->SegGs;
  365. TrapFrame->SegFs = InContext->SegFs;
  366. TrapFrame->SegEs = InContext->SegEs;
  367. TrapFrame->SegDs = InContext->SegDs;
  368. //
  369. // We are going back to 32 bit monitor code. Set Trapframe
  370. // exception list to END_OF_CHAIN such that we won't bugcheck
  371. // in KiExceptionExit.
  372. //
  373. TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
  374. }