Source code of Windows XP (NT5)
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.

1448 lines
45 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. exceptn.c
  5. Abstract:
  6. This module implement the code necessary to dispatch expections to the
  7. proper mode and invoke the exception dispatcher.
  8. Author:
  9. David N. Cutler (davec) 30-Apr-1989
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. 14-Feb-1990 shielint
  14. Modified for NT386 interrupt manager
  15. 6-April-1990 bryanwi
  16. Fix non-canonical stack case for 386.
  17. --*/
  18. #include "ki.h"
  19. #define FN_BITS_PER_TAGWORD 16
  20. #define FN_TAG_EMPTY 0x3
  21. #define FN_TAG_MASK 0x3
  22. #define FX_TAG_VALID 0x1
  23. #define NUMBER_OF_FP_REGISTERS 8
  24. #define BYTES_PER_FP_REGISTER 10
  25. #define BYTES_PER_FX_REGISTER 16
  26. extern UCHAR VdmUserCr0MapIn[];
  27. extern BOOLEAN KeI386FxsrPresent;
  28. extern BOOLEAN KeI386XMMIPresent;
  29. VOID
  30. Ki386AdjustEsp0(
  31. IN PKTRAP_FRAME TrapFrame
  32. );
  33. BOOLEAN
  34. KiEm87StateToNpxFrame(
  35. OUT PFLOATING_SAVE_AREA NpxFrmae
  36. );
  37. BOOLEAN
  38. KiNpxFrameToEm87State(
  39. IN PFLOATING_SAVE_AREA NpxFrmae
  40. );
  41. ULONG
  42. KiEspFromTrapFrame(
  43. IN PKTRAP_FRAME TrapFrame
  44. )
  45. /*++
  46. Routine Description:
  47. This routine fetches the correct esp from a trapframe, accounting
  48. for whether the frame is a user or kernel mode frame, and whether
  49. it has been edited.
  50. Arguments:
  51. TrapFrame - Supplies a pointer to a trap frame from which volatile context
  52. should be copied into the context record.
  53. Return Value:
  54. Value of Esp.
  55. --*/
  56. {
  57. if (((TrapFrame->SegCs & MODE_MASK) != KernelMode) ||
  58. (TrapFrame->EFlags & EFLAGS_V86_MASK)) {
  59. // User mode frame, real value of Esp is always in HardwareEsp.
  60. return TrapFrame->HardwareEsp;
  61. } else {
  62. if ((TrapFrame->SegCs & FRAME_EDITED) == 0) {
  63. // Kernel mode frame which has had esp edited,
  64. // value of Esp is in TempEsp.
  65. return TrapFrame->TempEsp;
  66. } else {
  67. // Kernel mode frame has has not had esp edited, compute esp.
  68. return (ULONG)&TrapFrame->HardwareEsp;
  69. }
  70. }
  71. }
  72. VOID
  73. KiEspToTrapFrame(
  74. IN PKTRAP_FRAME TrapFrame,
  75. IN ULONG Esp
  76. )
  77. /*++
  78. Routine Description:
  79. This routine sets the specified value Esp into the trap frame,
  80. accounting for whether the frame is a user or kernel mode frame,
  81. and whether it has been edited before.
  82. Arguments:
  83. TrapFrame - Supplies a pointer to a trap frame from which volatile context
  84. should be copied into the context record.
  85. Esp - New value for Esp.
  86. Return Value:
  87. None.
  88. --*/
  89. {
  90. ULONG OldEsp;
  91. OldEsp = KiEspFromTrapFrame(TrapFrame);
  92. if (((TrapFrame->SegCs & MODE_MASK) != KernelMode) ||
  93. (TrapFrame->EFlags & EFLAGS_V86_MASK)) {
  94. //
  95. // User mode trap frame
  96. //
  97. TrapFrame->HardwareEsp = Esp;
  98. } else {
  99. //
  100. // Kernel mode esp can't be lowered or iret emulation will fail
  101. //
  102. if (Esp < OldEsp)
  103. KeBugCheckEx(SET_OF_INVALID_CONTEXT,
  104. Esp, OldEsp, (ULONG_PTR)TrapFrame, 0);
  105. //
  106. // Edit frame, setting edit marker as needed.
  107. //
  108. if ((TrapFrame->SegCs & FRAME_EDITED) == 0) {
  109. // Kernel frame that has already been edited,
  110. // store value in TempEsp.
  111. TrapFrame->TempEsp = Esp;
  112. } else {
  113. // Kernel frame for which Esp is being edited first time.
  114. // Save real SegCs, set marked in SegCs, save Esp value.
  115. if (OldEsp != Esp) {
  116. TrapFrame->TempSegCs = TrapFrame->SegCs;
  117. TrapFrame->SegCs = TrapFrame->SegCs & ~FRAME_EDITED;
  118. TrapFrame->TempEsp = Esp;
  119. }
  120. }
  121. }
  122. }
  123. ULONG
  124. KiSegSsFromTrapFrame(
  125. IN PKTRAP_FRAME TrapFrame
  126. )
  127. /*++
  128. Routine Description:
  129. This routine fetches the correct ss from a trapframe, accounting
  130. for whether the frame is a user or kernel mode frame.
  131. Arguments:
  132. TrapFrame - Supplies a pointer to a trap frame from which volatile context
  133. should be copied into the context record.
  134. Return Value:
  135. Value of SegSs.
  136. --*/
  137. {
  138. if (TrapFrame->EFlags & EFLAGS_V86_MASK){
  139. return TrapFrame->HardwareSegSs;
  140. } else if ((TrapFrame->SegCs & MODE_MASK) != KernelMode) {
  141. //
  142. // It's user mode. The HardwareSegSs contains R3 data selector.
  143. //
  144. return TrapFrame->HardwareSegSs | RPL_MASK;
  145. } else {
  146. return KGDT_R0_DATA;
  147. }
  148. }
  149. VOID
  150. KiSegSsToTrapFrame(
  151. IN PKTRAP_FRAME TrapFrame,
  152. IN ULONG SegSs
  153. )
  154. /*++
  155. Routine Description:
  156. It turns out that in a flat system there are only two legal values
  157. for SS. Therefore, this procedure forces the appropriate one
  158. of those values to be used. The legal SS value is a function of
  159. which CS value is already set.
  160. Arguments:
  161. TrapFrame - Supplies a pointer to a trap frame from which volatile context
  162. should be copied into the context record.
  163. SegSs - value of SS caller would like to set.
  164. Return Value:
  165. Nothing.
  166. --*/
  167. {
  168. SegSs &= SEGMENT_MASK; // Throw away the high order trash bits
  169. if (TrapFrame->EFlags & EFLAGS_V86_MASK) {
  170. TrapFrame->HardwareSegSs = SegSs;
  171. } else if ((TrapFrame->SegCs & MODE_MASK) == UserMode) {
  172. //
  173. // If user mode, we simply put SegSs to trapfram. If the SegSs
  174. // is a bogus value. The trap0d handler will be able to detect
  175. // this and handle it appropriately.
  176. //
  177. TrapFrame->HardwareSegSs = SegSs | RPL_MASK;
  178. }
  179. //
  180. // else {
  181. // The frame is a kernel mode frame, which does not have
  182. // a place to store SS. Therefore, do nothing.
  183. //
  184. }
  185. VOID
  186. KeContextFromKframes (
  187. IN PKTRAP_FRAME TrapFrame,
  188. IN PKEXCEPTION_FRAME ExceptionFrame,
  189. IN OUT PCONTEXT ContextFrame
  190. )
  191. /*++
  192. Routine Description:
  193. This routine moves the selected contents of the specified trap and exception frames
  194. frames into the specified context frame according to the specified context
  195. flags.
  196. Arguments:
  197. TrapFrame - Supplies a pointer to a trap frame from which volatile context
  198. should be copied into the context record.
  199. ExceptionFrame - Supplies a pointer to an exception frame from which context
  200. should be copied into the context record. This argument is ignored since
  201. there is no exception frame on NT386.
  202. ContextFrame - Supplies a pointer to the context frame that receives the
  203. context copied from the trap and exception frames.
  204. Return Value:
  205. None.
  206. --*/
  207. {
  208. PFX_SAVE_AREA NpxFrame;
  209. BOOLEAN StateSaved;
  210. ULONG i;
  211. struct _FPSaveBuffer {
  212. UCHAR Buffer[15];
  213. FLOATING_SAVE_AREA SaveArea;
  214. } FloatSaveBuffer;
  215. PFLOATING_SAVE_AREA PSaveArea;
  216. UNREFERENCED_PARAMETER( ExceptionFrame );
  217. //
  218. // Set control information if specified.
  219. //
  220. if ((ContextFrame->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) {
  221. //
  222. // Set registers ebp, eip, cs, eflag, esp and ss.
  223. //
  224. ContextFrame->Ebp = TrapFrame->Ebp;
  225. ContextFrame->Eip = TrapFrame->Eip;
  226. if (((TrapFrame->SegCs & FRAME_EDITED) == 0) &&
  227. ((TrapFrame->EFlags & EFLAGS_V86_MASK) == 0)) {
  228. ContextFrame->SegCs = TrapFrame->TempSegCs & SEGMENT_MASK;
  229. } else {
  230. ContextFrame->SegCs = TrapFrame->SegCs & SEGMENT_MASK;
  231. }
  232. ContextFrame->EFlags = TrapFrame->EFlags;
  233. ContextFrame->SegSs = KiSegSsFromTrapFrame(TrapFrame);
  234. ContextFrame->Esp = KiEspFromTrapFrame(TrapFrame);
  235. }
  236. //
  237. // Set segment register contents if specified.
  238. //
  239. if ((ContextFrame->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) {
  240. //
  241. // Set segment registers gs, fs, es, ds.
  242. //
  243. // These values are junk most of the time, but useful
  244. // for debugging under certain conditions. Therefore,
  245. // we report whatever was in the frame.
  246. //
  247. if (TrapFrame->EFlags & EFLAGS_V86_MASK) {
  248. ContextFrame->SegGs = TrapFrame->V86Gs & SEGMENT_MASK;
  249. ContextFrame->SegFs = TrapFrame->V86Fs & SEGMENT_MASK;
  250. ContextFrame->SegEs = TrapFrame->V86Es & SEGMENT_MASK;
  251. ContextFrame->SegDs = TrapFrame->V86Ds & SEGMENT_MASK;
  252. }
  253. else {
  254. if (TrapFrame->SegCs == KGDT_R0_CODE) {
  255. //
  256. // Trap frames created from R0_CODE traps do not save
  257. // the following selectors. Set them in the frame now.
  258. //
  259. TrapFrame->SegGs = 0;
  260. TrapFrame->SegFs = KGDT_R0_PCR;
  261. TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
  262. TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
  263. }
  264. ContextFrame->SegGs = TrapFrame->SegGs & SEGMENT_MASK;
  265. ContextFrame->SegFs = TrapFrame->SegFs & SEGMENT_MASK;
  266. ContextFrame->SegEs = TrapFrame->SegEs & SEGMENT_MASK;
  267. ContextFrame->SegDs = TrapFrame->SegDs & SEGMENT_MASK;
  268. }
  269. }
  270. //
  271. // Set integer register contents if specified.
  272. //
  273. if ((ContextFrame->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
  274. //
  275. // Set integer registers edi, esi, ebx, edx, ecx, eax
  276. //
  277. ContextFrame->Edi = TrapFrame->Edi;
  278. ContextFrame->Esi = TrapFrame->Esi;
  279. ContextFrame->Ebx = TrapFrame->Ebx;
  280. ContextFrame->Ecx = TrapFrame->Ecx;
  281. ContextFrame->Edx = TrapFrame->Edx;
  282. ContextFrame->Eax = TrapFrame->Eax;
  283. }
  284. if (((ContextFrame->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
  285. CONTEXT_EXTENDED_REGISTERS) &&
  286. ((TrapFrame->SegCs & MODE_MASK) == UserMode)) {
  287. //
  288. // This is the base TrapFrame, and the NpxFrame is on the base
  289. // of the kernel stack, just above it in memory.
  290. //
  291. NpxFrame = (PFX_SAVE_AREA)(TrapFrame + 1);
  292. if (KeI386NpxPresent) {
  293. KiFlushNPXState (NULL);
  294. RtlCopyMemory( (PVOID)&(ContextFrame->ExtendedRegisters[0]),
  295. (PVOID)&(NpxFrame->U.FxArea),
  296. MAXIMUM_SUPPORTED_EXTENSION
  297. );
  298. }
  299. }
  300. //
  301. // Fetch floating register contents if requested, and type of target
  302. // is user. (system frames have no fp state, so ignore request)
  303. //
  304. if ( ((ContextFrame->ContextFlags & CONTEXT_FLOATING_POINT) ==
  305. CONTEXT_FLOATING_POINT) &&
  306. ((TrapFrame->SegCs & MODE_MASK) == UserMode)) {
  307. //
  308. // This is the base TrapFrame, and the NpxFrame is on the base
  309. // of the kernel stack, just above it in memory.
  310. //
  311. NpxFrame = (PFX_SAVE_AREA)(TrapFrame + 1);
  312. if (KeI386NpxPresent) {
  313. //
  314. // Force the coprocessors state to the save area and copy it
  315. // to the context frame.
  316. //
  317. if (KeI386FxsrPresent == TRUE) {
  318. //
  319. // FP state save was done using fxsave. Get the save
  320. // area in fnsave format
  321. //
  322. // Save area must be 16 byte aligned so we cushion it with
  323. // 15 bytes (in the locals declaration above) and round
  324. // down to align.
  325. //
  326. ULONG_PTR Temp;
  327. Temp = (ULONG_PTR)&FloatSaveBuffer.SaveArea;
  328. Temp &= ~0xf;
  329. PSaveArea = (PFLOATING_SAVE_AREA)Temp;
  330. KiFlushNPXState (PSaveArea);
  331. } else {
  332. PSaveArea = (PFLOATING_SAVE_AREA)&(NpxFrame->U.FnArea);
  333. KiFlushNPXState (NULL);
  334. }
  335. ContextFrame->FloatSave.ControlWord = PSaveArea->ControlWord;
  336. ContextFrame->FloatSave.StatusWord = PSaveArea->StatusWord;
  337. ContextFrame->FloatSave.TagWord = PSaveArea->TagWord;
  338. ContextFrame->FloatSave.ErrorOffset = PSaveArea->ErrorOffset;
  339. ContextFrame->FloatSave.ErrorSelector = PSaveArea->ErrorSelector;
  340. ContextFrame->FloatSave.DataOffset = PSaveArea->DataOffset;
  341. ContextFrame->FloatSave.DataSelector = PSaveArea->DataSelector;
  342. ContextFrame->FloatSave.Cr0NpxState = NpxFrame->Cr0NpxState;
  343. for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) {
  344. ContextFrame->FloatSave.RegisterArea[i] = PSaveArea->RegisterArea[i];
  345. }
  346. } else {
  347. //
  348. // The 80387 is being emulated by the R3 emulator.
  349. // ** The only time the Npx state is ever obtained or set is
  350. // ** for userlevel handling. Current Irql must be 0 or 1.
  351. // Go slurp the emulator's R3 data and generate the
  352. // floating point context
  353. //
  354. StateSaved = KiEm87StateToNpxFrame(&ContextFrame->FloatSave);
  355. if (StateSaved) {
  356. ContextFrame->FloatSave.Cr0NpxState = NpxFrame->Cr0NpxState;
  357. } else {
  358. //
  359. // The floatingpoint state can not be determined.
  360. // Remove the floatingpoint flag from the context frame flags.
  361. //
  362. ContextFrame->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
  363. }
  364. }
  365. }
  366. //
  367. // Fetch Dr register contents if requested. Values may be trash.
  368. //
  369. if ((ContextFrame->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
  370. CONTEXT_DEBUG_REGISTERS) {
  371. ContextFrame->Dr0 = TrapFrame->Dr0;
  372. ContextFrame->Dr1 = TrapFrame->Dr1;
  373. ContextFrame->Dr2 = TrapFrame->Dr2;
  374. ContextFrame->Dr3 = TrapFrame->Dr3;
  375. ContextFrame->Dr6 = TrapFrame->Dr6;
  376. //
  377. // If it's a user mode frame, and the thread doesn't have DRs set,
  378. // and we just return the trash in the frame, we risk accidentally
  379. // making the thread active with trash values on a set. Therefore,
  380. // Dr7 must be set to 0 if we get a non-active user mode frame.
  381. //
  382. if ((((TrapFrame->SegCs & MODE_MASK) != KernelMode) ||
  383. ((TrapFrame->EFlags & EFLAGS_V86_MASK) != 0)) &&
  384. (KeGetCurrentThread()->DebugActive == TRUE)) {
  385. ContextFrame->Dr7 = TrapFrame->Dr7;
  386. } else {
  387. ContextFrame->Dr7 = 0L;
  388. }
  389. }
  390. }
  391. VOID
  392. KeContextToKframes (
  393. IN OUT PKTRAP_FRAME TrapFrame,
  394. IN OUT PKEXCEPTION_FRAME ExceptionFrame,
  395. IN PCONTEXT ContextFrame,
  396. IN ULONG ContextFlags,
  397. IN KPROCESSOR_MODE PreviousMode
  398. )
  399. /*++
  400. Routine Description:
  401. This routine moves the selected contents of the specified context frame into
  402. the specified trap and exception frames according to the specified context
  403. flags.
  404. Arguments:
  405. TrapFrame - Supplies a pointer to a trap frame that receives the volatile
  406. context from the context record.
  407. ExceptionFrame - Supplies a pointer to an exception frame that receives
  408. the nonvolatile context from the context record. This argument is
  409. ignored since there is no exception frame on NT386.
  410. ContextFrame - Supplies a pointer to a context frame that contains the
  411. context that is to be copied into the trap and exception frames.
  412. ContextFlags - Supplies the set of flags that specify which parts of the
  413. context frame are to be copied into the trap and exception frames.
  414. PreviousMode - Supplies the processor mode for which the trap and exception
  415. frames are being built.
  416. Return Value:
  417. None.
  418. --*/
  419. {
  420. PFX_SAVE_AREA NpxFrame;
  421. ULONG i;
  422. ULONG j;
  423. ULONG TagWord;
  424. BOOLEAN StateSaved;
  425. BOOLEAN ModeChanged;
  426. #if DBG
  427. PKPCR Pcr;
  428. KIRQL OldIrql;
  429. #endif
  430. UNREFERENCED_PARAMETER( ExceptionFrame );
  431. //
  432. // Set control information if specified.
  433. //
  434. if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) {
  435. if ((ContextFrame->EFlags & EFLAGS_V86_MASK) !=
  436. (TrapFrame->EFlags & EFLAGS_V86_MASK)) {
  437. ModeChanged = TRUE;
  438. } else {
  439. ModeChanged = FALSE;
  440. }
  441. //
  442. // Set registers eflag, ebp, eip, cs, esp and ss.
  443. // Eflags is set first, so that the auxilliary routines
  444. // can check the v86 bit to determine as well as cs, to
  445. // determine if the frame is kernel or user mode. (v86 mode cs
  446. // can have any value)
  447. //
  448. TrapFrame->EFlags = SANITIZE_FLAGS(ContextFrame->EFlags, PreviousMode);
  449. TrapFrame->Ebp = ContextFrame->Ebp;
  450. TrapFrame->Eip = ContextFrame->Eip;
  451. if (TrapFrame->EFlags & EFLAGS_V86_MASK) {
  452. TrapFrame->SegCs = ContextFrame->SegCs;
  453. } else {
  454. TrapFrame->SegCs = SANITIZE_SEG(ContextFrame->SegCs, PreviousMode);
  455. if (PreviousMode != KernelMode && TrapFrame->SegCs < 8) {
  456. //
  457. // If user mode and the selector value is less than 8, we
  458. // know it is an invalid selector. Set it to flat user
  459. // mode selector. Another reason we need to check for this
  460. // is that any cs value less than 8 causes our exit kernel
  461. // macro to treat its exit trap fram as an edited frame.
  462. //
  463. TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
  464. }
  465. }
  466. KiSegSsToTrapFrame(TrapFrame, ContextFrame->SegSs);
  467. KiEspToTrapFrame(TrapFrame, ContextFrame->Esp);
  468. if (ModeChanged) {
  469. Ki386AdjustEsp0(TrapFrame); // realign esp0 in the tss
  470. }
  471. }
  472. //
  473. // Set segment register contents if specified.
  474. //
  475. if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) {
  476. //
  477. // Set segment registers gs, fs, es, ds.
  478. //
  479. //
  480. // There's only one legal value for DS and ES, so simply set it.
  481. // This allows KeContextFromKframes to report the real values in
  482. // the frame. (which are junk most of the time, but sometimes useful
  483. // for debugging.)
  484. // Only 2 legal values for FS, let either one be set.
  485. // Force GS to be 0 to deal with entry via SysCall and exit
  486. // via exception.
  487. //
  488. // For V86 mode, the FS, GS, DS, and ES registers must be properly
  489. // set from the supplied context.
  490. //
  491. if (TrapFrame->EFlags & EFLAGS_V86_MASK) {
  492. TrapFrame->V86Fs = ContextFrame->SegFs;
  493. TrapFrame->V86Es = ContextFrame->SegEs;
  494. TrapFrame->V86Ds = ContextFrame->SegDs;
  495. TrapFrame->V86Gs = ContextFrame->SegGs;
  496. } else if (((TrapFrame->SegCs & MODE_MASK) == KernelMode)) {
  497. //
  498. // set up the standard selectors
  499. //
  500. TrapFrame->SegFs = SANITIZE_SEG(ContextFrame->SegFs, PreviousMode);
  501. TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
  502. TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
  503. TrapFrame->SegGs = 0;
  504. } else {
  505. //
  506. // If user mode, we simply return whatever left in context frame
  507. // and let trap 0d handle it (if later we trap while popping the
  508. // trap frame.) V86 mode also get handled here.
  509. //
  510. TrapFrame->SegFs = ContextFrame->SegFs;
  511. TrapFrame->SegEs = ContextFrame->SegEs;
  512. TrapFrame->SegDs = ContextFrame->SegDs;
  513. if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK)) {
  514. TrapFrame->SegGs = 0;
  515. } else {
  516. TrapFrame->SegGs = ContextFrame->SegGs;
  517. }
  518. }
  519. }
  520. //
  521. // Set integer registers contents if specified.
  522. //
  523. if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
  524. //
  525. // Set integer registers edi, esi, ebx, edx, ecx, eax.
  526. //
  527. // Can NOT call RtlCopyMemory here because the regs aren't
  528. // contiguous in pusha frame, and we don't want to export
  529. // bits of junk into context record.
  530. //
  531. TrapFrame->Edi = ContextFrame->Edi;
  532. TrapFrame->Esi = ContextFrame->Esi;
  533. TrapFrame->Ebx = ContextFrame->Ebx;
  534. TrapFrame->Ecx = ContextFrame->Ecx;
  535. TrapFrame->Edx = ContextFrame->Edx;
  536. TrapFrame->Eax = ContextFrame->Eax;
  537. }
  538. //
  539. // Set extended register contents if requested, and type of target
  540. // is user. (system frames have no extended state, so ignore request)
  541. //
  542. if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS) &&
  543. ((TrapFrame->SegCs & MODE_MASK) == UserMode)) {
  544. //
  545. // This is the base TrapFrame, and the NpxFrame is on the base
  546. // of the kernel stack, just above it in memory.
  547. //
  548. NpxFrame = (PFX_SAVE_AREA)(TrapFrame + 1);
  549. if (KeI386NpxPresent) {
  550. KiFlushNPXState (NULL);
  551. RtlCopyMemory( (PVOID)&(NpxFrame->U.FxArea),
  552. (PVOID)&(ContextFrame->ExtendedRegisters[0]),
  553. MAXIMUM_SUPPORTED_EXTENSION
  554. );
  555. //
  556. // Make sure only valid floating state bits are moved to Cr0NpxState.
  557. //
  558. NpxFrame->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
  559. //
  560. // Make sure all reserved bits are clear in MXCSR so we don't get a GP
  561. // fault when doing an FRSTOR on this state.
  562. //
  563. NpxFrame->U.FxArea.MXCsr = SANITIZE_MXCSR(NpxFrame->U.FxArea.MXCsr);
  564. //
  565. // Only let VDMs turn on the EM bit. The kernel can't do
  566. // anything for FLAT apps
  567. //
  568. if (PsGetCurrentProcess()->VdmObjects != NULL) {
  569. NpxFrame->Cr0NpxState |= ContextFrame->FloatSave.Cr0NpxState &
  570. (CR0_EM | CR0_MP);
  571. }
  572. }
  573. }
  574. //
  575. // Set floating register contents if requested, and type of target
  576. // is user. (system frames have no fp state, so ignore request)
  577. //
  578. if (((ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) &&
  579. ((TrapFrame->SegCs & MODE_MASK) == UserMode)) {
  580. //
  581. // This is the base TrapFrame, and the NpxFrame is on the base
  582. // of the kernel stack, just above it in memory.
  583. //
  584. NpxFrame = (PFX_SAVE_AREA)(TrapFrame + 1);
  585. if (KeI386NpxPresent) {
  586. //
  587. // Set coprocessor stack, control and status registers
  588. //
  589. KiFlushNPXState (NULL);
  590. if (KeI386FxsrPresent == TRUE) {
  591. //
  592. // Restore FP state in the fxrstor format
  593. //
  594. NpxFrame->U.FxArea.ControlWord =
  595. (USHORT)ContextFrame->FloatSave.ControlWord;
  596. NpxFrame->U.FxArea.StatusWord =
  597. (USHORT)ContextFrame->FloatSave.StatusWord;
  598. //
  599. // Construct the tag word from fnsave format to fxsave format
  600. //
  601. NpxFrame->U.FxArea.TagWord = 0; // Mark every register invalid
  602. TagWord = ContextFrame->FloatSave.TagWord;
  603. for (i = 0; i < FN_BITS_PER_TAGWORD; i+=2) {
  604. if (((TagWord >> i) & FN_TAG_MASK) != FN_TAG_EMPTY) {
  605. //
  606. // This register is valid
  607. //
  608. NpxFrame->U.FxArea.TagWord |= (FX_TAG_VALID << (i/2));
  609. }
  610. }
  611. NpxFrame->U.FxArea.ErrorOffset =
  612. ContextFrame->FloatSave.ErrorOffset;
  613. NpxFrame->U.FxArea.ErrorSelector =
  614. (ContextFrame->FloatSave.ErrorSelector & 0xFFFF);
  615. NpxFrame->U.FxArea.ErrorOpcode =
  616. (USHORT)((ContextFrame->FloatSave.ErrorSelector >> 16) & 0xFFFF);
  617. NpxFrame->U.FxArea.DataOffset =
  618. ContextFrame->FloatSave.DataOffset;
  619. NpxFrame->U.FxArea.DataSelector =
  620. ContextFrame->FloatSave.DataSelector;
  621. //
  622. // Fxrstor format has each FP register in 128 bits (16 bytes)
  623. // where as fnsave saves each FP register in 80 bits (10 bytes)
  624. //
  625. RtlZeroMemory ((PVOID)&NpxFrame->U.FxArea.RegisterArea[0],
  626. SIZE_OF_FX_REGISTERS
  627. );
  628. for (i = 0; i < NUMBER_OF_FP_REGISTERS; i++) {
  629. for (j = 0; j < BYTES_PER_FP_REGISTER; j++) {
  630. NpxFrame->U.FxArea.RegisterArea[i*BYTES_PER_FX_REGISTER+j] =
  631. ContextFrame->FloatSave.RegisterArea[i*BYTES_PER_FP_REGISTER+j];
  632. }
  633. }
  634. } else {
  635. NpxFrame->U.FnArea.ControlWord =
  636. ContextFrame->FloatSave.ControlWord;
  637. NpxFrame->U.FnArea.StatusWord =
  638. ContextFrame->FloatSave.StatusWord;
  639. NpxFrame->U.FnArea.TagWord =
  640. ContextFrame->FloatSave.TagWord;
  641. NpxFrame->U.FnArea.ErrorOffset =
  642. ContextFrame->FloatSave.ErrorOffset;
  643. NpxFrame->U.FnArea.ErrorSelector =
  644. ContextFrame->FloatSave.ErrorSelector;
  645. NpxFrame->U.FnArea.DataOffset =
  646. ContextFrame->FloatSave.DataOffset;
  647. NpxFrame->U.FnArea.DataSelector =
  648. ContextFrame->FloatSave.DataSelector;
  649. for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) {
  650. NpxFrame->U.FnArea.RegisterArea[i] =
  651. ContextFrame->FloatSave.RegisterArea[i];
  652. }
  653. }
  654. //
  655. // Make sure only valid floating state bits are moved to Cr0NpxState.
  656. //
  657. NpxFrame->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
  658. //
  659. // Only let VDMs turn on the EM bit. The kernel can't do
  660. // anything for FLAT apps
  661. //
  662. if (PsGetCurrentProcess()->VdmObjects != NULL) {
  663. NpxFrame->Cr0NpxState |= ContextFrame->FloatSave.Cr0NpxState &
  664. (CR0_EM | CR0_MP);
  665. }
  666. } else {
  667. if (PsGetCurrentProcess()->VdmObjects != NULL) {
  668. //
  669. // This is a special hack to allow SetContext for VDMs to
  670. // turn on/off it's CR0_EM bit.
  671. //
  672. NpxFrame->Cr0NpxState &= ~(CR0_MP | CR0_TS | CR0_EM | CR0_PE);
  673. NpxFrame->Cr0NpxState |=
  674. VdmUserCr0MapIn[ContextFrame->FloatSave.Cr0NpxState & (CR0_EM | CR0_MP)];
  675. } else {
  676. //
  677. // The 80387 is being emulated by the R3 emulator.
  678. // ** The only time the Npx state is ever obtained or set is
  679. // ** for userlevel handling. Current Irql must be 0 or 1.
  680. // And the context being set must be for the current thread.
  681. // Go smash the floatingpoint context into the R3 emulator's
  682. // data area.
  683. //
  684. #if DBG
  685. OldIrql = KeRaiseIrqlToSynchLevel();
  686. Pcr = KeGetPcr();
  687. ASSERT (Pcr->Prcb->CurrentThread->Teb == Pcr->NtTib.Self);
  688. KeLowerIrql (OldIrql);
  689. #endif
  690. StateSaved = KiNpxFrameToEm87State(&ContextFrame->FloatSave);
  691. if (StateSaved) {
  692. //
  693. // Make sure only valid floating state bits are moved to
  694. // Cr0NpxState. Since we are emulating, don't allow
  695. // resetting CR0_EM.
  696. //
  697. NpxFrame->Cr0NpxState &= ~(CR0_MP | CR0_TS);
  698. NpxFrame->Cr0NpxState |=
  699. ContextFrame->FloatSave.Cr0NpxState & CR0_MP;
  700. }
  701. }
  702. }
  703. }
  704. //
  705. // Set debug register state if specified. If previous mode is user
  706. // mode (i.e. it's a user frame we're setting) and if effect will be to
  707. // cause at least one of the LE (local enable) bits in Dr7 to be
  708. // set (i.e. at least one of Dr0,1,2,3 are active) then set DebugActive
  709. // in the thread object to true. Otherwise set it to false.
  710. //
  711. if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) {
  712. TrapFrame->Dr0 = SANITIZE_DRADDR(ContextFrame->Dr0, PreviousMode);
  713. TrapFrame->Dr1 = SANITIZE_DRADDR(ContextFrame->Dr1, PreviousMode);
  714. TrapFrame->Dr2 = SANITIZE_DRADDR(ContextFrame->Dr2, PreviousMode);
  715. TrapFrame->Dr3 = SANITIZE_DRADDR(ContextFrame->Dr3, PreviousMode);
  716. TrapFrame->Dr6 = SANITIZE_DR6(ContextFrame->Dr6, PreviousMode);
  717. TrapFrame->Dr7 = SANITIZE_DR7(ContextFrame->Dr7, PreviousMode);
  718. if (PreviousMode != KernelMode) {
  719. KeGetPcr()->DebugActive = KeGetCurrentThread()->DebugActive =
  720. (BOOLEAN)((ContextFrame->Dr7 & DR7_ACTIVE) != 0);
  721. }
  722. }
  723. //
  724. // If thread is supposed to have IOPL, then force it on in eflags
  725. //
  726. if (KeGetCurrentThread()->Iopl) {
  727. TrapFrame->EFlags |= (EFLAGS_IOPL_MASK & -1); // IOPL = 3
  728. }
  729. return;
  730. }
  731. VOID
  732. KiDispatchException (
  733. IN PEXCEPTION_RECORD ExceptionRecord,
  734. IN PKEXCEPTION_FRAME ExceptionFrame,
  735. IN PKTRAP_FRAME TrapFrame,
  736. IN KPROCESSOR_MODE PreviousMode,
  737. IN BOOLEAN FirstChance
  738. )
  739. /*++
  740. Routine Description:
  741. This function is called to dispatch an exception to the proper mode and
  742. to cause the exception dispatcher to be called. If the previous mode is
  743. kernel, then the exception dispatcher is called directly to process the
  744. exception. Otherwise the exception record, exception frame, and trap
  745. frame contents are copied to the user mode stack. The contents of the
  746. exception frame and trap are then modified such that when control is
  747. returned, execution will commense in user mode in a routine which will
  748. call the exception dispatcher.
  749. Arguments:
  750. ExceptionRecord - Supplies a pointer to an exception record.
  751. ExceptionFrame - Supplies a pointer to an exception frame. For NT386,
  752. this should be NULL.
  753. TrapFrame - Supplies a pointer to a trap frame.
  754. PreviousMode - Supplies the previous processor mode.
  755. FirstChance - Supplies a boolean value that specifies whether this is
  756. the first (TRUE) or second (FALSE) chance for the exception.
  757. Return Value:
  758. None.
  759. --*/
  760. {
  761. CONTEXT ContextFrame;
  762. EXCEPTION_RECORD ExceptionRecord1, ExceptionRecord2;
  763. LONG Length;
  764. ULONG UserStack1;
  765. ULONG UserStack2;
  766. //
  767. // Move machine state from trap and exception frames to a context frame,
  768. // and increment the number of exceptions dispatched.
  769. //
  770. KeGetCurrentPrcb()->KeExceptionDispatchCount += 1;
  771. ContextFrame.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
  772. if (PreviousMode == UserMode) {
  773. //
  774. // For usermode exceptions always try to dispatch the floating
  775. // point state. This allows expection handlers & debuggers to
  776. // examine/edit the npx context if required. Plus it allows
  777. // exception handlers to use fp instructions without detroying
  778. // the npx state at the time of the exception.
  779. //
  780. // Note: If there's no 80387, ContextTo/FromKFrames will use the
  781. // emulator's current state. If the emulator can not give the
  782. // current state, then the context_floating_point bit will be
  783. // turned off by ContextFromKFrames.
  784. //
  785. ContextFrame.ContextFlags |= CONTEXT_FLOATING_POINT;
  786. if (KeI386XMMIPresent) {
  787. ContextFrame.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
  788. }
  789. }
  790. KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame);
  791. //
  792. // if it is BREAK_POINT exception, we subtract 1 from EIP and report
  793. // the updated EIP to user. This is because Cruiser requires EIP
  794. // points to the int 3 instruction (not the instruction following int 3).
  795. // In this case, BreakPoint exception is fatal. Otherwise we will step
  796. // on the int 3 over and over again, if user does not handle it
  797. //
  798. // if the BREAK_POINT occured in V86 mode, the debugger running in the
  799. // VDM will expect CS:EIP to point after the exception (the way the
  800. // processor left it. this is also true for protected mode dos
  801. // app debuggers. We will need a way to detect this.
  802. //
  803. //
  804. // if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
  805. // !(ContextFrame.EFlags & EFLAGS_V86_MASK)) {
  806. switch (ExceptionRecord->ExceptionCode) {
  807. case STATUS_BREAKPOINT:
  808. ContextFrame.Eip--;
  809. break;
  810. }
  811. //
  812. // Select the method of handling the exception based on the previous mode.
  813. //
  814. ASSERT ((
  815. !((PreviousMode == KernelMode) &&
  816. (ContextFrame.EFlags & EFLAGS_V86_MASK))
  817. ));
  818. if (PreviousMode == KernelMode) {
  819. //
  820. // Previous mode was kernel.
  821. //
  822. // If the kernel debugger is active, then give the kernel debugger the
  823. // first chance to handle the exception. If the kernel debugger handles
  824. // the exception, then continue execution. Else attempt to dispatch the
  825. // exception to a frame based handler. If a frame based handler handles
  826. // the exception, then continue execution.
  827. //
  828. // If a frame based handler does not handle the exception,
  829. // give the kernel debugger a second chance, if it's present.
  830. //
  831. // If the exception is still unhandled, call KeBugCheck().
  832. //
  833. if (FirstChance == TRUE) {
  834. if ((KiDebugRoutine != NULL) &&
  835. (((KiDebugRoutine) (TrapFrame,
  836. ExceptionFrame,
  837. ExceptionRecord,
  838. &ContextFrame,
  839. PreviousMode,
  840. FALSE)) != FALSE)) {
  841. goto Handled1;
  842. }
  843. // Kernel debugger didn't handle exception.
  844. if (RtlDispatchException(ExceptionRecord, &ContextFrame) == TRUE) {
  845. goto Handled1;
  846. }
  847. }
  848. //
  849. // This is the second chance to handle the exception.
  850. //
  851. if ((KiDebugRoutine != NULL) &&
  852. (((KiDebugRoutine) (TrapFrame,
  853. ExceptionFrame,
  854. ExceptionRecord,
  855. &ContextFrame,
  856. PreviousMode,
  857. TRUE)) != FALSE)) {
  858. goto Handled1;
  859. }
  860. KeBugCheckEx(
  861. KERNEL_MODE_EXCEPTION_NOT_HANDLED,
  862. ExceptionRecord->ExceptionCode,
  863. (ULONG)ExceptionRecord->ExceptionAddress,
  864. (ULONG)TrapFrame,
  865. 0);
  866. } else {
  867. //
  868. // Previous mode was user.
  869. //
  870. // If this is the first chance and the current process has a debugger
  871. // port, then send a message to the debugger port and wait for a reply.
  872. // If the debugger handles the exception, then continue execution. Else
  873. // transfer the exception information to the user stack, transition to
  874. // user mode, and attempt to dispatch the exception to a frame based
  875. // handler. If a frame based handler handles the exception, then continue
  876. // execution with the continue system service. Else execute the
  877. // NtRaiseException system service with FirstChance == FALSE, which
  878. // will call this routine a second time to process the exception.
  879. //
  880. // If this is the second chance and the current process has a debugger
  881. // port, then send a message to the debugger port and wait for a reply.
  882. // If the debugger handles the exception, then continue execution. Else
  883. // if the current process has a subsystem port, then send a message to
  884. // the subsystem port and wait for a reply. If the subsystem handles the
  885. // exception, then continue execution. Else terminate the thread.
  886. //
  887. if (FirstChance == TRUE) {
  888. //
  889. // This is the first chance to handle the exception.
  890. //
  891. if ((KiDebugRoutine != NULL) &&
  892. ((PsGetCurrentProcess()->DebugPort == NULL) ||
  893. (KdIsThisAKdTrap(ExceptionRecord, &ContextFrame, UserMode))))
  894. {
  895. //
  896. // Now dispatch the fault to the kernel debugger.
  897. //
  898. if ((((KiDebugRoutine) (TrapFrame,
  899. ExceptionFrame,
  900. ExceptionRecord,
  901. &ContextFrame,
  902. PreviousMode,
  903. FALSE)) != FALSE)) {
  904. goto Handled1;
  905. }
  906. }
  907. if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) {
  908. goto Handled2;
  909. }
  910. //
  911. // Transfer exception information to the user stack, transition
  912. // to user mode, and attempt to dispatch the exception to a frame
  913. // based handler.
  914. repeat:
  915. try {
  916. //
  917. // If the SS segment is not 32 bit flat, there is no point
  918. // to dispatch exception to frame based exception handler.
  919. //
  920. if (TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK) ||
  921. TrapFrame->EFlags & EFLAGS_V86_MASK ) {
  922. ExceptionRecord2.ExceptionCode = STATUS_ACCESS_VIOLATION;
  923. ExceptionRecord2.ExceptionFlags = 0;
  924. ExceptionRecord2.NumberParameters = 0;
  925. ExRaiseException(&ExceptionRecord2);
  926. }
  927. //
  928. // Compute length of context record and new aligned user stack
  929. // pointer.
  930. //
  931. Length = (sizeof(CONTEXT) + CONTEXT_ROUND) & ~CONTEXT_ROUND;
  932. UserStack1 = (ContextFrame.Esp & ~CONTEXT_ROUND) - Length;
  933. //
  934. // Probe user stack area for writability and then transfer the
  935. // context record to the user stack.
  936. //
  937. ProbeForWrite((PCHAR)UserStack1, Length, CONTEXT_ALIGN);
  938. RtlCopyMemory((PULONG)UserStack1, &ContextFrame, sizeof(CONTEXT));
  939. //
  940. // Compute length of exception record and new aligned stack
  941. // address.
  942. //
  943. Length = (sizeof(EXCEPTION_RECORD) - (EXCEPTION_MAXIMUM_PARAMETERS -
  944. ExceptionRecord->NumberParameters) * sizeof(ULONG) +3) &
  945. (~3);
  946. UserStack2 = UserStack1 - Length;
  947. //
  948. // Probe user stack area for writeability and then transfer the
  949. // context record to the user stack area.
  950. // N.B. The probing length is Length+8 because there are two
  951. // arguments need to be pushed to user stack later.
  952. //
  953. ProbeForWrite((PCHAR)(UserStack2 - 8), Length + 8, sizeof(ULONG));
  954. RtlCopyMemory((PULONG)UserStack2, ExceptionRecord, Length);
  955. //
  956. // Push address of exception record, context record to the
  957. // user stack. They are the two parameters required by
  958. // _KiUserExceptionDispatch.
  959. //
  960. *(PULONG)(UserStack2 - sizeof(ULONG)) = UserStack1;
  961. *(PULONG)(UserStack2 - 2*sizeof(ULONG)) = UserStack2;
  962. //
  963. // Set new stack pointer to the trap frame.
  964. //
  965. KiSegSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
  966. KiEspToTrapFrame(TrapFrame, (UserStack2 - sizeof(ULONG)*2));
  967. //
  968. // Force correct R3 selectors into TrapFrame.
  969. //
  970. TrapFrame->SegCs = SANITIZE_SEG(KGDT_R3_CODE, PreviousMode);
  971. TrapFrame->SegDs = SANITIZE_SEG(KGDT_R3_DATA, PreviousMode);
  972. TrapFrame->SegEs = SANITIZE_SEG(KGDT_R3_DATA, PreviousMode);
  973. TrapFrame->SegFs = SANITIZE_SEG(KGDT_R3_TEB, PreviousMode);
  974. TrapFrame->SegGs = 0;
  975. //
  976. // Set the address of the exception routine that will call the
  977. // exception dispatcher and then return to the trap handler.
  978. // The trap handler will restore the exception and trap frame
  979. // context and continue execution in the routine that will
  980. // call the exception dispatcher.
  981. //
  982. TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
  983. return;
  984. } except (KiCopyInformation(&ExceptionRecord1,
  985. (GetExceptionInformation())->ExceptionRecord)) {
  986. //
  987. // If the exception is a stack overflow, then attempt
  988. // to raise the stack overflow exception. Otherwise,
  989. // the user's stack is not accessible, or is misaligned,
  990. // and second chance processing is performed.
  991. //
  992. if (ExceptionRecord1.ExceptionCode == STATUS_STACK_OVERFLOW) {
  993. ExceptionRecord1.ExceptionAddress = ExceptionRecord->ExceptionAddress;
  994. RtlCopyMemory((PVOID)ExceptionRecord,
  995. &ExceptionRecord1, sizeof(EXCEPTION_RECORD));
  996. goto repeat;
  997. }
  998. }
  999. }
  1000. //
  1001. // This is the second chance to handle the exception.
  1002. //
  1003. if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) {
  1004. goto Handled2;
  1005. } else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) {
  1006. goto Handled2;
  1007. } else {
  1008. ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
  1009. KeBugCheckEx(
  1010. KERNEL_MODE_EXCEPTION_NOT_HANDLED,
  1011. ExceptionRecord->ExceptionCode,
  1012. (ULONG)ExceptionRecord->ExceptionAddress,
  1013. (ULONG)TrapFrame,
  1014. 0);
  1015. }
  1016. }
  1017. //
  1018. // Move machine state from context frame to trap and exception frames and
  1019. // then return to continue execution with the restored state.
  1020. //
  1021. Handled1:
  1022. KeContextToKframes(TrapFrame, ExceptionFrame, &ContextFrame,
  1023. ContextFrame.ContextFlags, PreviousMode);
  1024. //
  1025. // Exception was handled by the debugger or the associated subsystem
  1026. // and state was modified, if necessary, using the get state and set
  1027. // state capabilities. Therefore the context frame does not need to
  1028. // be transfered to the trap and exception frames.
  1029. //
  1030. Handled2:
  1031. return;
  1032. }
  1033. ULONG
  1034. KiCopyInformation (
  1035. IN OUT PEXCEPTION_RECORD ExceptionRecord1,
  1036. IN PEXCEPTION_RECORD ExceptionRecord2
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This function is called from an exception filter to copy the exception
  1041. information from one exception record to another when an exception occurs.
  1042. Arguments:
  1043. ExceptionRecord1 - Supplies a pointer to the destination exception record.
  1044. ExceptionRecord2 - Supplies a pointer to the source exception record.
  1045. Return Value:
  1046. A value of EXCEPTION_EXECUTE_HANDLER is returned as the function value.
  1047. --*/
  1048. {
  1049. //
  1050. // Copy one exception record to another and return value that causes
  1051. // an exception handler to be executed.
  1052. //
  1053. RtlCopyMemory((PVOID)ExceptionRecord1,
  1054. (PVOID)ExceptionRecord2,
  1055. sizeof(EXCEPTION_RECORD));
  1056. return EXCEPTION_EXECUTE_HANDLER;
  1057. }
  1058. NTSTATUS
  1059. KeRaiseUserException(
  1060. IN NTSTATUS ExceptionCode
  1061. )
  1062. /*++
  1063. Routine Description:
  1064. This function causes an exception to be raised in the calling thread's user-mode
  1065. context. It does this by editing the trap frame the kernel was entered with to
  1066. point to trampoline code that raises the requested exception.
  1067. Arguments:
  1068. ExceptionCode - Supplies the status value to be used as the exception
  1069. code for the exception that is to be raised.
  1070. Return Value:
  1071. The status value that should be returned by the caller.
  1072. --*/
  1073. {
  1074. PKTHREAD Thread;
  1075. PKTRAP_FRAME TrapFrame;
  1076. PTEB Teb;
  1077. ULONG PreviousEsp;
  1078. ASSERT(KeGetPreviousMode() == UserMode);
  1079. Thread = KeGetCurrentThread();
  1080. TrapFrame = Thread->TrapFrame;
  1081. if (TrapFrame == NULL) {
  1082. return ExceptionCode;
  1083. }
  1084. Teb = (PTEB)Thread->Teb;
  1085. //
  1086. // In order to create the correct call stack, we push the old return
  1087. // address onto the stack. The status code to be raised is passed
  1088. // in the TEB.
  1089. //
  1090. try {
  1091. Teb->ExceptionCode = ExceptionCode;
  1092. PreviousEsp = KiEspFromTrapFrame (TrapFrame) - sizeof (ULONG);
  1093. ProbeForWriteSmallStructure ((PLONG)PreviousEsp, sizeof (LONG), sizeof (UCHAR));
  1094. *(PLONG)PreviousEsp = TrapFrame->Eip;
  1095. } except(EXCEPTION_EXECUTE_HANDLER) {
  1096. return(ExceptionCode);
  1097. }
  1098. KiEspToTrapFrame (TrapFrame, PreviousEsp);
  1099. TrapFrame->Eip = (ULONG)KeRaiseUserExceptionDispatcher;
  1100. return ExceptionCode;
  1101. }