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.

597 lines
16 KiB

  1. //++
  2. //
  3. // Module Name:
  4. //
  5. // trampoln.s
  6. //
  7. // Abstract:
  8. //
  9. // This module implements the trampoline code necessary to dispatch user
  10. // mode APCs.
  11. //
  12. // Author:
  13. //
  14. // William K. Cheung 25-Oct-1995
  15. //
  16. // Environment:
  17. //
  18. // User mode only.
  19. //
  20. // Revision History:
  21. //
  22. // 08-Feb-1996 Updated to EAS 2.1
  23. //
  24. //--
  25. #include "ksia64.h"
  26. .file "trampoln.s"
  27. PublicFunction(RtlpCaptureRnats)
  28. PublicFunction(RtlDispatchException)
  29. PublicFunction(RtlRaiseException)
  30. PublicFunction(RtlRaiseStatus)
  31. PublicFunction(ZwContinue)
  32. PublicFunction(ZwCallbackReturn)
  33. PublicFunction(ZwRaiseException)
  34. PublicFunction(ZwTestAlert)
  35. .global Wow64PrepareForException
  36. //++
  37. //
  38. // EXCEPTION_DISPOSITION
  39. // KiUserApcHandler (
  40. // IN PEXCEPTION_RECORD ExceptionRecord,
  41. // IN ULONG EstablisherFrame,
  42. // IN OUT PCONTEXT ContextRecord,
  43. // IN OUT PDISPATCHER_CONTEXT DispatcherContext
  44. //
  45. // Routine Description:
  46. //
  47. // This function is called when an exception occurs in an APC routine
  48. // or one of its dynamic descendents and when an unwind through the
  49. // APC dispatcher is in progress. If an unwind is in progress, then test
  50. // alert is called to ensure that all currently queued APCs are executed.
  51. //
  52. // Arguments:
  53. //
  54. // ExceptionRecord (a0) - Supplies a pointer to an exception record.
  55. //
  56. // EstablisherFrame (a1) - Supplies the frame pointer of the establisher
  57. // of this exception handler.
  58. //
  59. // ContextRecord (a2) - Supplies a pointer to a context record.
  60. //
  61. // DispatcherContext (a3) - Supplies a pointer to the dispatcher context
  62. // record.
  63. //
  64. // Return Value:
  65. //
  66. // ExceptionContinueSearch is returned as the function value.
  67. //
  68. //--
  69. NESTED_ENTRY (KiUserApcHandler)
  70. //
  71. // register aliases
  72. //
  73. pUwnd = pt1
  74. pNot = pt2
  75. NESTED_SETUP(1, 2, 0, 0)
  76. add t0 = ErExceptionFlags, a0
  77. ;;
  78. PROLOGUE_END
  79. ld4 t2 = [t0] // get exception flags
  80. ;;
  81. and t2 = EXCEPTION_UNWIND, t2 // check if unwind in progress
  82. ;;
  83. cmp4.ne pUwnd, pNot = zero, t2
  84. ;;
  85. (pNot) add v0 = ExceptionContinueSearch, zero
  86. (pNot) br.ret.sptk.clr brp // return
  87. (pUwnd) br.call.spnt.many brp = ZwTestAlert
  88. //
  89. // restore preserved states and set the disposition value to continue search
  90. //
  91. add v0 = ExceptionContinueSearch, zero
  92. mov brp = savedbrp // restore return link
  93. nop.b 0
  94. nop.m 0
  95. mov ar.pfs = savedpfs // restore pfs
  96. br.ret.sptk.clr brp // return
  97. NESTED_EXIT (KiUserApcHandler)
  98. //++
  99. //
  100. // VOID
  101. // KiUserApcDispatcher (
  102. // IN PVOID NormalContext,
  103. // IN PVOID SystemArgument1,
  104. // IN PVOID SystemArgument2,
  105. // IN PKNORMAL_ROUTINE NormalRoutine
  106. // )
  107. //
  108. // Routine Description:
  109. //
  110. // This routine is entered on return from kernel mode to deliver an APC
  111. // in user mode. The stack frame for this routine was built when the
  112. // APC interrupt was processed and contains the entire machine state of
  113. // the current thread. The specified APC routine is called and then the
  114. // machine state is restored and execution is continued.
  115. //
  116. // Arguments:
  117. //
  118. // t0 - Supplies the normal context parameter that was specified when the
  119. // APC was initialized.
  120. //
  121. // t1 - Supplies the first argument that was provied by the executive when
  122. // the APC was queued.
  123. //
  124. // t2 - Supplies the second argument that was provided by the executive
  125. // when the APC was queued.
  126. //
  127. // t3 - Supplies the address of the plabel for the function
  128. // that is to be called.
  129. //
  130. // Return Value:
  131. //
  132. // None.
  133. //
  134. //
  135. // N.B. On entry, sp points to the stack scratch area at the top of the
  136. // memory stack.
  137. //
  138. // N.B. The input arguments of this function are passed from the kernel
  139. // in scratch registers t0, t1, t2, and t3.
  140. //
  141. //--
  142. NESTED_ENTRY_EX (KiUserApcDispatch, KiUserApcHandler)
  143. ALTERNATE_ENTRY (KiUserApcDispatcher)
  144. .prologue
  145. .unwabi @nt, CONTEXT_FRAME
  146. .regstk 0, 0, 3, 0
  147. rBsp = t10 // BspStore
  148. rpCr = t11 // pointer to context record
  149. rpT1 = t12 // temporary pointer
  150. alloc t22 = ar.pfs, 0, 0, 3, 0 // 3 outputs
  151. add t10 = STACK_SCRATCH_AREA+ContextFrameLength+24, sp
  152. add t11 = STACK_SCRATCH_AREA+ContextFrameLength, sp
  153. ;;
  154. PROLOGUE_END
  155. ld8.nta t12 = [t10], -8
  156. movl s1 = _gp
  157. ;;
  158. ld8.nta out0 = [t11], 8
  159. ld8.nta t13 = [t12], PlGlobalPointer-PlEntryPoint
  160. ;;
  161. ld8.nta out1 = [t11], 8
  162. ld8.nta out2 = [t10]
  163. mov bt0 = t13
  164. ld8.nta gp = [t12]
  165. br.call.sptk.many brp = bt0 // call APC routine
  166. ;;
  167. //
  168. // On return, setup global pointer and branch register to call ZwContinue.
  169. // Also, flush the RSE to sync up the bsp and bspstore pointers. The
  170. // corresponding field in the context record is updated too.
  171. //
  172. flushrs
  173. mov out1 = 1 // set TestAlert to TRUE
  174. ;;
  175. add out0 = STACK_SCRATCH_AREA, sp // context record address
  176. mov gp = s1 // restore gp
  177. br.call.sptk.many brp = ZwContinue
  178. ;;
  179. //
  180. // if successful, ZwContinue does not return here;
  181. // otherwise, error happened.
  182. //
  183. mov gp = s1 // restore gp
  184. mov s0 = v0 // save the return status
  185. ;;
  186. Kuad10:
  187. mov out0 = s0 // setup 1st argument
  188. br.call.sptk.many brp = RtlRaiseStatus
  189. ;;
  190. nop.m 0
  191. nop.i 0
  192. br Kuad10 // loop on return
  193. NESTED_EXIT(KiUserApcDispatch)
  194. //++
  195. //
  196. // VOID
  197. // KiUserCallbackDispatcher (
  198. // VOID
  199. // )
  200. //
  201. // Routine Description:
  202. //
  203. // This routine is entered on a callout from kernel mode to execute a
  204. // user mode callback function. All arguments for this function have
  205. // been placed on the stack.
  206. //
  207. // Arguments:
  208. //
  209. // (sp + 32 + CkApiNumber) - Supplies the API number of the callback
  210. // function that is to be executed.
  211. //
  212. // (sp + 32 + CkBuffer) - Supplies a pointer to the input buffer.
  213. //
  214. // (sp + 32 + CkLength) - Supplies the input buffer length.
  215. //
  216. // Return Value:
  217. //
  218. // This function returns to kernel mode.
  219. //
  220. // N.B. Preserved register s1 is used to save ZwCallbackReturn plabel address.
  221. // On entry, gp is set to the global pointer value of NTDLL
  222. //
  223. //--
  224. NESTED_ENTRY(KiUserCallbackDispatch)
  225. .prologue
  226. .savesp rp, STACK_SCRATCH_AREA+CkBrRp
  227. .savesp ar.pfs, STACK_SCRATCH_AREA+CkRsPFS
  228. .vframesp STACK_SCRATCH_AREA+CkIntSp
  229. nop.m 0
  230. nop.m 0
  231. nop.i 0
  232. ;;
  233. PROLOGUE_END
  234. ALTERNATE_ENTRY(KiUserCallbackDispatcher)
  235. //
  236. // register aliases
  237. //
  238. rpT0 = t0 // temporary pointer
  239. rpT1 = t1 // temporary pointer
  240. rT0 = t2 // temporary value
  241. rFunc = t3 // callback function entry
  242. rApi = t4
  243. alloc t22 = ar.pfs, 0, 0, 3, 0 // 3 outputs max.
  244. mov teb = kteb // sanitize teb
  245. add rpT0 = STACK_SCRATCH_AREA + CkApiNumber, sp
  246. movl gp = _gp
  247. ;;
  248. ld4 rApi = [rpT0], CkBuffer - CkApiNumber // get API number
  249. add rpT1 = TePeb, teb
  250. mov s0 = gp
  251. ;;
  252. //
  253. // load both input buffer address and length into scratch register t2
  254. // and then deposit them into registers out0 & out1 respectively.
  255. //
  256. // N.B. t0 is 8-byte aligned.
  257. //
  258. LDPTRINC(out0, rpT0, CkLength-CkBuffer) // input buffer address
  259. LDPTR(t11, rpT1) // get address of PEB
  260. #if defined(_WIN64)
  261. shl rApi = rApi, 3 // compute offset to table entry
  262. #else
  263. shl rApi = rApi, 2 // compute offset to table entry
  264. #endif
  265. ;;
  266. ld4 out1 = [rpT0] // get input buffer length
  267. add t5 = PeKernelCallbackTable, t11
  268. ;;
  269. LDPTR(rFunc, t5) // address of callback table
  270. ;;
  271. add rFunc = rApi, rFunc // compute addr of table entry
  272. ;;
  273. LDPTR(t6, rFunc) // get plabel's address
  274. ;;
  275. ld8.nt1 t9 = [t6], PlGlobalPointer-PlEntryPoint // load entry point address
  276. ;;
  277. ld8.nt1 gp = [t6] // load callee's GP
  278. mov bt0 = t9
  279. br.call.sptk.many brp = bt0 // invoke the callback func
  280. //
  281. // If a return from the callback function occurs, then the output buffer
  282. // address and length are returned as NULL.
  283. //
  284. mov out0 = zero // NULL output buffer addr
  285. mov out1 = zero // zero output buffer len
  286. mov out2 = v0 // set completion status
  287. mov gp = s0
  288. br.call.sptk.many brp = ZwCallbackReturn
  289. //
  290. // Unsuccessful completion after attempting to return to kernel mode. Use
  291. // the return status as the exception code, set noncontinuable exception and
  292. // attempt to raise another exception. Note there is no return from raise
  293. // status.
  294. //
  295. nop.m 0
  296. mov gp = s0 // restore our own GP
  297. mov s0 = v0 // save status value
  298. ;;
  299. Kucd10:
  300. mov out0 = s0 // set status value
  301. br.call.sptk.many brp = RtlRaiseStatus
  302. nop.m 0
  303. nop.m 0
  304. br Kucd10 // jump back to Kucd10
  305. NESTED_EXIT(KiUserCallbackDispatch)
  306. //++
  307. //
  308. // VOID
  309. // KiUserExceptionDispatcher (
  310. // IN PEXCEPTION_RECORD ExceptionRecord,
  311. // IN PCONTEXT ContextRecord
  312. // )
  313. //
  314. // Routine Description:
  315. //
  316. // This routine is entered on return from kernel mode to dispatch a user
  317. // mode exception. If a frame based handler handles the exception, then
  318. // the execution is continued. Else last chance processing is performed.
  319. //
  320. // Arguments:
  321. //
  322. // s0 - Supplies a pointer to an exception record.
  323. //
  324. // s1 - Supplies a pointer to a context record.
  325. //
  326. // Return Value:
  327. //
  328. // None.
  329. //
  330. // N.B. preserved register s3 is used to save the current global pointer.
  331. //
  332. //--
  333. NESTED_ENTRY (KiUserExceptionDispatch)
  334. ALTERNATE_ENTRY(KiUserExceptionDispatcher)
  335. .prologue
  336. .unwabi @nt, CONTEXT_FRAME
  337. alloc t0 = ar.pfs, 0, 1, 3, 0
  338. mov teb = kteb // sanitize teb
  339. mov s3 = gp // save global pointer
  340. ;;
  341. PROLOGUE_END
  342. flushrs // flush the RSE
  343. ;;
  344. mov out0 = s1
  345. br.call.sptk.many brp = RtlpCaptureRnats
  346. ;;
  347. add t1 = @gprel(Wow64PrepareForException), gp
  348. ;;
  349. ld8 t1 = [t1]
  350. ;;
  351. cmp.ne pt1, pt0 = zero, t1 // Wow64PrepareForException != NULL?
  352. ;;
  353. (pt1) ld8 t2 = [t1], PlGlobalPointer - PlEntryPoint
  354. ;;
  355. (pt1) ld8 gp = [t1]
  356. (pt1) mov bt0 = t2
  357. (pt1) br.call.spnt.few brp = bt0
  358. ;;
  359. mov gp = s3
  360. mov out0 = s0
  361. mov out1 = s1
  362. br.call.sptk.many brp = RtlDispatchException
  363. cmp4.eq pt1, pt0 = zero, v0 // result is FALSE ?
  364. ;;
  365. (pt1) mov out2 = zero
  366. mov gp = s3
  367. (pt0) add out0 = 0, s1
  368. (pt0) mov out1 = zero // set test alert to FALSE.
  369. (pt0) br.call.sptk.many brp = ZwContinue
  370. ;;
  371. (pt1) add out0 = 0, s0
  372. (pt1) mov out1 = s1
  373. (pt1) br.call.sptk.many brp = ZwRaiseException
  374. ;;
  375. //
  376. // Common code for nonsuccessful completion of the continue or last chance
  377. // processing service. Use the return status as the exception code, set
  378. // noncontinuable exception and attempt to raise another exception. Note
  379. // that the stack grows and eventually this loop will end.
  380. //
  381. Kued10:
  382. //
  383. // allocate space for exception record
  384. //
  385. nop.m 0
  386. movl s2 = EXCEPTION_NONCONTINUABLE // set noncontinuable flag.
  387. add sp = -ExceptionRecordLength, sp
  388. nop.f 0
  389. mov gp = s3 // restore gp
  390. ;;
  391. add out0 = STACK_SCRATCH_AREA, sp // get except record addr
  392. add t2 = ErExceptionFlags+STACK_SCRATCH_AREA, sp
  393. add t3 = ErExceptionCode+STACK_SCRATCH_AREA, sp
  394. ;;
  395. //
  396. // Set exception flags and exception code.
  397. //
  398. st4 [t2] = s2, ErExceptionRecord - ErExceptionFlags
  399. st4 [t3] = v0, ErNumberParameters - ErExceptionCode
  400. ;;
  401. //
  402. // Set exception record and number of parameters.
  403. // Then call RtlRaiseException
  404. //
  405. st4 [t2] = s0
  406. st4 [t3] = zero
  407. br.call.sptk.many brp = RtlRaiseException
  408. nop.m 0
  409. nop.m 0
  410. br Kued10 // loop on return
  411. NESTED_EXIT(KiUserExceptionDispatch)
  412. //++
  413. //
  414. // NTSTATUS
  415. // KiRaiseUserExceptionDispatcher (
  416. // IN NTSTATUS ExceptionCode
  417. // )
  418. //
  419. // Routine Description:
  420. //
  421. // This routine is entered on return from kernel mode to raise a user
  422. // mode exception.
  423. //
  424. // Arguments:
  425. //
  426. // v0 - Supplies the status code to be raised.
  427. //
  428. // Return Value:
  429. //
  430. // ExceptionCode
  431. //
  432. //--
  433. //
  434. // N.B. This function is not called in the typical way. Instead of a normal
  435. // subroutine call to the nested entry point above, the alternate entry point
  436. // address below is stuffed into the Fir address of the trap frame. Thus when
  437. // the kernel returns from the trap, the following code is executed directly.
  438. //
  439. NESTED_ENTRY(KiRaiseUserExceptionDispatch)
  440. .prologue
  441. .savepsp ar.pfs, -8
  442. nop.m 0
  443. .savepsp rp, 0
  444. nop.m 0
  445. nop.i 0
  446. ;;
  447. ALTERNATE_ENTRY(KiRaiseUserExceptionDispatcher)
  448. //
  449. // ar.pfs and brp have been saved on the stack in the scratch area.
  450. //
  451. alloc t22 = ar.pfs, 8, 1, 1, 0
  452. ld8.nta t3 = [sp]
  453. .fframe ExceptionRecordLength+STACK_SCRATCH_AREA, tg10
  454. [tg10:] add sp = -ExceptionRecordLength-STACK_SCRATCH_AREA, sp
  455. ;;
  456. PROLOGUE_END
  457. add t1 = STACK_SCRATCH_AREA+ErExceptionCode, sp
  458. add t2 = STACK_SCRATCH_AREA+ErExceptionFlags, sp
  459. mov loc0 = v0
  460. ;;
  461. //
  462. // set exception code and exception flags
  463. //
  464. st4 [t1] = v0, ErExceptionRecord - ErExceptionCode
  465. movl gp = _gp // setup gp to ntdll's
  466. st4 [t2] = zero, ErExceptionAddress - ErExceptionFlags
  467. ;;
  468. st4 [t1] = zero, ErNumberParameters - ErExceptionRecord
  469. add out0 = STACK_SCRATCH_AREA, sp
  470. ;;
  471. //
  472. // set exception record and exception address
  473. //
  474. st4 [t1] = zero // set number of parameters
  475. STPTR(t2, t3)
  476. br.call.sptk.many brp = RtlRaiseException
  477. add t1 = ExceptionRecordLength+STACK_SCRATCH_AREA, sp
  478. add t2 = ExceptionRecordLength+STACK_SCRATCH_AREA+8, sp
  479. mov v0 = loc0
  480. ;;
  481. ld8.nta t3 = [t1]
  482. ld8.nta t4 = [t2]
  483. ;;
  484. mov brp = t3
  485. .restore tg20
  486. [tg20:] add sp = ExceptionRecordLength, sp
  487. mov ar.pfs = t4
  488. br.ret.sptk.clr brp
  489. NESTED_EXIT(KiRaiseUserExceptionDispatcher)