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.

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