Windows NT 4.0 source code leak
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.

524 lines
18 KiB

4 years ago
  1. // TITLE("Trampoline Code For User Mode APC and Exception Dispatching")
  2. //++
  3. //
  4. // Copyright (c) 1990 Microsoft Corporation
  5. // Copyright (c) 1992 Digital Equipment Corporation
  6. //
  7. // Module Name:
  8. //
  9. // trampoln.s
  10. //
  11. // Abstract:
  12. //
  13. // This module implements the trampoline code necessary to dispatch user
  14. // mode APCs and exceptions.
  15. //
  16. // Author:
  17. //
  18. // David N. Cutler (davec) 3-Apr-1990
  19. //
  20. // Environment:
  21. //
  22. // User mode only.
  23. //
  24. // Revision History:
  25. //
  26. // Thomas Van Baak (tvb) 11-May-1992
  27. //
  28. // Adapted for Alpha AXP.
  29. //
  30. //--
  31. #include "ksalpha.h"
  32. //
  33. // Define length of exception dispatcher stack frame.
  34. //
  35. #define ExceptionDispatcherFrameLength (ExceptionRecordLength + ContextFrameLength)
  36. SBTTL("User APC Dispatcher")
  37. //++
  38. //
  39. // The following code is never executed. Its purpose is to support unwinding
  40. // through the call to the APC dispatcher.
  41. //
  42. //--
  43. //
  44. // N.B. This function specifies its own private exception handler.
  45. //
  46. EXCEPTION_HANDLER(KiUserApcHandler)
  47. NESTED_ENTRY(KiUserApcDispatch, ContextFrameLength, zero);
  48. .set noreorder
  49. .set noat
  50. stq sp, CxIntSp(sp) // save stack pointer
  51. stq ra, CxIntRa(sp) // save return address
  52. stq ra, CxFir(sp) // set continuation address
  53. stq fp, CxIntFp(sp) // save integer register fp
  54. stq gp, CxIntGp(sp) // save integer register gp
  55. stq s0, CxIntS0(sp) // save integer registers s0 - s5
  56. stq s1, CxIntS1(sp) //
  57. stq s2, CxIntS2(sp) //
  58. stq s3, CxIntS3(sp) //
  59. stq s4, CxIntS4(sp) //
  60. stq s5, CxIntS5(sp) //
  61. stt f2, CxFltF2(sp) // save floating registers f2 - f9
  62. stt f3, CxFltF3(sp) //
  63. stt f4, CxFltF4(sp) //
  64. stt f5, CxFltF5(sp) //
  65. stt f6, CxFltF6(sp) //
  66. stt f7, CxFltF7(sp) //
  67. stt f8, CxFltF8(sp) //
  68. stt f9, CxFltF9(sp) //
  69. mov sp, fp // set frame pointer
  70. .set at
  71. .set reorder
  72. PROLOGUE_END
  73. //++
  74. //
  75. // VOID
  76. // KiUserApcDispatcher (
  77. // IN PVOID NormalContext,
  78. // IN PVOID SystemArgument1,
  79. // IN PVOID SystemArgument2,
  80. // IN PKNORMAL_ROUTINE NormalRoutine
  81. // )
  82. //
  83. // Routine Description:
  84. //
  85. // This routine is entered on return from kernel mode to deliver an APC
  86. // in user mode. The context frame for this routine was built when the
  87. // APC interrupt was processed and contains the entire machine state of
  88. // the current thread. The specified APC routine is called and then the
  89. // machine state is restored and execution is continued.
  90. //
  91. // Arguments:
  92. //
  93. // a0 - Supplies the normal context parameter that was specified when the
  94. // APC was initialized.
  95. //
  96. // a1 - Supplies the first argument that was provided by the executive when
  97. // the APC was queued.
  98. //
  99. // a2 - Supplies the second argument that was provided by the executive
  100. // when the APC was queued.
  101. //
  102. // a3 - Supplies the address of the function that is to be called.
  103. //
  104. // N.B. Register sp supplies a pointer to a context frame.
  105. //
  106. // N.B. Register fp supplies the same value as sp and is used as a frame
  107. // pointer.
  108. //
  109. // Return Value:
  110. //
  111. // None.
  112. //
  113. //--
  114. //
  115. // N.B. This function is not called in the typical way. Instead of a normal
  116. // subroutine call to the nested entry point above, the alternate entry point
  117. // address below is stuffed into the Fir address of the trap frame. Thus when
  118. // the kernel returns from the trap, the following code is executed directly.
  119. //
  120. ALTERNATE_ENTRY(KiUserApcDispatcher)
  121. jsr ra, (a3) // call specified APC routine
  122. mov fp, a0 // set address of context frame
  123. ldil a1, TRUE // set test alert argument true
  124. bsr ra, ZwContinue // execute system service to continue
  125. mov v0, s0 // save status value
  126. //
  127. // Unsuccessful completion after attempting to continue execution. Use the
  128. // return status as the exception code, set noncontinuable exception and
  129. // attempt to raise another exception. Note there is no return from raise
  130. // status.
  131. //
  132. 10: mov s0, a0 // set status value
  133. bsr ra, RtlRaiseStatus // raise exception
  134. br zero, 10b // loop on return
  135. .end KiUserApcDispatch
  136. SBTTL("User APC Exception Handler")
  137. //++
  138. //
  139. // EXCEPTION_DISPOSITION
  140. // KiUserApcHandler (
  141. // IN PEXCEPTION_RECORD ExceptionRecord,
  142. // IN ULONG EstablisherFrame,
  143. // IN OUT PCONTEXT ContextRecord,
  144. // IN OUT PDISPATCHER_CONTEXT DispatcherContext
  145. //
  146. // Routine Description:
  147. //
  148. // This function is called when an exception occurs in an APC routine
  149. // or one of its dynamic descendents, or when an unwind through the
  150. // APC dispatcher is in progress. If an unwind is in progress, then test
  151. // alert is called to ensure that all currently queued APCs are executed.
  152. //
  153. // Arguments:
  154. //
  155. // ExceptionRecord (a0) - Supplies a pointer to an exception record.
  156. //
  157. // EstablisherFrame (a1) - Supplies the frame pointer of the establisher
  158. // of this exception handler.
  159. //
  160. // ContextRecord (a2) - Supplies a pointer to a context record.
  161. //
  162. // DispatcherContext (a3) - Supplies a pointer to the dispatcher context
  163. // record.
  164. //
  165. // Return Value:
  166. //
  167. // ExceptionContinueSearch is returned as the function value.
  168. //
  169. //--
  170. .struct 0
  171. HdRa: .space 8 // saved return address
  172. .space 1 * 8 // required for 16-byte stack alignment
  173. HandlerFrameLength: // length of handler frame
  174. NESTED_ENTRY(KiUserApcHandler, HandlerFrameLength, zero)
  175. lda sp, -HandlerFrameLength(sp) // allocate stack frame
  176. stq ra, HdRa(sp) // save return address
  177. PROLOGUE_END
  178. //
  179. // The following code is equivalent to:
  180. //
  181. // EXCEPTION_DISPOSITION
  182. // KiUserApcHandler(IN PEXCEPTION_RECORD ExceptionRecord)
  183. // {
  184. // if (IS_UNWINDING(ExceptionRecord->ExceptionFlags)) {
  185. // NtTestAlert();
  186. // }
  187. // return ExceptionContinueSearch
  188. // }
  189. //
  190. ldl t0, ErExceptionFlags(a0) // get exception flags
  191. and t0, EXCEPTION_UNWIND, t0 // check if unwind in progress
  192. beq t0, 10f // if eq, no unwind in progress
  193. bsr ra, ZwTestAlert // test for alert pending
  194. 10: ldil v0, ExceptionContinueSearch // set disposition value
  195. ldq ra, HdRa(sp) // restore return address
  196. lda sp, HandlerFrameLength(sp) // deallocate stack frame
  197. ret zero, (ra) // return
  198. .end KiUserApcHandler
  199. SBTTL("User Callback Dispatcher")
  200. //++
  201. //
  202. // The following code is never executed. Its purpose is to support unwinding
  203. // through the call to the exception dispatcher.
  204. //
  205. //--
  206. NESTED_ENTRY(KiUserCallbackDispatch, ContextFrameLength, zero);
  207. .set noreorder
  208. stq sp, CkSp(sp)
  209. stq ra, CkRa(sp)
  210. .set reorder
  211. PROLOGUE_END
  212. //++
  213. //
  214. // VOID
  215. // KiUserCallbackDispatcher (
  216. // VOID
  217. // )
  218. //
  219. // Routine Description:
  220. //
  221. // This routine is entered on a callout from kernel mode to execute a
  222. // user mode callback function. All arguments for this function have
  223. // been placed on the stack.
  224. //
  225. // Arguments:
  226. //
  227. // (sp + 16) - Supplies a value of zero for alignment.
  228. //
  229. // (sp + 24) - Supplies the API number of the callback function that is
  230. // executed.
  231. //
  232. // (sp + 32) - Supplies a pointer to the input buffer.
  233. //
  234. // (sp + 40) - Supplies the input buffer length.
  235. //
  236. // Return Value:
  237. //
  238. // This function returns to kernel mode.
  239. //
  240. //--
  241. ALTERNATE_ENTRY(KiUserCallbackDispatcher)
  242. ldl a0, CkBuffer(sp) // get input buffer address
  243. ldl a1, CkLength(sp) // get input buffer length
  244. ldl t0, CkApiNumber(sp) // get API number
  245. GET_THREAD_ENVIRONMENT_BLOCK // get TEB in v0
  246. ldl t5, TePeb(v0) // get PEB in t5
  247. ldl t2, PeKernelCallbackTable(t5) // get address of callback table
  248. s4addl t0, t2, t3 // get address of callback
  249. ldl t4, 0(t3) // get callback pointer
  250. jsr ra, (t4) // call specified function
  251. //
  252. // If a return from the callback function occurs, then the output buffer
  253. // address and length are returned as NULL.
  254. //
  255. bis zero,zero,a0 // set zero buffer address
  256. bis zero,zero,a1 // set zero buffer length
  257. bis v0, zero, a2 // set completion status
  258. bsr ra, ZwCallbackReturn // return to kernel mode
  259. //
  260. // Unsuccessful completion after attempting to return to kernel mode. Use
  261. // the return status as the exception code, set noncontinuable exception and
  262. // attempt to raise another exception. Note there is no return from raise
  263. // status.
  264. //
  265. bis v0, zero, s0 // save status value
  266. 10: bis s0, zero, a0 // set status value
  267. bsr ra, RtlRaiseStatus // raise exception
  268. br zero, 10b // loop on return
  269. .end KiUserCallbackDispatch
  270. SBTTL("User Exception Dispatcher")
  271. //++
  272. //
  273. // The following code is never executed. Its purpose is to support unwinding
  274. // through the call to the exception dispatcher.
  275. //
  276. // When reverse executed, this prologue will restore all integer registers,
  277. // rather than just the non-volatile registers. This is necessary for proper
  278. // unwinding through the call to the exception dispatcher when non-standard
  279. // calls have been used in frames at or above the exception frame. Non-leaf
  280. // functions using a non-standard call are allowed to save the return address
  281. // register in another integer register instead of on the stack.
  282. //
  283. //--
  284. NESTED_ENTRY(KiUserExceptionDispatch, ExceptionDispatcherFrameLength, zero);
  285. .set noreorder
  286. .set noat
  287. stq sp, CxIntSp(sp) // save stack pointer
  288. stq ra, CxIntRa(sp) // save return address
  289. stq ra, CxFir(sp) // set continuation address
  290. stq v0, CxIntV0(sp) // save integer register v0
  291. stq t0, CxIntT0(sp) // save integer registers t0 - t6
  292. stq t1, CxIntT1(sp) //
  293. stq t2, CxIntT2(sp) //
  294. stq t3, CxIntT3(sp) //
  295. stq t4, CxIntT4(sp) //
  296. stq t5, CxIntT5(sp) //
  297. stq t6, CxIntT6(sp) //
  298. stq t7, CxIntT7(sp) //
  299. stq s0, CxIntS0(sp) // save integer registers s0 - s5
  300. stq s1, CxIntS1(sp) //
  301. stq s2, CxIntS2(sp) //
  302. stq s3, CxIntS3(sp) //
  303. stq s4, CxIntS4(sp) //
  304. stq s5, CxIntS5(sp) //
  305. stq fp, CxIntFp(sp) // save integer register fp
  306. stq a0, CxIntA0(sp) // save integer registers a0 - a5
  307. stq a1, CxIntA1(sp) //
  308. stq a2, CxIntA2(sp) //
  309. stq a3, CxIntA3(sp) //
  310. stq a4, CxIntA4(sp) //
  311. stq a5, CxIntA5(sp) //
  312. stq t8, CxIntT8(sp) // save integer registers t8 - t11
  313. stq t9, CxIntT9(sp) //
  314. stq t10, CxIntT10(sp) //
  315. stq t11, CxIntT11(sp) //
  316. stq t12, CxIntT12(sp) // save integer register t12
  317. stq AT, CxIntAt(sp) // save integer register AT
  318. stq gp, CxIntGp(sp) // save integer register gp
  319. stt f2, CxFltF2(sp) // save floating registers f2 - f9
  320. stt f3, CxFltF3(sp) //
  321. stt f4, CxFltF4(sp) //
  322. stt f5, CxFltF5(sp) //
  323. stt f6, CxFltF6(sp) //
  324. stt f7, CxFltF7(sp) //
  325. stt f8, CxFltF8(sp) //
  326. stt f9, CxFltF9(sp) //
  327. mov sp, fp // set frame pointer
  328. .set at
  329. .set reorder
  330. PROLOGUE_END
  331. //++
  332. //
  333. // VOID
  334. // KiUserExceptionDispatcher (
  335. // IN PEXCEPTION_RECORD ExceptionRecord,
  336. // IN PCONTEXT ContextRecord
  337. // )
  338. //
  339. // Routine Description:
  340. //
  341. // This routine is entered on return from kernel mode to dispatch a user
  342. // mode exception. If a frame based handler handles the exception, then
  343. // the execution is continued. Otherwise last chance processing is performed.
  344. //
  345. // Arguments:
  346. //
  347. // s0 - Supplies a pointer to an exception record.
  348. //
  349. // s1 - Supplies a pointer to a context frame.
  350. //
  351. // fp - Supplies the same value as sp and is used as a frame pointer.
  352. //
  353. // Return Value:
  354. //
  355. // None.
  356. //
  357. //--
  358. //
  359. // N.B. This function is not called in the typical way. Instead of a normal
  360. // subroutine call to the nested entry point above, the alternate entry point
  361. // address below is stuffed into the Fir address of the trap frame. Thus when
  362. // the kernel returns from the trap, the following code is executed directly.
  363. //
  364. ALTERNATE_ENTRY(KiUserExceptionDispatcher)
  365. mov s0, a0 // set address of exception record
  366. mov s1, a1 // set address of context frame
  367. bsr ra, RtlDispatchException // attempt to dispatch the exception
  368. //
  369. // If the return status is TRUE, then the exception was handled and execution
  370. // should be continued with the NtContinue service in case the context was
  371. // changed. If the return status is FALSE, then the exception was not handled
  372. // and NtRaiseException is called to perform last chance exception processing.
  373. //
  374. beq v0, 10f // if eq [false], perform last chance processing
  375. //
  376. // Continue execution.
  377. //
  378. mov s1, a0 // set address of context frame
  379. ldil a1, FALSE // set test alert argument false
  380. bsr ra, ZwContinue // execute system service to continue
  381. br zero, 20f // join common code
  382. //
  383. // Last chance processing.
  384. //
  385. 10: mov s0, a0 // set address of exception record
  386. mov s1, a1 // set address of context frame
  387. ldil a2, FALSE // set first chance argument false
  388. bsr ra, ZwRaiseException // perform last chance processing
  389. //
  390. // Common code for unsuccessful completion of the continue or last chance
  391. // service. Use the return status (which is now in v0) as the exception code,
  392. // set noncontinuable exception and attempt to raise another exception. Note
  393. // the stack grows and eventually this loop will end.
  394. //
  395. 20: lda sp, -ExceptionRecordLength(sp) // allocate exception record
  396. mov sp, a0 // get address of actual record
  397. stl v0, ErExceptionCode(a0) // set exception code
  398. ldil t0, EXCEPTION_NONCONTINUABLE // set noncontinuable flag
  399. stl t0, ErExceptionFlags(a0) // store exception flags
  400. stl s0, ErExceptionRecord(a0) // set associated exception record
  401. stl zero, ErNumberParameters(a0) // set number of parameters
  402. bsr ra, RtlRaiseException // raise exception
  403. br zero, 20b // loop on error
  404. .end KiUserExceptionDispatch
  405. //++
  406. //
  407. // NTSTATUS
  408. // KiRaiseUserExceptionDispatcher (
  409. // IN NTSTATUS ExceptionCode
  410. // )
  411. //
  412. // Routine Description:
  413. //
  414. // This routine is entered on return from kernel mode to raise a user
  415. // mode exception.
  416. //
  417. // Arguments:
  418. //
  419. // v0 - Supplies the status code to be raised.
  420. //
  421. // Return Value:
  422. //
  423. // ExceptionCode
  424. //
  425. //--
  426. //
  427. // N.B. This function is not called in the typical way. Instead of a normal
  428. // subroutine call to the nested entry point above, the alternate entry point
  429. // address below is stuffed into the Fir address of the trap frame. Thus when
  430. // the kernel returns from the trap, the following code is executed directly.
  431. //
  432. .struct 0
  433. RaiseRa: .space 8 // saved return address
  434. RaiseV0: .space 8 // saved S0
  435. RaiseExr: .space ExceptionRecordLength // exception record for RtlRaiseException
  436. RaiseFrameLength: // length of handler frame
  437. NESTED_ENTRY(KiRaiseUserExceptionDispatcher, RaiseFrameLength, zero)
  438. lda sp, -RaiseFrameLength(sp) // allocate stack frame
  439. stq ra, RaiseRa(sp) // save return address
  440. PROLOGUE_END
  441. stq v0, RaiseV0(sp) // save function return status
  442. stl v0, ErExceptionCode+RaiseExr(sp) // set exception code
  443. stl zero, ErExceptionFlags+RaiseExr(sp) // set exception flags
  444. stl zero, ErExceptionRecord+RaiseExr(sp) // set exception record
  445. stl ra, ErExceptionAddress+RaiseExr(sp) // set exception address
  446. stl zero, ErNumberParameters+RaiseExr(sp)
  447. lda a0, RaiseExr(sp) // set argument to RtlRaiseException
  448. bsr ra, RtlRaiseException // attempt to raise the exception
  449. ldq v0, RaiseV0(sp) // return status
  450. ldq ra, RaiseRa(sp) // restore ra
  451. lda sp, RaiseFrameLength(sp) // deallocate stack frame
  452. ret zero, (ra) // return
  453. .end KiRaiseUserExceptionDispatch