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.

946 lines
29 KiB

  1. /*++
  2. Module Name:
  3. exceptn.c
  4. Abstract:
  5. This module implement the code necessary to dispatch expections to the
  6. proper mode and invoke the exception dispatcher.
  7. Author:
  8. William K. Cheung (wcheung) 10-Nov-1995
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "ki.h"
  14. #include "ntfpia64.h"
  15. #include "fedefs.h"
  16. #include "fetypes.h"
  17. #include "fesupprt.h"
  18. #include "feproto.h"
  19. #include "floatem.h"
  20. #include "fpswa.h"
  21. LONG
  22. fp_emulate (
  23. ULONG trap_type,
  24. PVOID pbundle,
  25. ULONGLONG *pipsr,
  26. ULONGLONG *pfpsr,
  27. ULONGLONG *pisr,
  28. ULONGLONG *ppreds,
  29. ULONGLONG *pifs,
  30. PVOID fp_state
  31. );
  32. BOOLEAN
  33. KiEmulateFloat (
  34. PEXCEPTION_RECORD ExceptionRecord,
  35. PKEXCEPTION_FRAME ExceptionFrame,
  36. PKTRAP_FRAME TrapFrame
  37. )
  38. {
  39. FLOATING_POINT_STATE FpState;
  40. USHORT ISRCode;
  41. ULONG TrapType;
  42. PVOID ExceptionAddress;
  43. BUNDLE KeBundle;
  44. LONG Status = -1;
  45. FpState.ExceptionFrame = (PVOID)ExceptionFrame;
  46. FpState.TrapFrame = (PVOID)TrapFrame;
  47. if (ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS) {
  48. TrapType = 1;
  49. ExceptionAddress = (PVOID)TrapFrame->StIIP;
  50. } else {
  51. TrapType = 0;
  52. ExceptionAddress = (PVOID)TrapFrame->StIIPA;
  53. }
  54. try {
  55. KeBundle.BundleLow =(ULONGLONG)(*(PULONGLONG)ExceptionAddress);
  56. KeBundle.BundleHigh =(ULONGLONG)(*((PULONGLONG)ExceptionAddress + 1));
  57. } except (EXCEPTION_EXECUTE_HANDLER) {
  58. //
  59. // if an exception (memory fault) occurs, then let hardware handle it
  60. //
  61. return TRUE;
  62. }
  63. if ((Status = fp_emulate(TrapType, &KeBundle,
  64. &TrapFrame->StIPSR, &TrapFrame->StFPSR, &TrapFrame->StISR,
  65. &TrapFrame->Preds, &TrapFrame->StIFS, (PVOID)&FpState)) == 0) {
  66. //
  67. // Exception was handled and state modified.
  68. // Therefore the context frame does not need to
  69. // be transfered to the trap and exception frames.
  70. //
  71. // Since it was fault, PC should be advanced
  72. //
  73. if (TrapType == 1) {
  74. KiAdvanceInstPointer(TrapFrame);
  75. }
  76. if (TrapFrame->StIPSR & (1 << PSR_MFH)) {
  77. //
  78. // high fp set is modified; set the dfh and clear the mfh
  79. // to force a reload on the first access to the high fp set
  80. //
  81. TrapFrame->StIPSR &= ~(1i64 << PSR_MFH);
  82. TrapFrame->StIPSR |= (1i64 << PSR_DFH);
  83. }
  84. return TRUE;
  85. }
  86. if (Status == -1) {
  87. return FALSE;
  88. }
  89. ISRCode = (USHORT)TrapFrame->StISR;
  90. if (Status & 0x1) {
  91. ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR;
  92. if (!(Status & 0x4)) {
  93. if (TrapType == 1) {
  94. //
  95. // FP Fault
  96. //
  97. if (ISRCode & 0x11) {
  98. ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
  99. } else if (ISRCode & 0x22) {
  100. ExceptionRecord->ExceptionCode = STATUS_FLOAT_DENORMAL_OPERAND;
  101. } else if (ISRCode & 0x44) {
  102. ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
  103. }
  104. } else {
  105. //
  106. // FP Trap
  107. //
  108. ISRCode = ISRCode >> 7;
  109. if (ISRCode & 0x11) {
  110. ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
  111. } else if (ISRCode & 0x22) {
  112. ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
  113. } else if (ISRCode & 0x44) {
  114. ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
  115. }
  116. }
  117. }
  118. if (Status & 0x2) {
  119. //
  120. // FP Fault To Trap
  121. //
  122. KiAdvanceInstPointer(TrapFrame);
  123. if (!(Status & 0x4)) {
  124. ISRCode = ISRCode >> 7;
  125. if (ISRCode & 0x11) {
  126. ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
  127. } else if (ISRCode & 0x22) {
  128. ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
  129. } else if (ISRCode & 0x44) {
  130. ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
  131. }
  132. } else {
  133. ExceptionRecord->ExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS;
  134. }
  135. }
  136. }
  137. return FALSE;
  138. }
  139. typedef struct _BRL_INST {
  140. union {
  141. struct {
  142. ULONGLONG qp: 6;
  143. ULONGLONG b1: 3;
  144. ULONGLONG rsv0: 3;
  145. ULONGLONG p: 1;
  146. ULONGLONG imm20: 20;
  147. ULONGLONG wh: 2;
  148. ULONGLONG d: 1;
  149. ULONGLONG i: 1;
  150. ULONGLONG Op: 4;
  151. ULONGLONG rsv1: 23;
  152. } i;
  153. ULONGLONG Ulong64;
  154. } u;
  155. } BRL_INST;
  156. typedef struct _BRL2_INST {
  157. union {
  158. struct {
  159. ULONGLONG rsv0: 2;
  160. ULONGLONG imm39: 39;
  161. ULONGLONG rsv1: 23;
  162. } i;
  163. ULONGLONG Ulong64;
  164. } u;
  165. } BRL0_INST;
  166. typedef struct _FRAME_MARKER {
  167. union {
  168. struct {
  169. ULONGLONG sof : 7;
  170. ULONGLONG sol : 7;
  171. ULONGLONG sor : 4;
  172. ULONGLONG rrbgr : 7;
  173. ULONGLONG rrbfr : 7;
  174. ULONGLONG rrbpr : 6;
  175. } f;
  176. ULONGLONG Ulong64;
  177. } u;
  178. } FRAME_MARKER;
  179. BOOLEAN
  180. KiEmulateBranchLongFault(
  181. IN PEXCEPTION_RECORD ExceptionRecord,
  182. IN OUT PKEXCEPTION_FRAME ExceptionFrame,
  183. IN OUT PKTRAP_FRAME TrapFrame
  184. )
  185. /*++
  186. Routine Description:
  187. This function is called to emulate a brl instruction.
  188. Arguments:
  189. ExceptionRecord - Supplies a pointer to an exception record.
  190. ExceptionFrame - Supplies a pointer to an exception frame.
  191. TrapFrame - Supplies a pointer to a trap frame.
  192. Return Value:
  193. A value of TRUE is return if the brl is successfully emulated.
  194. Otherwise, a value of FALSE is returned.
  195. --*/
  196. {
  197. PULONGLONG BundleAddress;
  198. PVOID ExceptionAddress;
  199. ULONGLONG BundleLow;
  200. ULONGLONG BundleHigh;
  201. ULONGLONG Template;
  202. BRL_INST BrlInst;
  203. BRL0_INST BrlInst0;
  204. ULONGLONG NewIP;
  205. ULONGLONG Taken;
  206. FRAME_MARKER Cfm;
  207. BundleAddress = (PULONGLONG)TrapFrame->StIIP;
  208. ExceptionAddress = (PVOID) TrapFrame->StIIP;
  209. try {
  210. //
  211. // get the instruction bundle
  212. //
  213. BundleLow = *BundleAddress;
  214. BundleHigh = *(BundleAddress+1);
  215. } except ((KiCopyInformation(ExceptionRecord,
  216. (GetExceptionInformation())->ExceptionRecord))) {
  217. //
  218. // Preserve the original exception address.
  219. //
  220. ExceptionRecord->ExceptionAddress = ExceptionAddress;
  221. return FALSE;
  222. }
  223. BrlInst0.u.Ulong64 = (BundleLow >> 46) | (BundleHigh << 18);
  224. BrlInst.u.Ulong64 = (BundleHigh >> 23);
  225. Template = BundleLow & 0x1f;
  226. if (!((Template == 4)||(Template == 5))) {
  227. //
  228. // if template does not indicate MLX, return FALSE
  229. //
  230. return FALSE;
  231. }
  232. switch (BrlInst.u.i.Op) {
  233. case 0xc: // brl.cond
  234. Taken = TrapFrame->Preds & (1i64 << BrlInst.u.i.qp);
  235. break;
  236. case 0xd: // brl.call
  237. Taken = TrapFrame->Preds & (1i64 << BrlInst.u.i.qp);
  238. if (Taken) {
  239. switch (BrlInst.u.i.b1) {
  240. case 0: TrapFrame->BrRp = TrapFrame->StIIP + 16; break;
  241. case 1: ExceptionFrame->BrS0 = TrapFrame->StIIP + 16; break;
  242. case 2: ExceptionFrame->BrS1 = TrapFrame->StIIP + 16; break;
  243. case 3: ExceptionFrame->BrS2 = TrapFrame->StIIP + 16; break;
  244. case 4: ExceptionFrame->BrS3 = TrapFrame->StIIP + 16; break;
  245. case 5: ExceptionFrame->BrS4 = TrapFrame->StIIP + 16; break;
  246. case 6: TrapFrame->BrT0 = TrapFrame->StIIP + 16; break;
  247. case 7: TrapFrame->BrT1 = TrapFrame->StIIP + 16; break;
  248. }
  249. TrapFrame->RsPFS = TrapFrame->StIFS & 0x3FFFFFFFFFi64;
  250. TrapFrame->RsPFS |= (ExceptionFrame->ApEC & (0x3fi64 << 52));
  251. TrapFrame->RsPFS |= (((TrapFrame->StIPSR >> PSR_CPL) & 0x3) << 62);
  252. Cfm.u.Ulong64 = TrapFrame->StIFS;
  253. Cfm.u.f.sof -= Cfm.u.f.sol;
  254. Cfm.u.f.sol = 0;
  255. Cfm.u.f.sor = 0;
  256. Cfm.u.f.rrbgr = 0;
  257. Cfm.u.f.rrbfr = 0;
  258. Cfm.u.f.rrbpr = 0;
  259. TrapFrame->StIFS = Cfm.u.Ulong64;
  260. TrapFrame->StIFS |= 0x8000000000000000;
  261. }
  262. break;
  263. default:
  264. return FALSE;
  265. }
  266. if (Taken) {
  267. NewIP = TrapFrame->StIIP +
  268. (((BrlInst.u.i.i<<59)|(BrlInst0.u.i.imm39<<20)|(BrlInst.u.i.imm20)) << 4);
  269. TrapFrame->StIIP = NewIP;
  270. } else {
  271. TrapFrame->StIIP += 16;
  272. }
  273. TrapFrame->StIPSR &= ~(3i64 << PSR_RI);
  274. return TRUE;
  275. }
  276. VOID
  277. KiDispatchException (
  278. IN PEXCEPTION_RECORD ExceptionRecord,
  279. IN PKEXCEPTION_FRAME ExceptionFrame,
  280. IN PKTRAP_FRAME TrapFrame,
  281. IN KPROCESSOR_MODE PreviousMode,
  282. IN BOOLEAN FirstChance
  283. )
  284. /*++
  285. Routine Description:
  286. This function is called to dispatch an exception to the proper mode and
  287. to cause the exception dispatcher to be called.
  288. If the exception is a data misalignment, this is the first chance for
  289. handling the exception, and the current thread has enabled automatic
  290. alignment fixup, then an attempt is made to emulate the unaligned
  291. reference.
  292. If the exception is a floating exception (N.B. the pseudo status
  293. STATUS_FLOAT_STACK_CHECK is used to signify this and is converted to the
  294. proper code by examiningg the main status field of the floating point
  295. status register).
  296. If the exception is neither a data misalignment nor a floating point
  297. exception and the the previous mode is kernel, then the exception
  298. dispatcher is called directly to process the exception. Otherwise the
  299. exception record, exception frame, and trap frame contents are copied
  300. to the user mode stack. The contents of the exception frame and trap
  301. are then modified such that when control is returned, execution will
  302. commense in user mode in a routine which will call the exception
  303. dispatcher.
  304. Arguments:
  305. ExceptionRecord - Supplies a pointer to an exception record.
  306. ExceptionFrame - Supplies a pointer to an exception frame.
  307. TrapFrame - Supplies a pointer to a trap frame.
  308. PreviousMode - Supplies the previous processor mode.
  309. FirstChance - Supplies a boolean variable that specifies whether this
  310. is the first (TRUE) or second (FALSE) time that this exception has
  311. been processed.
  312. Return Value:
  313. None.
  314. --*/
  315. {
  316. CONTEXT ContextFrame;
  317. EXCEPTION_RECORD ExceptionRecord1;
  318. PPLABEL_DESCRIPTOR Plabel;
  319. BOOLEAN UserApcPending;
  320. BOOLEAN AlignmentFaultHandled;
  321. BOOLEAN ExceptionWasForwarded = FALSE;
  322. ISR Isr;
  323. PSR Psr;
  324. //
  325. // If the exception is a illegal instruction, check to see if it was
  326. // trying to executing a brl instruction. If so, emulate the brl
  327. // instruction.
  328. //
  329. if (ExceptionRecord->ExceptionCode == STATUS_ILLEGAL_INSTRUCTION) {
  330. Isr.ull = TrapFrame->StISR;
  331. Psr.ull = TrapFrame->StIPSR;
  332. if ((Isr.sb.isr_code == ISR_ILLEGAL_OP) && (Isr.sb.isr_ei == 1)) {
  333. if (KiEmulateBranchLongFault(ExceptionRecord,
  334. ExceptionFrame,
  335. TrapFrame) == TRUE) {
  336. //
  337. // emulation was successful;
  338. //
  339. return;
  340. }
  341. }
  342. }
  343. //
  344. // If the exception is a data misalignment, the previous mode was user,
  345. // this is the first chance for handling the exception, and the current
  346. // thread has enabled automatic alignment fixup, then attempt to emulate
  347. // the unaligned reference.
  348. //
  349. if (ExceptionRecord->ExceptionCode == STATUS_DATATYPE_MISALIGNMENT) {
  350. AlignmentFaultHandled = KiHandleAlignmentFault( ExceptionRecord,
  351. ExceptionFrame,
  352. TrapFrame,
  353. PreviousMode,
  354. FirstChance,
  355. &ExceptionWasForwarded );
  356. if (AlignmentFaultHandled != FALSE) {
  357. goto Handled2;
  358. }
  359. }
  360. //
  361. // N.B. BREAKIN_BREAKPOINT check is in KdpTrap()
  362. //
  363. //
  364. // If the exception is a floating point exception, then the
  365. // ExceptionCode was set to STATUS_FLOAT_MULTIPLE_TRAPS or
  366. // STATUS_FLOAT_MULTIPLE_FAULTS.
  367. //
  368. if ((ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS) ||
  369. (ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS)) {
  370. if (KiEmulateFloat(ExceptionRecord, ExceptionFrame, TrapFrame)) {
  371. //
  372. // Emulation is successful; continue execution
  373. //
  374. return;
  375. }
  376. }
  377. //
  378. // Move machine state from trap and exception frames to a context frame,
  379. // and increment the number of exceptions dispatched.
  380. //
  381. ContextFrame.ContextFlags = CONTEXT_FULL;
  382. KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame);
  383. KeGetCurrentPrcb()->KeExceptionDispatchCount += 1;
  384. //
  385. // Select the method of handling the exception based on the previous mode.
  386. //
  387. if (PreviousMode == KernelMode) {
  388. //
  389. // Previous mode was kernel.
  390. //
  391. // If this is the first chance, the kernel debugger is active, and
  392. // the exception is a kernel breakpoint, then give the kernel debugger
  393. // a chance to handle the exception.
  394. //
  395. // If this is the first chance and the kernel debugger is not active
  396. // or does not handle the exception, then attempt to find a frame
  397. // handler to handle the exception.
  398. //
  399. // If this is the second chance or the exception is not handled, then
  400. // if the kernel debugger is active, then give the kernel debugger a
  401. // second chance to handle the exception. If the kernel debugger does
  402. // not handle the exception, then bug check.
  403. //
  404. if (FirstChance != FALSE) {
  405. //
  406. // This is the first chance to handle the exception.
  407. //
  408. // Note: RtlpCaptureRnats() flushes the RSE and captures the
  409. // Nat bits of stacked registers in the RSE frame at
  410. // which exception happens.
  411. //
  412. RtlpCaptureRnats(&ContextFrame);
  413. TrapFrame->RsRNAT = ContextFrame.RsRNAT;
  414. //
  415. // If the kernel debugger is active, the exception is a breakpoint,
  416. // and the breakpoint is handled by the kernel debugger, then give
  417. // the kernel debugger a chance to handle the exception.
  418. //
  419. if ((KiDebugRoutine != NULL) &&
  420. (KdIsThisAKdTrap(ExceptionRecord,
  421. &ContextFrame,
  422. KernelMode) != FALSE)) {
  423. if (((KiDebugRoutine) (TrapFrame,
  424. ExceptionFrame,
  425. ExceptionRecord,
  426. &ContextFrame,
  427. KernelMode,
  428. FALSE)) != FALSE) {
  429. goto Handled1;
  430. }
  431. }
  432. if (RtlDispatchException(ExceptionRecord, &ContextFrame) != FALSE) {
  433. goto Handled1;
  434. }
  435. }
  436. //
  437. // This is the second chance to handle the exception.
  438. //
  439. if (KiDebugRoutine != NULL) {
  440. if (((KiDebugRoutine) (TrapFrame,
  441. ExceptionFrame,
  442. ExceptionRecord,
  443. &ContextFrame,
  444. PreviousMode,
  445. TRUE)) != FALSE) {
  446. goto Handled1;
  447. }
  448. }
  449. KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
  450. ExceptionRecord->ExceptionCode,
  451. (ULONG_PTR)ExceptionRecord->ExceptionAddress,
  452. ExceptionRecord->ExceptionInformation[0],
  453. ExceptionRecord->ExceptionInformation[1]);
  454. } else {
  455. //
  456. // Previous mode was user.
  457. //
  458. // If this is the first chance, the kernel debugger is active, the
  459. // exception is a kernel breakpoint, and the current process is not
  460. // being debugged, or the current process is being debugged, but the
  461. // the breakpoint is not a kernel breakpoint instruction, then give
  462. // the kernel debugger a chance to handle the exception.
  463. //
  464. // If this is the first chance and the current process has a debugger
  465. // port, then send a message to the debugger port and wait for a reply.
  466. // If the debugger handles the exception, then continue execution. Else
  467. // transfer the exception information to the user stack, transition to
  468. // user mode, and attempt to dispatch the exception to a frame based
  469. // handler. If a frame based handler handles the exception, then continue
  470. // execution. Otherwise, execute the raise exception system service
  471. // which will call this routine a second time to process the exception.
  472. //
  473. // If this is the second chance and the current process has a debugger
  474. // port, then send a message to the debugger port and wait for a reply.
  475. // If the debugger handles the exception, then continue execution. Else
  476. // if the current process has a subsystem port, then send a message to
  477. // the subsystem port and wait for a reply. If the subsystem handles the
  478. // exception, then continue execution. Else terminate the thread.
  479. //
  480. if (FirstChance != FALSE) {
  481. //
  482. // If the kernel debugger is active, the exception is a kernel
  483. // breakpoint, and the current process is not being debugged,
  484. // or the current process is being debugged, but the breakpoint
  485. // is not a kernel breakpoint instruction, then give the kernel
  486. // debugger a chance to handle the exception.
  487. //
  488. if ((KiDebugRoutine != NULL) &&
  489. (KdIsThisAKdTrap(ExceptionRecord,
  490. &ContextFrame,
  491. UserMode) != FALSE) &&
  492. ((PsGetCurrentProcess()->DebugPort == NULL) ||
  493. ((PsGetCurrentProcess()->DebugPort != NULL) &&
  494. ((ExceptionRecord->ExceptionInformation[0] !=
  495. BREAKPOINT_STOP) &&
  496. (ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP))))) {
  497. if (((KiDebugRoutine) (TrapFrame,
  498. ExceptionFrame,
  499. ExceptionRecord,
  500. &ContextFrame,
  501. UserMode,
  502. FALSE)) != FALSE) {
  503. goto Handled1;
  504. }
  505. }
  506. //
  507. // This is the first chance to handle the exception.
  508. //
  509. if (ExceptionWasForwarded == FALSE &&
  510. DbgkForwardException(ExceptionRecord, TRUE, FALSE)) {
  511. TrapFrame->StFPSR = SANITIZE_FSR(TrapFrame->StFPSR, UserMode);
  512. goto Handled2;
  513. }
  514. //
  515. // Transfer exception information to the user stack, transition
  516. // to user mode, and attempt to dispatch the exception to a frame
  517. // based handler.
  518. //
  519. //
  520. // We are running on the kernel stack now. On the user stack, we
  521. // build a stack frame containing the following:
  522. //
  523. // | |
  524. // |-----------------------------------|
  525. // | |
  526. // | User's stack frame |
  527. // | |
  528. // |-----------------------------------|
  529. // | |
  530. // | Context record |
  531. // | |
  532. // | |
  533. // |- - - - - - - - - - - - - - - - - -|
  534. // | |
  535. // | Exception record |
  536. // | |
  537. // |- - - - - - - - - - - - - - - - - -|
  538. // | Stack Scratch Area |
  539. // |-----------------------------------|
  540. // | |
  541. //
  542. // This stack frame is for KiUserExceptionDispatcher, the assembly
  543. // langauge routine that effects transfer in user mode to
  544. // RtlDispatchException. KiUserExceptionDispatcher is passed
  545. // pointers to the Exception Record and Context Record as
  546. // parameters.
  547. //
  548. repeat:
  549. try {
  550. //
  551. // Compute length of exception record and new aligned stack
  552. // address.
  553. //
  554. ULONG Length = (STACK_SCRATCH_AREA + 15 +
  555. sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)) & ~(15);
  556. ULONGLONG UserStack = (ContextFrame.IntSp & (~15)) - Length;
  557. ULONGLONG ContextSlot = UserStack + STACK_SCRATCH_AREA;
  558. ULONGLONG ExceptSlot = ContextSlot + sizeof(CONTEXT);
  559. PULONGLONG PUserStack = (PULONGLONG) UserStack;
  560. //
  561. // When the exception gets dispatched to the user the
  562. // user BSP state will be loaded. Clear the preload
  563. // count in the RSE so it is not reloaded after if the
  564. // context is reused.
  565. //
  566. ContextFrame.RsRSC = ZERO_PRELOAD_SIZE(ContextFrame.RsRSC);
  567. //
  568. // Probe user stack area for writeability and then transfer the
  569. // exception record and conext record to the user stack area.
  570. //
  571. ProbeForWrite((PCHAR)UserStack, Length, sizeof(QUAD));
  572. RtlCopyMemory((PVOID)ContextSlot, &ContextFrame,
  573. sizeof(CONTEXT));
  574. RtlCopyMemory((PVOID)ExceptSlot, ExceptionRecord,
  575. sizeof(EXCEPTION_RECORD));
  576. //
  577. // Set address of exception record and context record in
  578. // the exception frame and the new stack pointer in the
  579. // current trap frame. Also set the initial frame size
  580. // to be zero.
  581. //
  582. // N.B. User exception dispatcher flushes the RSE
  583. // and updates the BSPStore field upon entry.
  584. //
  585. TrapFrame->RsPFS = SANITIZE_PFS(TrapFrame->StIFS, UserMode);
  586. TrapFrame->StIFS &= 0xffffffc000000000i64;
  587. TrapFrame->StIPSR &= ~((0x3i64 << PSR_RI) | (0x1i64 << PSR_IS));
  588. TrapFrame->IntSp = UserStack;
  589. TrapFrame->IntNats = 0;
  590. //
  591. // reset the user FPSR so that a recursive exception will not occur.
  592. //
  593. // TrapFrame->StFPSR = USER_FPSR_INITIAL;
  594. ExceptionFrame->IntS0 = ExceptSlot;
  595. ExceptionFrame->IntS1 = ContextSlot;
  596. ExceptionFrame->IntNats = 0;
  597. //
  598. // Set the address and the gp of the exception routine that
  599. // will call the exception dispatcher and then return to the
  600. // trap handler. The trap handler will restore the exception
  601. // and trap frame context and continue execution in the routine
  602. // that will call the exception dispatcher.
  603. //
  604. Plabel = (PPLABEL_DESCRIPTOR)KeUserExceptionDispatcher;
  605. TrapFrame->StIIP = Plabel->EntryPoint;
  606. TrapFrame->IntGp = Plabel->GlobalPointer;
  607. return;
  608. //
  609. // If an exception occurs, then copy the new exception information
  610. // to an exception record and handle the exception.
  611. //
  612. } except (KiCopyInformation(&ExceptionRecord1,
  613. (GetExceptionInformation())->ExceptionRecord)) {
  614. //
  615. // If the exception is a stack overflow, then attempt
  616. // to raise the stack overflow exception. Otherwise,
  617. // the user's stack is not accessible, or is misaligned,
  618. // and second chance processing is performed.
  619. //
  620. if (ExceptionRecord1.ExceptionCode == STATUS_STACK_OVERFLOW) {
  621. ExceptionRecord1.ExceptionAddress = ExceptionRecord->ExceptionAddress;
  622. RtlCopyMemory((PVOID)ExceptionRecord,
  623. &ExceptionRecord1, sizeof(EXCEPTION_RECORD));
  624. goto repeat;
  625. }
  626. }
  627. }
  628. //
  629. // This is the second chance to handle the exception.
  630. //
  631. UserApcPending = KeGetCurrentThread()->ApcState.UserApcPending;
  632. if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) {
  633. TrapFrame->StFPSR = SANITIZE_FSR(TrapFrame->StFPSR, UserMode);
  634. goto Handled2;
  635. } else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) {
  636. TrapFrame->StFPSR = SANITIZE_FSR(TrapFrame->StFPSR, UserMode);
  637. goto Handled2;
  638. } else {
  639. ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
  640. KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
  641. ExceptionRecord->ExceptionCode,
  642. (ULONG_PTR)ExceptionRecord->ExceptionAddress,
  643. ExceptionRecord->ExceptionInformation[0],
  644. ExceptionRecord->ExceptionInformation[1]);
  645. }
  646. }
  647. //
  648. // Move machine state from context frame to trap and exception frames and
  649. // then return to continue execution with the restored state.
  650. //
  651. Handled1:
  652. KeContextToKframes(TrapFrame, ExceptionFrame, &ContextFrame,
  653. ContextFrame.ContextFlags, PreviousMode);
  654. //
  655. // Exception was handled by the debugger or the associated subsystem
  656. // and state was modified, if necessary, using the get state and set
  657. // state capabilities. Therefore the context frame does not need to
  658. // be transfered to the trap and exception frames.
  659. //
  660. Handled2:
  661. return;
  662. }
  663. ULONG
  664. KiCopyInformation (
  665. IN OUT PEXCEPTION_RECORD ExceptionRecord1,
  666. IN PEXCEPTION_RECORD ExceptionRecord2
  667. )
  668. /*++
  669. Routine Description:
  670. This function is called from an exception filter to copy the exception
  671. information from one exception record to another when an exception occurs.
  672. Arguments:
  673. ExceptionRecord1 - Supplies a pointer to the destination exception record.
  674. ExceptionRecord2 - Supplies a pointer to the source exception record.
  675. Return Value:
  676. A value of EXCEPTION_EXECUTE_HANDLER is returned as the function value.
  677. --*/
  678. {
  679. //
  680. // Copy one exception record to another and return value that causes
  681. // an exception handler to be executed.
  682. //
  683. RtlCopyMemory((PVOID)ExceptionRecord1,
  684. (PVOID)ExceptionRecord2,
  685. sizeof(EXCEPTION_RECORD));
  686. return EXCEPTION_EXECUTE_HANDLER;
  687. }
  688. NTSTATUS
  689. KeRaiseUserException(
  690. IN NTSTATUS ExceptionCode
  691. )
  692. /*++
  693. Routine Description:
  694. This function causes an exception to be raised in the calling thread's user-mode
  695. context. It does this by editing the trap frame the kernel was entered with to
  696. point to trampoline code that raises the requested exception.
  697. Arguments:
  698. ExceptionCode - Supplies the status value to be used as the exception
  699. code for the exception that is to be raised.
  700. Return Value:
  701. The status value that should be returned by the caller.
  702. --*/
  703. {
  704. PKTRAP_FRAME TrapFrame;
  705. IA64_PFS Ifs;
  706. ASSERT(KeGetPreviousMode() == UserMode);
  707. TrapFrame = KeGetCurrentThread()->TrapFrame;
  708. if (TrapFrame == NULL) {
  709. return ExceptionCode;
  710. }
  711. try {
  712. PULONGLONG IntSp;
  713. IntSp = (PULONGLONG) TrapFrame->IntSp;
  714. ProbeForWriteSmallStructure (IntSp, sizeof (*IntSp)*2, sizeof(QUAD));
  715. *IntSp++ = TrapFrame->BrRp;
  716. *IntSp = TrapFrame->RsPFS;
  717. TrapFrame->StIIP = ((PPLABEL_DESCRIPTOR)KeRaiseUserExceptionDispatcher)->EntryPoint;
  718. } except (EXCEPTION_EXECUTE_HANDLER) {
  719. return (ExceptionCode);
  720. }
  721. //
  722. // Set IFS the size after the the system call.
  723. //
  724. Ifs.ull = TrapFrame->StIFS;
  725. Ifs.sb.pfs_sof = Ifs.sb.pfs_sof - Ifs.sb.pfs_sol;
  726. Ifs.sb.pfs_sol = 0;
  727. TrapFrame->StIFS = Ifs.ull;
  728. return(ExceptionCode);
  729. }