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.

1451 lines
52 KiB

  1. // TITLE("Kernel Trap Handler")
  2. //++
  3. // Copyright (c) 1990 Microsoft Corporation
  4. // Copyright (c) 1992 Digital Equipment Corporation
  5. //
  6. // Module Name:
  7. //
  8. // trap.s
  9. //
  10. //
  11. // Abstract:
  12. //
  13. // Implements trap routines for ALPHA, these are the
  14. // entry points that the palcode calls for exception
  15. // processing.
  16. //
  17. //
  18. // Author:
  19. //
  20. // David N. Cutler (davec) 4-Apr-1990
  21. // Joe Notarangelo 06-Feb-1992
  22. //
  23. //
  24. // Environment:
  25. //
  26. // Kernel mode only.
  27. //
  28. //
  29. // Revision History:
  30. //
  31. // Nigel Haslock 05-May-1995 preserve fpcr across system calls
  32. //
  33. //--
  34. #include "ksalpha.h"
  35. //
  36. // Define exception handler frame
  37. //
  38. .struct 0
  39. HdRa: .space 8 // return address
  40. .space 3*8 // round to cache block
  41. HandlerFrameLength: // frame length
  42. SBTTL("General Exception Dispatch")
  43. //++
  44. //
  45. // Routine Description:
  46. //
  47. // The following code is never executed. Its purpose is to allow the
  48. // kernel debugger to walk call frames backwards through an exception
  49. // to support unwinding through exceptions for system services, and to
  50. // support get/set user context.
  51. //
  52. // N.B. The volatile registers must be saved in this prologue because
  53. // the compiler will occasionally generate code that uses volatile
  54. // registers to save the contents of nonvolatile registers when
  55. // a function only calls another function with a known register
  56. // signature (such as _OtsDivide).
  57. //
  58. //--
  59. NESTED_ENTRY(KiGeneralExceptionDispatch, TrapFrameLength, zero)
  60. .set noreorder
  61. stq sp, TrIntSp(sp) // save stack pointer
  62. stq ra, TrIntRa(sp) // save return address
  63. stq ra, TrFir(sp) // save return address
  64. stq fp, TrIntFp(sp) // save frame pointer
  65. stq gp, TrIntGp(sp) // save global pointer
  66. bis sp, sp, fp // set frame pointer
  67. .set reorder
  68. stq v0, TrIntV0(sp) // save integer register v0
  69. stq t0, TrIntT0(sp) // save integer registers t0 - t7
  70. stq t1, TrIntT1(sp) //
  71. stq t2, TrIntT2(sp) //
  72. stq t3, TrIntT3(sp) //
  73. stq t4, TrIntT4(sp) //
  74. stq t5, TrIntT5(sp) //
  75. stq t6, TrIntT6(sp) //
  76. stq t7, TrIntT7(sp) //
  77. stq a4, TrIntA4(sp) // save integer registers a4 - a5
  78. stq a5, TrIntA5(sp) //
  79. stq t8, TrIntT8(sp) // save integer registers t8 - t12
  80. stq t9, TrIntT9(sp) //
  81. stq t10, TrIntT10(sp) //
  82. stq t11, TrIntT11(sp) //
  83. stq t12, TrIntT12(sp) //
  84. .set noat
  85. stq AT, TrIntAt(sp) // save integer register AT
  86. .set at
  87. PROLOGUE_END
  88. //++
  89. //
  90. // Routine Description:
  91. //
  92. // PALcode dispatches to this kernel entry point when a "general"
  93. // exception occurs. These general exceptions are any exception
  94. // other than an interrupt, system service call or memory management
  95. // fault. The types of exceptions that will dispatch through this
  96. // routine will be: breakpoints, unaligned accesses, machine check
  97. // errors, illegal instruction exceptions, and arithmetic exceptions.
  98. // The purpose of this routine is to save the volatile state and
  99. // enter the common exception dispatch code.
  100. //
  101. // Arguments:
  102. //
  103. // fp - Supplies a pointer to the trap frame.
  104. // gp - Supplies a pointer to the system short data area.
  105. // sp - Supplies a pointer to the trap frame.
  106. // a0 = Supplies a pointer to the exception record.
  107. // a3 = Supplies the previous psr.
  108. //
  109. // Note: Control registers, ra, sp, fp, gp have already been saved
  110. // argument registers a0-a3 have been saved as well
  111. //
  112. //--
  113. ALTERNATE_ENTRY(KiGeneralException)
  114. bsr ra, KiGenerateTrapFrame // store volatile state
  115. br ra, KiExceptionDispatch // handle the exception
  116. .end KiGeneralExceptionDispatch
  117. SBTTL("Exception Dispatch")
  118. //++
  119. //
  120. // Routine Description:
  121. //
  122. // This routine begins the common code for raising an exception.
  123. // The routine saves the non-volatile state and dispatches to the
  124. // next level exception dispatcher.
  125. //
  126. // Arguments:
  127. //
  128. // fp - Supplies a pointer to the trap frame.
  129. // sp - Supplies a pointer to the trap frame.
  130. // a0 = Supplies a pointer to the exception record.
  131. // a3 = Supplies the previous psr.
  132. //
  133. // gp, ra - saved in trap frame
  134. // a0-a3 - saved in trap frame
  135. //
  136. // Return Value:
  137. //
  138. // None.
  139. //
  140. //--
  141. NESTED_ENTRY(KiExceptionDispatch, ExceptionFrameLength, zero )
  142. //
  143. // Build exception frame
  144. //
  145. lda sp, -ExceptionFrameLength(sp) // allocate exception frame
  146. stq ra, ExIntRa(sp) // save ra
  147. stq s0, ExIntS0(sp) // save integer registers s0 - s5
  148. stq s1, ExIntS1(sp) //
  149. stq s2, ExIntS2(sp) //
  150. stq s3, ExIntS3(sp) //
  151. stq s4, ExIntS4(sp) //
  152. stq s5, ExIntS5(sp) //
  153. stt f2, ExFltF2(sp) // save floating registers f2 - f9
  154. stt f3, ExFltF3(sp) //
  155. stt f4, ExFltF4(sp) //
  156. stt f5, ExFltF5(sp) //
  157. stt f6, ExFltF6(sp) //
  158. stt f7, ExFltF7(sp) //
  159. stt f8, ExFltF8(sp) //
  160. stt f9, ExFltF9(sp) //
  161. PROLOGUE_END
  162. ldil a4, TRUE // first chance to true
  163. and a3, PSR_MODE_MASK, a3 // set previous mode
  164. bis fp, zero, a2 // set pointer to trap frame
  165. bis sp, zero, a1 // set pointer to exception frame
  166. bsr ra, KiDispatchException // dispatch exception
  167. SBTTL("Exception Exit")
  168. //++
  169. //
  170. // Routine Description:
  171. //
  172. // This routine is called to exit from an exception.
  173. //
  174. // N.B. This transfer of control occurs from:
  175. //
  176. // 1. fall-through from above
  177. // 2. exit from continue system service
  178. // 3. exit from raise exception system service
  179. // 4. exit into user mode from thread startup
  180. //
  181. // Arguments:
  182. //
  183. // fp - Supplies a pointer to the trap frame.
  184. // sp - Supplies a pointer to the exception frame.
  185. //
  186. // Return Value:
  187. //
  188. // Does not return.
  189. //
  190. //--
  191. ALTERNATE_ENTRY(KiExceptionExit)
  192. ldq s0, ExIntS0(sp) // restore integer registers s0 - s5
  193. ldq s1, ExIntS1(sp) //
  194. ldq s2, ExIntS2(sp) //
  195. ldq s3, ExIntS3(sp) //
  196. ldq s4, ExIntS4(sp) //
  197. ldq s5, ExIntS5(sp) //
  198. ldl a0, TrPsr(fp) // get previous psr
  199. bsr ra, KiRestoreNonVolatileFloatState // restore nv float state
  200. ALTERNATE_ENTRY(KiAlternateExit)
  201. //
  202. // on entry:
  203. //
  204. // a0 = Supplies the previous psr.
  205. //
  206. // rfe will do the following for us:
  207. //
  208. // set sfw interrupt requests as per a1
  209. // restore previous irql and mode from previous psr
  210. // restore registers, a0-a3, fp, sp, ra, gp
  211. // return to saved exception address in the trap frame
  212. //
  213. // here, we need to restore the trap frame and determine
  214. // if we must request an APC interrupt
  215. //
  216. bis zero, zero, a1 // assume softwareinterrupt requested
  217. blbc a0, 30f // if lbc, previous mode kernel
  218. //
  219. // Check to determine if an apc interrupt should be generated.
  220. //
  221. GET_CURRENT_THREAD // get current thread address
  222. ldq_u t1, ThApcState+AsUserApcPending(v0) // get user APC pending
  223. extbl t1, (ThApcState+AsUserApcPending) % 8, t0 //
  224. ZeroByte(ThAlerted(v0)) // clear kernel mode alerted
  225. cmovne t0, APC_INTERRUPT, a1 // if pending set APC interrupt
  226. 30: bsr ra, KiRestoreTrapFrame // restore volatile state
  227. //
  228. // a0 = previous psr
  229. // a1 = sfw interrupt requests
  230. //
  231. RETURN_FROM_TRAP_OR_INTERRUPT // return from exception
  232. .end KiExceptionDispatch
  233. SBTTL("Memory Management Exception Dispatch")
  234. //++
  235. //
  236. // Routine Description:
  237. //
  238. // The following code is never executed. Its purpose is to allow the
  239. // kernel debugger to walk call frames backwards through an exception
  240. // to support unwinding through exceptions for system services, and to
  241. // support get/set user context.
  242. //
  243. // N.B. The volatile registers must be saved in this prologue because
  244. // the compiler will occasionally generate code that uses volatile
  245. // registers to save the contents of nonvolatile registers when
  246. // a function only calls another function with a known register
  247. // signature (such as _OtsMove).
  248. //
  249. //--
  250. NESTED_ENTRY(KiMemoryManagementDispatch, TrapFrameLength, zero)
  251. .set noreorder
  252. stq sp, TrIntSp(sp) // save stack pointer
  253. stq ra, TrIntRa(sp) // save return address
  254. stq ra, TrFir(sp) // save return address
  255. stq fp, TrIntFp(sp) // save frame pointer
  256. stq gp, TrIntGp(sp) // save global pointer
  257. bis sp, sp, fp // set frame pointer
  258. .set reorder
  259. stq v0, TrIntV0(sp) // save integer register v0
  260. stq t0, TrIntT0(sp) // save integer registers t0 - t7
  261. stq t1, TrIntT1(sp) //
  262. stq t2, TrIntT2(sp) //
  263. stq t3, TrIntT3(sp) //
  264. stq t4, TrIntT4(sp) //
  265. stq t5, TrIntT5(sp) //
  266. stq t6, TrIntT6(sp) //
  267. stq t7, TrIntT7(sp) //
  268. stq a4, TrIntA4(sp) // save integer registers a4 - a5
  269. stq a5, TrIntA5(sp) //
  270. stq t8, TrIntT8(sp) // save integer registers t8 - t12
  271. stq t9, TrIntT9(sp) //
  272. stq t10, TrIntT10(sp) //
  273. stq t11, TrIntT11(sp) //
  274. stq t12, TrIntT12(sp) //
  275. .set noat
  276. stq AT, TrIntAt(sp) // save integer register AT
  277. .set at
  278. PROLOGUE_END
  279. //++
  280. //
  281. // Routine Description:
  282. //
  283. // This routine is called from the PALcode when a translation not valid
  284. // fault or an access violation is encountered. This routine will
  285. // call MmAccessFault to attempt to resolve the fault. If the fault
  286. // cannot be resolved then the routine will dispatch to the exception
  287. // dispatcher so the exception can be raised.
  288. //
  289. // Arguments:
  290. //
  291. // fp - Supplies a pointer to the trap frame.
  292. // gp - Supplies a pointer to the system short data area.
  293. // sp - Supplies a pointer to the trap frame.
  294. // a0 = Supplies the load/store indicator, 1 = store, 0 = load.
  295. // a1 = Supplies the bad virtual address.
  296. // a2 = Supplies the previous mode.
  297. // a3 = Supplies the previous psr.
  298. //
  299. // gp, ra - saved in trap frame
  300. // a0-a3 - saved in trap frame
  301. //
  302. // Return Value:
  303. //
  304. // None.
  305. //
  306. //--
  307. ALTERNATE_ENTRY(KiMemoryManagementException)
  308. bsr ra, KiGenerateTrapFrame // store volatile state
  309. //
  310. // Save parameters in exception record and save previous psr.
  311. //
  312. STP a0, TrExceptionRecord + ErExceptionInformation(fp) // set load/store
  313. #if defined(_AXP64_)
  314. stq a1, TrExceptionRecord + ErExceptionInformation + 8(fp) // set bad va
  315. #else
  316. stl a1, TrExceptionRecord + ErExceptionInformation + 4(fp) // set bad va
  317. #endif
  318. stl a3, TrExceptionRecord + ErExceptionCode(fp) // save previous psr
  319. //
  320. // Call memory management to handle the access fault.
  321. //
  322. bis fp, zero, a3 // set address of trap frame
  323. bsr ra, MmAccessFault // resolve memory management fault
  324. ldl a3, TrExceptionRecord + ErExceptionCode(fp) // get previous psr
  325. //
  326. // Check if working set watch is enabled.
  327. //
  328. ldl t0, PsWatchEnabled // get working set watch enable flag
  329. bis v0, zero, a0 // save status of fault resolution
  330. blt v0, 40f // if ltz, resolution not successful
  331. beq t0, 35f // if eq. zero, watch not enabled
  332. LDP a1, TrExceptionRecord + ErExceptionAddress(fp) // set exception address
  333. #if defined(_AXP64_)
  334. ldq a2, TrExceptionRecord + ErExceptionInformation + 8(fp) // set bad address
  335. #else
  336. ldl a2, TrExceptionRecord + ErExceptionInformation + 4(fp) // set bad address
  337. #endif
  338. bsr ra, PsWatchWorkingSet // record working set information
  339. //
  340. // Check if debugger has any breakpoints that should be inserted.
  341. //
  342. 35: ldl t0, KdpOweBreakpoint // get owned breakpoint flag
  343. zap t0, 0xfe, t1 // mask off high bytes
  344. beq t1, 37f // if eq, no break points owed
  345. bsr ra, KdSetOwedBreakpoints // set owed break points
  346. //
  347. // Exit exception.
  348. //
  349. 37: ldl a0, TrPsr(fp) // get previous psr
  350. br zero, KiAlternateExit // exception handled
  351. //
  352. // Check to determine if the fault occured in the interlocked pop
  353. // entry slist code. There is a case where a fault may occur in this
  354. // code when the right set of circumstances occurs. The fault can be
  355. // ignored by simply skipping the faulting instruction.
  356. //
  357. 40: ldq t0, TrFir(fp) // get faulting instruction address
  358. lda t1, ExpInterlockedPopEntrySListFault // get address of pop code
  359. cmpeq t0, t1, t2 // check if address matches
  360. bne t2, 70f // if ne, fault address match
  361. //
  362. // Memory management failed to resolve fault.
  363. //
  364. // STATUS_IN_PAGE_ERROR | 0x10000000 is a special status that indicates a
  365. // page fault at Irql greater than APC_LEVEL.
  366. //
  367. // The following statuses can be raised:
  368. //
  369. // STATUS_ACCESS_VIOLATION
  370. // STATUS_GUARD_PAGE_VIOLATION
  371. // STATUS_STACK_OVERFLOW
  372. //
  373. // All other status will be set to:
  374. //
  375. // STATUS_IN_PAGE_ERROR
  376. //
  377. // dispatch exception via common code in KiDispatchException
  378. // Following must be done:
  379. // allocate exception frame via sp
  380. // complete data in ExceptionRecord
  381. // a0 points to ExceptionRecord
  382. // a1 points to ExceptionFrame
  383. // a2 points to TrapFrame
  384. // a3 = previous psr
  385. //
  386. // Exception record information has the following values
  387. // offset value
  388. // 0 read vs write indicator (set on entry)
  389. // 4 bad virtual address (set on entry)
  390. // 8 real status (only if status was not "recognized")
  391. //
  392. //
  393. // Check for special status that indicates a page fault at
  394. // Irql above APC_LEVEL.
  395. //
  396. ldil t1, STATUS_IN_PAGE_ERROR | 0x10000000 // get special status
  397. cmpeq v0, t1, t2 // check if status is special case
  398. bne t2, 60f // if ne, status is special case
  399. //
  400. // Check for expected status values.
  401. //
  402. lda a0, TrExceptionRecord(fp) // get exception record address
  403. bis zero, 2, t0 // set number of parameters
  404. ldil t1, STATUS_ACCESS_VIOLATION // get access violation code
  405. cmpeq v0, t1, t2 // check if access violation
  406. bne t2, 50f // if ne, access violation
  407. ldil t1, STATUS_GUARD_PAGE_VIOLATION // get guard page violation code
  408. cmpeq v0, t1, t2 // check if guard page violation
  409. bne t2, 50f // if ne, guard page violation
  410. ldil t1, STATUS_STACK_OVERFLOW // get stack overflow code
  411. cmpeq v0, t1, t2 // check if stack overflow
  412. bne t2, 50f // if ne, stack overflow
  413. //
  414. // Status is not recognized, save real status, bump the number
  415. // of exception parameters, and set status to STATUS_IN_PAGE_ERROR
  416. //
  417. #if defined(_AXP64_)
  418. stq v0, ErExceptionInformation + 16(a0) // save real status code
  419. #else
  420. stl v0, ErExceptionInformation + 8(a0) // save real status code
  421. #endif
  422. bis zero, 3, t0 // set number of params
  423. ldil v0, STATUS_IN_PAGE_ERROR // set status to in page error
  424. //
  425. // Fill in the remaining exception record parameters and attempt to
  426. // resolve the exception.
  427. //
  428. 50: ldl a3, ErExceptionCode(a0) // get previous psr
  429. stl v0, ErExceptionCode(a0) // save exception code
  430. stl zero, ErExceptionFlags(a0) // set exception flags
  431. STP zero, ErExceptionRecord(a0) // set associated record
  432. stl t0, ErNumberParameters(a0) // set number of parameters
  433. br ra, KiExceptionDispatch // dispatch exception
  434. //
  435. // Generate a bugcheck - A page fault has occured at an IRQL that is greater
  436. // than APC_LEVEL.
  437. //
  438. 60: ldil a0, IRQL_NOT_LESS_OR_EQUAL // set bugcheck code
  439. #if defined(_AXP64_)
  440. ldq a1, TrExceptionRecord + ErExceptionInformation + 8(fp) // set bad va
  441. #else
  442. ldl a1, TrExceptionRecord + ErExceptionInformation + 4(fp) // set bad va
  443. #endif
  444. ldl a2, TrExceptionRecord + ErExceptionCode(fp) // set previous IRQL
  445. srl a2, PSR_IRQL, a2 //
  446. LDP a3, TrExceptionRecord + ErExceptionInformation(fp) // set load/store indicator
  447. ldq a4, TrFir(fp) // set exception pc
  448. br ra, KeBugCheckEx // handle bugcheck
  449. //
  450. // The fault occured in the interlocked pop slist function and the faulting
  451. // instruction should be skipped.
  452. //
  453. 70: lda t0, ExpInterlockedPopEntrySListResume // get resumption address
  454. stq t0, TrFir(fp) // set continuation address
  455. ldl a0, TrPsr(fp) // get previous psr
  456. br zero, KiAlternateExit //
  457. .end KiMemoryManagementDispatch
  458. SBTTL("Invalid Access Allowed")
  459. //++
  460. //
  461. // BOOLEAN
  462. // KeInvalidAccessAllowed (
  463. // IN PVOID TrapFrame
  464. // )
  465. //
  466. // Routine Description:
  467. //
  468. // Mm will pass a pointer to a trap frame prior to issuing a bug check on
  469. // a pagefault. This routine lets Mm know if it is ok to bugcheck. The
  470. // specific case we must protect are the interlocked pop sequences which can
  471. // blindly access memory that may have been freed and/or reused prior to the
  472. // access. We don't want to bugcheck the system in these cases, so we check
  473. // the instruction pointer here.
  474. //
  475. // Arguments:
  476. //
  477. // TrapFrame (a0) - Supplies a trap frame pointer. NULL means return False.
  478. //
  479. // Return Value:
  480. //
  481. // True if the invalid access should be ignored.
  482. // False which will usually trigger a bugcheck.
  483. //
  484. //--
  485. LEAF_ENTRY(KeInvalidAccessAllowed)
  486. bis zero, 0, v0 // assume access not allowed
  487. beq a0, 10f // if eq, no trap frame specified
  488. ldq t0, TrFir(a0) // get faulting instruction address
  489. lda t1, ExpInterlockedPopEntrySListFault // get address of pop code
  490. cmpeq t0, t1, v0 // check if fault at pop code address
  491. 10: ret zero, (ra) // return
  492. .end KeInvalidAccessAllowed
  493. SBTTL("Primary Interrupt Dispatch")
  494. //++
  495. //
  496. // Routine Description:
  497. //
  498. // The following code is never executed. Its purpose is to allow the
  499. // kernel debugger to walk call frames backwards through an exception,
  500. // to support unwinding through exceptions for system services, and to
  501. // support get/set user context.
  502. //
  503. // N.B. The volatile registers must be saved in this prologue because
  504. // the compiler will occasionally generate code that uses volatile
  505. // registers to save the contents of nonvolatile registers when
  506. // a function only calls another function with a known register
  507. // signature (such as _OtsMove)
  508. //
  509. //--
  510. EXCEPTION_HANDLER(KiInterruptHandler)
  511. NESTED_ENTRY(KiInterruptDistribution, TrapFrameLength, zero);
  512. .set noreorder
  513. stq sp,TrIntSp(sp) // save stack pointer
  514. stq ra,TrIntRa(sp) // save return address
  515. stq ra,TrFir(sp) // save return address
  516. stq fp,TrIntFp(sp) // save frame pointer
  517. stq gp,TrIntGp(sp) // save general pointer
  518. bis sp, sp, fp // set frame pointer
  519. .set reorder
  520. stq v0, TrIntV0(sp) // save integer register v0
  521. stq t0, TrIntT0(sp) // save integer registers t0 - t7
  522. stq t1, TrIntT1(sp) //
  523. stq t2, TrIntT2(sp) //
  524. stq t3, TrIntT3(sp) //
  525. stq t4, TrIntT4(sp) //
  526. stq t5, TrIntT5(sp) //
  527. stq t6, TrIntT6(sp) //
  528. stq t7, TrIntT7(sp) //
  529. stq a4, TrIntA4(sp) // save integer registers a4 - a5
  530. stq a5, TrIntA5(sp) //
  531. stq t8, TrIntT8(sp) // save integer registers t8 - t12
  532. stq t9, TrIntT9(sp) //
  533. stq t10, TrIntT10(sp) //
  534. stq t11, TrIntT11(sp) //
  535. stq t12, TrIntT12(sp) //
  536. .set noat
  537. stq AT, TrIntAt(sp) // save integer register AT
  538. .set at
  539. PROLOGUE_END
  540. //++
  541. //
  542. // Routine Description:
  543. //
  544. // The PALcode dispatches to this routine when an enabled interrupt
  545. // is asserted.
  546. //
  547. // When this routine is entered, interrupts are disabled.
  548. //
  549. // The function of this routine is to determine the highest priority
  550. // pending interrupt, raise the IRQL to the level of the highest interrupt,
  551. // and then dispatch the interrupt to the proper service routine.
  552. //
  553. //
  554. // Arguments:
  555. //
  556. // a0 - Supplies the interrupt vector number.
  557. // a1 - Supplies the address of the pcr.
  558. // a3 - Supplies the previous psr.
  559. // fp - Supplies a pointer to the trap frame.
  560. // gp - Supplies a pointer to the system short data area.
  561. //
  562. // Return Value:
  563. //
  564. // None.
  565. //
  566. //--
  567. ALTERNATE_ENTRY(KiInterruptException)
  568. bsr ra, KiSaveVolatileIntegerState // save integer registers
  569. //
  570. // Count the number of interrupts.
  571. //
  572. GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
  573. ldl t0, PbInterruptCount(v0) // get current count of interrupts
  574. addl t0, 1, t1 // increment count
  575. stl t1, PbInterruptCount(v0) // save new interrupt count
  576. //
  577. // If interrupt vector > DISPATCH_LEVEL, indicate interrupt active in PRCB
  578. //
  579. cmpule a0, DISPATCH_LEVEL, t4 // compare vector to DISPATCH_LEVEL
  580. LDP t2, PbInterruptTrapFrame(v0)// get old interrupt trap frame
  581. cmovne t4, zero, t2 // zero trap frame if <= DISPATCH_LEVEL
  582. STP t2, TrTrapFrame(fp) // save old interrupt trap in new
  583. bne t4, 10f // vector <= DISPATCH_LEVEL, no interrupt trap
  584. STP fp, PbInterruptTrapFrame(v0)// set new interrupt trap frame
  585. 10: SPADDP a0, a1, a0 // convert index to offset + PCR base
  586. LDP a0, PcInterruptRoutine(a0) // get service routine address
  587. jsr ra, (a0) // call interrupt service routine
  588. //
  589. // Restore state and exit interrupt.
  590. //
  591. ldl a0, TrPsr(fp) // get previous psr
  592. #ifndef NT_UP
  593. DISABLE_INTERRUPTS // disable interrupts
  594. #endif
  595. GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
  596. LDP t0, TrTrapFrame(fp) // get old interrupt trap frame
  597. STP t0, PbInterruptTrapFrame(v0)// restore old interrupt trap frame
  598. #ifndef NT_UP
  599. ENABLE_INTERRUPTS // enable interrupts
  600. #endif
  601. bne t0, 50f // if ne, interrupt still active,
  602. //
  603. // If a dispatch interrupt is pending, lower IRQL to DISPATCH_LEVEL, and
  604. // directly call the dispatch interrupt handler.
  605. //
  606. ldl t2, PbSoftwareInterrupts(v0) // get pending SW interrupts
  607. beq t2, 50f // if eq, no pending SW interrupts
  608. stl zero, PbSoftwareInterrupts(v0) // clear pending SW interrupts
  609. and a0, PSR_IRQL_MASK, a1 // extract IRQL from PSR
  610. cmpult a1, DISPATCH_LEVEL << PSR_IRQL, t3 // check return IRQL
  611. beq t3, 70f // if not lt DISPATCH_LEVEL, can't bypass
  612. //
  613. // Update count of bypassed dispatch interrupts.
  614. //
  615. ldl t4, PbDpcBypassCount(v0) // get old bypass count
  616. addl t4, 1, t5 // increment
  617. stl t5, PbDpcBypassCount(v0) // store new bypass count
  618. ldil a0, DISPATCH_LEVEL // set new IRQL level
  619. SWAP_IRQL // lower IRQL to DISPATCH_LEVEL
  620. bsr ra, KiDispatchInterrupt // process dispatch interrupt
  621. 45: ldl a0, TrPsr(fp) // restore previous psr
  622. //
  623. // Check if an APC interrupt should be generated.
  624. //
  625. 50: bis zero, zero, a1 // clear sfw interrupt request
  626. blbc a0, 60f // if kernel no apc
  627. GET_CURRENT_THREAD // get current thread address
  628. ldq_u t1, ThApcState+AsUserApcPending(v0) // get user APC pending
  629. extbl t1, (ThApcState+AsUserApcPending) % 8, t0 //
  630. ZeroByte(ThAlerted(v0)) // clear kernel mode alerted
  631. cmovne t0, APC_INTERRUPT, a1 // if pending set APC interrupt
  632. 60: bsr ra, KiRestoreVolatileIntegerState // restore volatile state
  633. //
  634. // a0 = previous mode
  635. // a1 = sfw interrupt requests
  636. //
  637. RETURN_FROM_TRAP_OR_INTERRUPT // return from trap/interrupt
  638. //
  639. // Previous IRQL is >= DISPATCH_LEVEL, so a pending software interrupt cannot
  640. // be short-circuited. Request a software interrupt from the PAL.
  641. //
  642. 70: ldil a0, DISPATCH_LEVEL // set interrupt request level
  643. REQUEST_SOFTWARE_INTERRUPT // request interrupt from PAL
  644. br zero, 45b // rejoin common code
  645. .end KiInterruptDistribution
  646. //++
  647. //
  648. // EXCEPTION_DISPOSITION
  649. // KiInterruptHandler (
  650. // IN PEXCEPTION_RECORD ExceptionRecord,
  651. // IN ULONG EstablisherFrame,
  652. // IN OUT PCONTEXT ContextRecord,
  653. // IN OUT PDISPATCHER_CONTEXT DispatcherContext
  654. //
  655. // Routine Description:
  656. //
  657. // Control reaches here when an exception is not handled by an interrupt
  658. // service routine or an unwind is initiated in an interrupt service
  659. // routine that would result in an unwind through the interrupt dispatcher.
  660. // This is considered to be a fatal system error and bug check is called.
  661. //
  662. // Arguments:
  663. //
  664. // ExceptionRecord (a0) - Supplies a pointer to an exception record.
  665. //
  666. // EstablisherFrame (a1) - Supplies the frame pointer of the establisher
  667. // of this exception handler.
  668. //
  669. // N.B. This is not actually the frame pointer of the establisher of
  670. // this handler. It is actually the stack pointer of the caller
  671. // of the system service. Therefore, the establisher frame pointer
  672. // is not used and the address of the trap frame is determined by
  673. // examining the saved fp register in the context record.
  674. //
  675. // ContextRecord (a2) - Supplies a pointer to a context record.
  676. //
  677. // DispatcherContext (a3) - Supplies a pointer to the dispatcher context
  678. // record.
  679. //
  680. // Return Value:
  681. //
  682. // There is no return from this routine.
  683. //
  684. //--
  685. NESTED_ENTRY(KiInterruptHandler, HandlerFrameLength, zero)
  686. lda sp, -HandlerFrameLength(sp) // allocate stack frame
  687. stq ra, HdRa(sp) // save return address
  688. PROLOGUE_END
  689. ldl t0, ErExceptionFlags(a0) // get exception flags
  690. ldil a0, INTERRUPT_UNWIND_ATTEMPTED // assume unwind in progress
  691. and t0, EXCEPTION_UNWIND, t1 // check if unwind in progress
  692. bne t1, 10f // if ne, unwind in progress
  693. ldil a0, INTERRUPT_EXCEPTION_NOT_HANDLED // set bug check code
  694. 10: bsr ra, KeBugCheck // call bug check routine
  695. .end KiInterruptHandler
  696. SBTTL("System Service Dispatch")
  697. //++
  698. //
  699. // Routine Description:
  700. //
  701. // The following code is never executed. Its purpose is to allow the
  702. // kernel debugger to walk call frames backwards through an exception,
  703. // to support unwinding through exceptions for system services, and to
  704. // support get/set user context.
  705. //
  706. //--
  707. .struct 0
  708. ScCurrentThread: // current thread address
  709. .space 8 //
  710. ScServiceRoutine: // service routine address
  711. .space 8 //
  712. ScServiceDescriptor: // service descriptor address
  713. .space 8 //
  714. ScServiceNumber: // service number
  715. .space 4 //
  716. .space 4 // fill
  717. SyscallFrameLength: // frame length
  718. EXCEPTION_HANDLER(KiSystemServiceHandler)
  719. NESTED_ENTRY(KiSystemServiceDispatch, TrapFrameLength, zero);
  720. .set noreorder
  721. stq sp, TrIntSp - TrapFrameLength(sp) // save stack pointer
  722. lda sp, -TrapFrameLength(sp) // allocate stack frame
  723. stq ra,TrIntRa(sp) // save return address
  724. stq ra,TrFir(sp) // save return address
  725. stq fp,TrIntFp(sp) // save frame pointer
  726. stq gp,TrIntGp(sp) // save general pointer
  727. bis sp, sp, fp // set frame pointer
  728. .set reorder
  729. PROLOGUE_END
  730. //++
  731. //
  732. // Routine Description:
  733. //
  734. // Control reaches here when we have a system call call pal executed.
  735. // When this routine is entered, interrupts are disabled.
  736. //
  737. // The function of this routine is to call the specified system service.
  738. //
  739. //
  740. // Arguments:
  741. //
  742. // v0 - Supplies the system service code.
  743. // t0 - Previous processor mode
  744. // t1 - Current thread address
  745. // gp - Supplies a pointer to the system short data area.
  746. // fp - Supplies a pointer to the trap frame.
  747. //
  748. // Return Value:
  749. //
  750. // None.
  751. //
  752. //--
  753. ALTERNATE_ENTRY(KiSystemServiceException)
  754. START_REGION(KiSystemServiceDispatchStart)
  755. mf_fpcr f0 // save floating control register
  756. stt f0, TrFpcr(fp) //
  757. lda sp, -SyscallFrameLength(sp) // allocate stack frame
  758. STP t1, ScCurrentThread(sp) // save current thread address
  759. ldq_u t4, ThPreviousMode(t1) // get old previous thread mode
  760. LDP t5, ThTrapFrame(t1) // get current trap frame address
  761. extbl t4, ThPreviousMode % 8, t3 // extract previous mode
  762. stl t3, TrPreviousMode(fp) // save old previous mode of thread
  763. StoreByte(t0, ThPreviousMode(t1)) // set new previous mode in thread
  764. STP t5, TrTrapFrame(fp) // save current trap frame address
  765. //
  766. // If the specified system service number is not within range, then
  767. // attempt to convert the thread to a GUI thread and retry the service
  768. // dispatch.
  769. //
  770. // N.B. The argument registers a0-a3, the system service number in v0,
  771. // and the thread address in t1 must be preserved while attempting
  772. // to convert the thread to a GUI thread.
  773. //
  774. ALTERNATE_ENTRY(KiSystemServiceRepeat)
  775. STP fp, ThTrapFrame(t1) // save address of trap frame
  776. LDP t10, ThServiceTable(t1) // get service descriptor table address
  777. srl v0, SERVICE_TABLE_SHIFT, t2 // isolate service descriptor offset
  778. and t2, SERVICE_TABLE_MASK, t2 //
  779. ADDP t2, t10, t10 // compute service descriptor address
  780. ldl t3, SdLimit(t10) // get service number limit
  781. and v0, SERVICE_NUMBER_MASK, t7 // isolate service table offset
  782. cmpult t7, t3, t4 // check if valid service number
  783. beq t4, 80f // if eq, not valid service number
  784. LDP t4, SdBase(t10) // get service table address
  785. SPADDP t7, t4, t3 // compute address in service table
  786. LDP t5, 0(t3) // get address of service routine
  787. #if DBG
  788. LDP t6, SdCount(t10) // get service count table address
  789. beq t6, 5f // if eq, table not defined
  790. S4ADDP t7, t6, t6 // compute system service offset value
  791. ldl t11, 0(t6) // increment system service count
  792. addl t11, 1, t11 //
  793. stl t11, 0(t6) // store result
  794. #endif
  795. //
  796. // If the system service is a GUI service and the GDI user batch queue is
  797. // not empty, then call the appropriate service to flush the user batch.
  798. //
  799. 5: cmpeq t2, SERVICE_TABLE_TEST, t2 // check if GUI system service
  800. beq t2, 15f // if eq, not GUI system service
  801. LDP t3, ThTeb(t1) // get current thread TEB address
  802. ldl t4, TeGdiBatchCount(t3) // get number of batched GDI calls
  803. beq t4, 15f // if eq, no batched calls
  804. STP t5, ScServiceRoutine(sp) // save service routine address
  805. STP t10, ScServiceDescriptor(sp)// save service descriptor address
  806. stl t7, ScServiceNumber(sp) // save service table offset
  807. LDP t5, KeGdiFlushUserBatch // get address of flush routine
  808. stq a0, TrIntA0(fp) // save possible arguments
  809. stq a1, TrIntA1(fp) //
  810. stq a2, TrIntA2(fp) //
  811. stq a3, TrIntA3(fp) //
  812. stq a4, TrIntA4(fp) //
  813. stq a5, TrIntA5(fp) //
  814. jsr ra, (t5) // flush GDI user batch
  815. ldq a0, TrIntA0(fp) // restore possible arguments
  816. ldq a1, TrIntA1(fp) //
  817. ldq a2, TrIntA2(fp) //
  818. ldq a3, TrIntA3(fp) //
  819. ldq a4, TrIntA4(fp) //
  820. ldq a5, TrIntA5(fp) //
  821. LDP t5, ScServiceRoutine(sp) // restore service routine address
  822. LDP t10, ScServiceDescriptor(sp) // restore service descriptor address
  823. ldl t7, ScServiceNumber(sp) // restore service table offset
  824. //
  825. // Check if system service has any in memory arguments.
  826. //
  827. 15: blbc t5, 30f // if clear, no in memory arguments
  828. LDP t10, SdNumber(t10) // get argument table address
  829. ADDP t7, t10, t11 // compute address in argument table
  830. //
  831. // The following code captures arguments that were passed in memory on the
  832. // callers stack. This is necessary to ensure that the caller does not modify
  833. // the arguments after they have been probed and is also necessary in kernel
  834. // mode because a trap frame has been allocated on the stack.
  835. //
  836. // If the previous mode is user, then the user stack is probed for readability.
  837. //
  838. LDP t10, TrIntSp(fp) // get previous stack pointer
  839. beq t0, 10f // if eq, previous mode was kernel
  840. LDIP t2, MM_USER_PROBE_ADDRESS // get user probe address
  841. cmpult t10, t2, t4 // check if stack in user region
  842. cmoveq t4, t2, t10 // if eq, set invalid user stack address
  843. 10: ldq_u t4, 0(t11) // get number of memory arguments * 8
  844. extbl t4, t11, t9 //
  845. addl t9, 0x1f, t3 // round up to hexaword (32 bytes)
  846. bic t3, 0x1f, t3 // ensure hexaword alignment
  847. SUBP sp, t3, sp // allocate space on kernel stack
  848. bis sp, zero, t2 // set destination copy address
  849. ADDP t2, t3, t4 // compute destination end address
  850. START_REGION(KiSystemServiceStartAddress)
  851. //
  852. // This code is set up to load the cache block in the first
  853. // instruction and then perform computations that do not require
  854. // the cache while waiting for the data. In addition, the stores
  855. // are setup so they will be in order.
  856. //
  857. 20: ldq t6, 24(t10) // get argument from previous stack
  858. ADDP t10, 32, t10 // next hexaword on previous stack
  859. ADDP t2, 32, t2 // next hexaword on kernel stack
  860. cmpeq t2, t4, t11 // at end address?
  861. stq t6, -8(t2) // store argument on kernel stack
  862. ldq t7, -16(t10) // argument from previous stack
  863. ldq t8, -24(t10) // argument from previous stack
  864. ldq t9, -32(t10) // argument from previous stack
  865. stq t7, -16(t2) // save argument on kernel stack
  866. stq t8, -24(t2) // save argument on kernel stack
  867. stq t9, -32(t2) // save argument on kernel stack
  868. beq t11, 20b // if eq, get next block
  869. END_REGION(KiSystemServiceEndAddress)
  870. bic t5, 3, t5 // clear lower bits of service addr
  871. //
  872. // Call system service.
  873. //
  874. 30: jsr ra, (t5)
  875. //
  876. // Restore old trap frame address from the current trap frame and update
  877. // the number of system calls.
  878. //
  879. ALTERNATE_ENTRY(KiSystemServiceExit)
  880. bis v0, zero, t1 // save return status
  881. GET_PROCESSOR_CONTROL_BLOCK_BASE // get processor block address
  882. LDP t2, -SyscallFrameLength + ScCurrentThread(fp) // get current thread address
  883. LDP t3, TrTrapFrame(fp) // get old trap frame address
  884. ldl t10, PbSystemCalls(v0) // increment number of calls
  885. addl t10, 1, t10 //
  886. stl t10, PbSystemCalls(v0) // store result
  887. STP t3, ThTrapFrame(t2) // restore old trap frame address
  888. bis t1, zero, v0 // restore return status
  889. ldt f0, TrFpcr(fp) // restore floating control register
  890. mt_fpcr f0 //
  891. ldl a0, TrPsr(fp) // get previous processor status
  892. ldl t5, TrPreviousMode(fp) // get old previous mode
  893. StoreByte(t5, ThPreviousMode(t2)) // store previous mode in thread
  894. //
  895. // Check if an APC interrupt should be generated.
  896. //
  897. bis zero, zero, a1 // clear siftware interrupt request
  898. blbc a0, 70f // if kernel mode skip apc check
  899. ldq_u t1, ThApcState+AsUserApcPending(t2) // get user APC pending
  900. extbl t1, (ThApcState+AsUserApcPending) % 8, t0 //
  901. ZeroByte(ThAlerted(t2)) // clear kernel mode alerted
  902. cmovne t0, APC_INTERRUPT, a1 // if pending set APC interrupt
  903. //
  904. // a0 = previous psr
  905. // a1 = sfw interrupt requests
  906. //
  907. 70: RETURN_FROM_SYSTEM_CALL // return to caller
  908. //
  909. // The specified system service number is not within range. Attempt to
  910. // convert the thread to a GUI thread if specified system service is a
  911. // GUI service.
  912. //
  913. // N.B. The argument register a0-a5 and the system service number in v0
  914. // must be preserved if an attempt is made to convert the thread to
  915. // a GUI thread.
  916. //
  917. 80: cmpeq t2, SERVICE_TABLE_TEST, t2 // check if GUI system service
  918. beq t2, 55f // if eq, not GUI system service
  919. stl v0, ScServiceNumber(sp) // save system service number
  920. stq a0, TrIntA0(fp) // save argument registers a0-a5
  921. stq a1, TrIntA1(fp) //
  922. stq a2, TrIntA2(fp) //
  923. stq a3, TrIntA3(fp) //
  924. stq a4, TrIntA4(fp) //
  925. stq a5, TrIntA5(fp) //
  926. bsr ra, PsConvertToGuiThread // attempt to convert to GUI thread
  927. bis v0, zero, t0 // save completion status
  928. lda fp, SyscallFrameLength(sp) // restore trap frame address
  929. GET_CURRENT_THREAD // restore current thread address
  930. bis v0, zero, t1 // set current thread address
  931. ldl v0, ScServiceNumber(sp) // restore system service number
  932. ldq a0, TrIntA0(fp) // restore argument registers a0-a5
  933. ldq a1, TrIntA1(fp) //
  934. ldq a2, TrIntA2(fp) //
  935. ldq a3, TrIntA3(fp) //
  936. ldq a4, TrIntA4(fp) //
  937. ldq a5, TrIntA5(fp) //
  938. beq t0, KiSystemServiceRepeat // if eq, successful conversion
  939. //
  940. // The conversion to a Gui thread failed. The correct return value is encoded
  941. // in a byte table indexed by the service number that is at the end of the
  942. // service address table. The encoding is as follows:
  943. //
  944. // 0 - return 0.
  945. // -1 - return -1.
  946. // 1 - return status code.
  947. //
  948. lda t2, KeServiceDescriptorTableShadow // get descriptor base address
  949. ldl t3, SERVICE_TABLE_TEST + SdLimit(t2) // get service number limit
  950. LDP t4, SERVICE_TABLE_TEST + SdBase(t2) // get service table address
  951. SPADDP t3, t4, t2 // compute ending service table address
  952. and v0, SERVICE_NUMBER_MASK, t3 // isolate service number
  953. ADDP t2, t3, t3 // compute return value address
  954. ldq_u t2, 0(t3) // get packed status bytes
  955. extbl t2, t3, t2 // extract encoded status byte
  956. sll t2, 7 * 8, t2 // sign extend status byte value
  957. sra t2, 7 * 8, v0 //
  958. ble v0, KiSystemServiceExit // if le, return value set
  959. //
  960. // Return invalid system service status for invalid service code.
  961. //
  962. 55: ldil v0, STATUS_INVALID_SYSTEM_SERVICE // set completion status
  963. br zero, KiSystemServiceExit //
  964. END_REGION(KiSystemServiceDispatchEnd)
  965. .end KiSystemServiceDispatch
  966. //++
  967. //
  968. // EXCEPTION_DISPOSITION
  969. // KiSystemServiceHandler (
  970. // IN PEXCEPTION_RECORD ExceptionRecord,
  971. // IN ULONG EstablisherFrame,
  972. // IN OUT PCONTEXT ContextRecord,
  973. // IN OUT PDISPATCHER_CONTEXT DispatcherContext
  974. // )
  975. //
  976. // Routine Description:
  977. //
  978. // Control reaches here when a exception is raised in a system service
  979. // or the system service dispatcher, and for an unwind during a kernel
  980. // exception.
  981. //
  982. // If an unwind is being performed and the system service dispatcher is
  983. // the target of the unwind, then an exception occured while attempting
  984. // to copy the user's in-memory argument list. Control is transfered to
  985. // the system service exit by return a continue execution disposition
  986. // value.
  987. //
  988. // If an unwind is being performed and the previous mode is user, then
  989. // bug check is called to crash the system. It is not valid to unwind
  990. // out of a system service into user mode.
  991. //
  992. // If an unwind is being performed, the previous mode is kernel, the
  993. // system service dispatcher is not the target of the unwind, and the
  994. // thread does not own any mutexes, then the previous mode field from
  995. // the trap frame is restored to the thread object. Otherwise, bug
  996. // check is called to crash the system. It is invalid to unwind out of
  997. // a system service while owning a mutex.
  998. //
  999. // If an exception is being raised and the exception PC is within the
  1000. // range of the system service dispatcher in-memory argument copy code,
  1001. // then an unwind to the system service exit code is initiated.
  1002. //
  1003. // If an exception is being raised and the exception PC is not within
  1004. // the range of the system service dispatcher, and the previous mode is
  1005. // not user, then a continue searh disposition value is returned. Otherwise,
  1006. // a system service has failed to handle an exception and bug check is
  1007. // called. It is invalid for a system service not to handle all exceptions
  1008. // that can be raised in the service.
  1009. //
  1010. // Arguments:
  1011. //
  1012. // ExceptionRecord (a0) - Supplies a pointer to an exception record.
  1013. //
  1014. // EstablisherFrame (a1) - Supplies the frame pointer of the establisher
  1015. // of this exception handler.
  1016. //
  1017. // N.B. This is not actually the frame pointer of the establisher of
  1018. // this handler. It is actually the stack pointer of the caller
  1019. // of the system service. Therefore, the establisher frame pointer
  1020. // is not used and the address of the trap frame is determined by
  1021. // examining the saved fp register in the context record.
  1022. //
  1023. // ContextRecord (a2) - Supplies a pointer to a context record.
  1024. //
  1025. // DispatcherContext (a3) - Supplies a pointer to the dispatcher context
  1026. // record.
  1027. //
  1028. // Return Value:
  1029. //
  1030. // If bug check is called, there is no return from this routine and the
  1031. // system is crashed. If an exception occured while attempting to copy
  1032. // the user in-memory argument list, then there is no return from this
  1033. // routine, and unwind is called. Otherwise, ExceptionContinueSearch is
  1034. // returned as the function value.
  1035. //
  1036. //--
  1037. LEAF_ENTRY(KiSystemServiceHandler)
  1038. lda sp, -HandlerFrameLength(sp) // allocate stack frame
  1039. stq ra, HdRa(sp) // save return address
  1040. PROLOGUE_END
  1041. ldl t0, ErExceptionFlags(a0) // get exception flags
  1042. and t0, EXCEPTION_UNWIND, t1 // check if unwind in progress
  1043. bne t1, 40f // if ne, unwind in progress
  1044. //
  1045. // An exception is in progress.
  1046. //
  1047. // If the exception PC is within the in-memory argument copy code of the
  1048. // system service dispatcher, then call unwind to transfer control to the
  1049. // system service exit code. Otherwise, check if the previous mode is user
  1050. // or kernel mode.
  1051. //
  1052. //
  1053. LDP t0, ErExceptionAddress(a0) // get address of exception
  1054. lda t1, KiSystemServiceStartAddress // address of system service
  1055. cmpult t0, t1, t3 // check if before start range
  1056. lda t2, KiSystemServiceEndAddress // end address
  1057. bne t3, 10f // if ne, before start of range
  1058. cmpult t0, t2, t3 // check if before end of range
  1059. bne t3, 30f // if ne, before end of range
  1060. //
  1061. // If the previous mode was kernel mode, then a continue search disposition
  1062. // value is returned. Otherwise, the exception was raised in a system service
  1063. // and was not handled by that service. Call bug check to crash the system.
  1064. //
  1065. 10: GET_CURRENT_THREAD // get current thread address
  1066. ldq_u t4, ThPreviousMode(v0) // get previous mode from thread
  1067. extbl t4, ThPreviousMode % 8, t1 //
  1068. bne t1, 20f // if ne, previous mode was user
  1069. //
  1070. // Previous mode is kernel mode.
  1071. //
  1072. ldil v0, ExceptionContinueSearch // set disposition code
  1073. lda sp, HandlerFrameLength(sp) // deallocate stack frame
  1074. jmp zero, (ra) // return
  1075. //
  1076. // Previous mode is user mode. Call bug check to crash the system.
  1077. //
  1078. 20: bis a3, zero, a4 // set dispatcher context address
  1079. bis a2, zero, a3 // set context record address
  1080. bis a1, zero, a2 // set system service frame address
  1081. bis a0, zero, a1 // set exception record address
  1082. ldil a0, SYSTEM_SERVICE_EXCEPTION // set bug check code
  1083. bsr ra, KeBugCheckEx // call bug check routine
  1084. //
  1085. // The exception was raised in the system service dispatcher. Unwind to the
  1086. // the system service exit code.
  1087. //
  1088. 30: ldl a3, ErExceptionCode(a0) // set return value
  1089. bis zero, zero, a2 // set exception record address
  1090. bis a1, zero, a0 // set target frame address
  1091. lda a1, KiSystemServiceExit // set target PC address
  1092. bsr ra, RtlUnwind // unwind to system service exit
  1093. //
  1094. // An unwind is in progress.
  1095. //
  1096. // If a target unwind is being performed, then continue execution is returned
  1097. // to transfer control to the system service exit code. Otherwise, restore the
  1098. // previous mode if the previous mode is not user and there are no mutexes owned
  1099. // by the current thread.
  1100. //
  1101. 40: and t0, EXCEPTION_TARGET_UNWIND, t1 // check if target unwnd in progres
  1102. bne t1, 60f // if ne, target unwind in progress
  1103. //
  1104. // An unwind is being performed through the system service dispatcher. If the
  1105. // previous mode is not kernel or the current thread owns one or more mutexes,
  1106. // then call bug check and crash the system. Otherwise, restore the previous
  1107. // mode in the current thread object.
  1108. //
  1109. GET_CURRENT_THREAD // get current thread address
  1110. ldl t1, CxIntFp(a2) // get address of trap frame
  1111. ldq_u t4, ThPreviousMode(v0) // get previous mode from thread
  1112. extbl t4, ThPreviousMode % 8, t3 //
  1113. ldl t4,TrPreviousMode(t1) // get previous mode from trap frame
  1114. bne t3, 50f // if ne, previous mode was user
  1115. //
  1116. // Restore previous from trap frame to thread object and continue the unwind
  1117. // operation.
  1118. //
  1119. StoreByte(t4, ThPreviousMode(v0)) // restore previous mode from trap frame
  1120. ldil v0, ExceptionContinueSearch // set disposition value
  1121. lda sp, HandlerFrameLength(sp) // deallocate stack frame
  1122. jmp zero, (ra) // return
  1123. //
  1124. // An attempt is being made to unwind into user mode. Call bug check to crash
  1125. // the system.
  1126. //
  1127. 50: ldil a0, SYSTEM_UNWIND_PREVIOUS_USER // set bug check code
  1128. bsr ra, KeBugCheck // call bug check
  1129. //
  1130. // A target unwind is being performed. Return a continue search disposition
  1131. // value.
  1132. //
  1133. 60: ldil v0, ExceptionContinueSearch // set disposition value
  1134. lda sp, HandlerFrameLength(sp) // deallocate stack frame
  1135. jmp zero, (ra) // return
  1136. .end KiSystemServiceHandler
  1137. //++
  1138. //
  1139. // Routine Description:
  1140. //
  1141. // The following code is never executed. Its purpose is to allow the
  1142. // kernel debugger to walk call frames backwards through an exception
  1143. // to support unwinding through exceptions for system services, and to
  1144. // support get/set user context.
  1145. //--
  1146. NESTED_ENTRY(KiPanicDispatch, TrapFrameLength, zero)
  1147. .set noreorder
  1148. stq sp, TrIntSp(sp) // save stack pointer
  1149. stq ra, TrIntRa(sp) // save return address
  1150. stq ra, TrFir(sp) // save return address
  1151. stq fp, TrIntFp(sp) // save frame pointer
  1152. stq gp, TrIntGp(sp) // save global pointer
  1153. bis sp, sp, fp // set frame pointer
  1154. .set reorder
  1155. PROLOGUE_END
  1156. //++
  1157. //
  1158. // Routine Description:
  1159. //
  1160. // PALcode dispatches to this entry point when a panic situation
  1161. // is detected while in PAL mode. The panic situation may be that
  1162. // the kernel stack is about to overflow/underflow or there may be
  1163. // a condition that was not expected to occur while in PAL mode
  1164. // (eg. arithmetic exception while in PAL). This entry point is
  1165. // here to help us debug the condition.
  1166. //
  1167. // Arguments:
  1168. //
  1169. // fp - points to trap frame
  1170. // sp - points to exception frame
  1171. // a0 = Bug check code
  1172. // a1 = Exception address
  1173. // a2 = Bugcheck parameter
  1174. // a3 = Bugcheck parameter
  1175. //
  1176. // gp, ra - saved in trap frame
  1177. // a0-a3 - saved in trap frame
  1178. //
  1179. // Return Value:
  1180. //
  1181. // None.
  1182. //
  1183. //--
  1184. ALTERNATE_ENTRY(KiPanicException)
  1185. stq ra, TrIntRa(fp) // PAL is supposed to do this, but it doesn't!
  1186. //
  1187. // Save state, volatile float and integer state via KiGenerateTrapFrame
  1188. //
  1189. bsr ra, KiGenerateTrapFrame // save volatile state
  1190. //
  1191. // Dispatch to KeBugCheckEx, does not return
  1192. //
  1193. br ra, KeBugCheckEx // do the bugcheck
  1194. .end KiPanicDispatch
  1195. //++
  1196. //
  1197. // VOID
  1198. // KiBreakinBreakpoint(
  1199. // VOID
  1200. // );
  1201. //
  1202. // Routine Description:
  1203. //
  1204. // This routine issues a breakin breakpoint.
  1205. //
  1206. // Arguments:
  1207. //
  1208. // None.
  1209. //
  1210. // Return Value:
  1211. //
  1212. // None.
  1213. //
  1214. //--
  1215. LEAF_ENTRY( KiBreakinBreakpoint )
  1216. BREAK_BREAKIN // execute breakin breakpoint
  1217. ret zero, (ra) // return to caller
  1218. .end KiBreakinBreakpoint