Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

616 lines
18 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. //
  119. // Transfer the context information to the user stack, initialize the
  120. // APC routine parameters, and modify the trap frame so execution will
  121. // continue in user mode at the user mode APC dispatch routine.
  122. //
  123. // We build the following structure on the user stack:
  124. //
  125. // | |
  126. // |-------------------------------|
  127. // | |
  128. // | Interrupted user's |
  129. // | stack frame |
  130. // | |
  131. // | |
  132. // |-------------------------------|
  133. // | Slack Space due to the |
  134. // | 16-byte stack alignment |
  135. // | - - - - - - - - - - - - - - - |
  136. // | NormalRoutine |
  137. // | SystemArgument2 |
  138. // | SystemArgument1 |
  139. // | NormalContext |
  140. // | - - - - - - - - - - - - - - - |
  141. // | Context Frame |
  142. // | Filled in with state |
  143. // | of interrupted user |
  144. // | program |
  145. // | - - - - - - - - - - - - - - - |
  146. // | Stack Scratch Area |
  147. // |-------------------------------|
  148. // | |
  149. //
  150. // Return Value:
  151. //
  152. // None.
  153. //
  154. //
  155. // N.B. On entry, sp points to the stack scratch area at the top of the
  156. // memory stack.
  157. //
  158. //--
  159. NESTED_ENTRY_EX (KiUserApcDispatch, KiUserApcHandler)
  160. ALTERNATE_ENTRY (KiUserApcDispatcher)
  161. .prologue
  162. .unwabi @nt, CONTEXT_FRAME
  163. .regstk 0, 0, 3, 0
  164. rBsp = t10 // BspStore
  165. rpCr = t11 // pointer to context record
  166. rpT1 = t12 // temporary pointer
  167. alloc t22 = ar.pfs, 0, 0, 3, 0 // 3 outputs
  168. add t10 = STACK_SCRATCH_AREA+ContextFrameLength+24, sp
  169. add t11 = STACK_SCRATCH_AREA+ContextFrameLength, sp
  170. ;;
  171. PROLOGUE_END
  172. ld8.nta t12 = [t10], -8
  173. movl s1 = _gp
  174. ;;
  175. ld8.nta out0 = [t11], 8
  176. ld8.nta t13 = [t12], PlGlobalPointer-PlEntryPoint
  177. ;;
  178. ld8.nta out1 = [t11], 8
  179. ld8.nta out2 = [t10]
  180. mov bt0 = t13
  181. ld8.nta gp = [t12]
  182. br.call.sptk.many brp = bt0 // call APC routine
  183. ;;
  184. //
  185. // On return, setup global pointer and branch register to call ZwContinue.
  186. // Also, flush the RSE to sync up the bsp and bspstore pointers. The
  187. // corresponding field in the context record is updated too.
  188. //
  189. flushrs
  190. mov out1 = 1 // set TestAlert to TRUE
  191. ;;
  192. add out0 = STACK_SCRATCH_AREA, sp // context record address
  193. mov gp = s1 // restore gp
  194. br.call.sptk.many brp = ZwContinue
  195. ;;
  196. //
  197. // if successful, ZwContinue does not return here;
  198. // otherwise, error happened.
  199. //
  200. mov gp = s1 // restore gp
  201. mov s0 = v0 // save the return status
  202. ;;
  203. Kuad10:
  204. mov out0 = s0 // setup 1st argument
  205. br.call.sptk.many brp = RtlRaiseStatus
  206. ;;
  207. nop.m 0
  208. nop.i 0
  209. br Kuad10 // loop on return
  210. NESTED_EXIT(KiUserApcDispatch)
  211. //++
  212. //
  213. // VOID
  214. // KiUserCallbackDispatcher (
  215. // VOID
  216. // )
  217. //
  218. // Routine Description:
  219. //
  220. // This routine is entered on a callout from kernel mode to execute a
  221. // user mode callback function. All arguments for this function have
  222. // been placed on the stack.
  223. //
  224. // Arguments:
  225. //
  226. // (sp + 32 + CkApiNumber) - Supplies the API number of the callback
  227. // function that is to be executed.
  228. //
  229. // (sp + 32 + CkBuffer) - Supplies a pointer to the input buffer.
  230. //
  231. // (sp + 32 + CkLength) - Supplies the input buffer length.
  232. //
  233. // Return Value:
  234. //
  235. // This function returns to kernel mode.
  236. //
  237. // N.B. Preserved register s1 is used to save ZwCallbackReturn plabel address.
  238. // On entry, gp is set to the global pointer value of NTDLL
  239. //
  240. //--
  241. NESTED_ENTRY(KiUserCallbackDispatch)
  242. .prologue
  243. .savesp rp, STACK_SCRATCH_AREA+CkBrRp
  244. .savesp ar.pfs, STACK_SCRATCH_AREA+CkRsPFS
  245. .vframesp STACK_SCRATCH_AREA+CkIntSp
  246. nop.m 0
  247. nop.m 0
  248. nop.i 0
  249. ;;
  250. PROLOGUE_END
  251. ALTERNATE_ENTRY(KiUserCallbackDispatcher)
  252. //
  253. // register aliases
  254. //
  255. rpT0 = t0 // temporary pointer
  256. rpT1 = t1 // temporary pointer
  257. rT0 = t2 // temporary value
  258. rFunc = t3 // callback function entry
  259. rApi = t4
  260. alloc t22 = ar.pfs, 0, 0, 3, 0 // 3 outputs max.
  261. mov teb = kteb // sanitize teb
  262. add rpT0 = STACK_SCRATCH_AREA + CkApiNumber, sp
  263. movl gp = _gp
  264. ;;
  265. ld4 rApi = [rpT0], CkBuffer - CkApiNumber // get API number
  266. add rpT1 = TePeb, teb
  267. mov s0 = gp
  268. ;;
  269. //
  270. // load both input buffer address and length into scratch register t2
  271. // and then deposit them into registers out0 & out1 respectively.
  272. //
  273. // N.B. t0 is 8-byte aligned.
  274. //
  275. LDPTRINC(out0, rpT0, CkLength-CkBuffer) // input buffer address
  276. LDPTR(t11, rpT1) // get address of PEB
  277. #if defined(_WIN64)
  278. shl rApi = rApi, 3 // compute offset to table entry
  279. #else
  280. shl rApi = rApi, 2 // compute offset to table entry
  281. #endif
  282. ;;
  283. ld4 out1 = [rpT0] // get input buffer length
  284. add t5 = PeKernelCallbackTable, t11
  285. ;;
  286. LDPTR(rFunc, t5) // address of callback table
  287. ;;
  288. add rFunc = rApi, rFunc // compute addr of table entry
  289. ;;
  290. LDPTR(t6, rFunc) // get plabel's address
  291. ;;
  292. ld8.nt1 t9 = [t6], PlGlobalPointer-PlEntryPoint // load entry point address
  293. ;;
  294. ld8.nt1 gp = [t6] // load callee's GP
  295. mov bt0 = t9
  296. br.call.sptk.many brp = bt0 // invoke the callback func
  297. //
  298. // If a return from the callback function occurs, then the output buffer
  299. // address and length are returned as NULL.
  300. //
  301. mov out0 = zero // NULL output buffer addr
  302. mov out1 = zero // zero output buffer len
  303. mov out2 = v0 // set completion status
  304. mov gp = s0
  305. br.call.sptk.many brp = ZwCallbackReturn
  306. //
  307. // Unsuccessful completion after attempting to return to kernel mode. Use
  308. // the return status as the exception code, set noncontinuable exception and
  309. // attempt to raise another exception. Note there is no return from raise
  310. // status.
  311. //
  312. nop.m 0
  313. mov gp = s0 // restore our own GP
  314. mov s0 = v0 // save status value
  315. ;;
  316. Kucd10:
  317. mov out0 = s0 // set status value
  318. br.call.sptk.many brp = RtlRaiseStatus
  319. nop.m 0
  320. nop.m 0
  321. br Kucd10 // jump back to Kucd10
  322. NESTED_EXIT(KiUserCallbackDispatch)
  323. //++
  324. //
  325. // VOID
  326. // KiUserExceptionDispatcher (
  327. // IN PEXCEPTION_RECORD ExceptionRecord,
  328. // IN PCONTEXT ContextRecord
  329. // )
  330. //
  331. // Routine Description:
  332. //
  333. // This routine is entered on return from kernel mode to dispatch a user
  334. // mode exception. If a frame based handler handles the exception, then
  335. // the execution is continued. Else last chance processing is performed.
  336. //
  337. // Arguments:
  338. //
  339. // s0 - Supplies a pointer to an exception record.
  340. //
  341. // s1 - Supplies a pointer to a context record.
  342. //
  343. // Return Value:
  344. //
  345. // None.
  346. //
  347. // N.B. preserved register s3 is used to save the current global pointer.
  348. //
  349. //--
  350. NESTED_ENTRY (KiUserExceptionDispatch)
  351. ALTERNATE_ENTRY(KiUserExceptionDispatcher)
  352. .prologue
  353. .unwabi @nt, CONTEXT_FRAME
  354. alloc t0 = ar.pfs, 0, 1, 3, 0
  355. mov teb = kteb // sanitize teb
  356. mov s3 = gp // save global pointer
  357. ;;
  358. PROLOGUE_END
  359. flushrs // flush the RSE
  360. ;;
  361. mov out0 = s1
  362. br.call.sptk.many brp = RtlpCaptureRnats
  363. ;;
  364. add t1 = @gprel(Wow64PrepareForException), gp
  365. ;;
  366. ld8 t1 = [t1]
  367. ;;
  368. cmp.ne pt1, pt0 = zero, t1 // Wow64PrepareForException != NULL?
  369. ;;
  370. (pt1) ld8 t2 = [t1], PlGlobalPointer - PlEntryPoint
  371. ;;
  372. (pt1) ld8 gp = [t1]
  373. (pt1) mov bt0 = t2
  374. (pt1) br.call.spnt.few brp = bt0
  375. ;;
  376. mov gp = s3
  377. mov out0 = s0
  378. mov out1 = s1
  379. br.call.sptk.many brp = RtlDispatchException
  380. cmp4.eq pt1, pt0 = zero, v0 // result is FALSE ?
  381. ;;
  382. (pt1) mov out2 = zero
  383. mov gp = s3
  384. (pt0) add out0 = 0, s1
  385. (pt0) mov out1 = zero // set test alert to FALSE.
  386. (pt0) br.call.sptk.many brp = ZwContinue
  387. ;;
  388. (pt1) add out0 = 0, s0
  389. (pt1) mov out1 = s1
  390. (pt1) br.call.sptk.many brp = ZwRaiseException
  391. ;;
  392. //
  393. // Common code for nonsuccessful completion of the continue or last chance
  394. // processing service. Use the return status as the exception code, set
  395. // noncontinuable exception and attempt to raise another exception. Note
  396. // that the stack grows and eventually this loop will end.
  397. //
  398. Kued10:
  399. //
  400. // allocate space for exception record
  401. //
  402. nop.m 0
  403. movl s2 = EXCEPTION_NONCONTINUABLE // set noncontinuable flag.
  404. add sp = -ExceptionRecordLength, sp
  405. nop.f 0
  406. mov gp = s3 // restore gp
  407. ;;
  408. add out0 = STACK_SCRATCH_AREA, sp // get except record addr
  409. add t2 = ErExceptionFlags+STACK_SCRATCH_AREA, sp
  410. add t3 = ErExceptionCode+STACK_SCRATCH_AREA, sp
  411. ;;
  412. //
  413. // Set exception flags and exception code.
  414. //
  415. st4 [t2] = s2, ErExceptionRecord - ErExceptionFlags
  416. st4 [t3] = v0, ErNumberParameters - ErExceptionCode
  417. ;;
  418. //
  419. // Set exception record and number of parameters.
  420. // Then call RtlRaiseException
  421. //
  422. st4 [t2] = s0
  423. st4 [t3] = zero
  424. br.call.sptk.many brp = RtlRaiseException
  425. nop.m 0
  426. nop.m 0
  427. br Kued10 // loop on return
  428. NESTED_EXIT(KiUserExceptionDispatch)
  429. //++
  430. //
  431. // NTSTATUS
  432. // KiRaiseUserExceptionDispatcher (
  433. // IN NTSTATUS ExceptionCode
  434. // )
  435. //
  436. // Routine Description:
  437. //
  438. // This routine is entered on return from kernel mode to raise a user
  439. // mode exception.
  440. //
  441. // Arguments:
  442. //
  443. // v0 - Supplies the status code to be raised.
  444. //
  445. // Return Value:
  446. //
  447. // ExceptionCode
  448. //
  449. //--
  450. //
  451. // N.B. This function is not called in the typical way. Instead of a normal
  452. // subroutine call to the nested entry point above, the alternate entry point
  453. // address below is stuffed into the Fir address of the trap frame. Thus when
  454. // the kernel returns from the trap, the following code is executed directly.
  455. //
  456. NESTED_ENTRY(KiRaiseUserExceptionDispatch)
  457. .prologue
  458. .savepsp ar.pfs, -8
  459. nop.m 0
  460. .savepsp rp, 0
  461. nop.m 0
  462. nop.i 0
  463. ;;
  464. ALTERNATE_ENTRY(KiRaiseUserExceptionDispatcher)
  465. //
  466. // ar.pfs and brp have been saved on the stack in the scratch area.
  467. //
  468. alloc t22 = ar.pfs, 8, 1, 1, 0
  469. ld8.nta t3 = [sp]
  470. .fframe ExceptionRecordLength+STACK_SCRATCH_AREA, tg10
  471. [tg10:] add sp = -ExceptionRecordLength-STACK_SCRATCH_AREA, sp
  472. ;;
  473. PROLOGUE_END
  474. add t1 = STACK_SCRATCH_AREA+ErExceptionRecord, sp
  475. add t2 = STACK_SCRATCH_AREA+ErExceptionFlags, sp
  476. add t5 = TeExceptionCode, teb
  477. ;;
  478. //
  479. // set exception code and exception flags
  480. //
  481. ld4 t4 = [t5]
  482. movl gp = _gp // setup gp to ntdll's
  483. st8 [t1] = zero, ErExceptionCode - ErExceptionRecord
  484. st4 [t2] = zero, ErExceptionAddress - ErExceptionFlags
  485. mov loc0 = v0
  486. ;;
  487. st4 [t1] = t4, ErNumberParameters - ErExceptionCode
  488. add out0 = STACK_SCRATCH_AREA, sp
  489. ;;
  490. //
  491. // set exception record and exception address
  492. //
  493. st4 [t1] = zero // set number of parameters
  494. STPTR(t2, t3)
  495. br.call.sptk.many brp = RtlRaiseException
  496. add t1 = ExceptionRecordLength+STACK_SCRATCH_AREA, sp
  497. add t2 = ExceptionRecordLength+STACK_SCRATCH_AREA+8, sp
  498. mov v0 = loc0
  499. ;;
  500. ld8.nta t3 = [t1]
  501. ld8.nta t4 = [t2]
  502. ;;
  503. mov brp = t3
  504. .restore tg20
  505. [tg20:] add sp = ExceptionRecordLength+STACK_SCRATCH_AREA, sp
  506. mov ar.pfs = t4
  507. br.ret.sptk.clr brp
  508. NESTED_EXIT(KiRaiseUserExceptionDispatcher)