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.

522 lines
17 KiB

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