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.

381 lines
12 KiB

  1. title "Call Out to User Mode"
  2. ;++
  3. ;
  4. ; Copyright (c) 2000 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; callout.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the code necessary to call out from kernel
  13. ; mode to user mode.
  14. ;
  15. ; Author:
  16. ;
  17. ; David N. Cutler (davec) 30-Aug-2000
  18. ;
  19. ; Environment:
  20. ;
  21. ; Kernel mode only.
  22. ;
  23. ;--
  24. include ksamd64.inc
  25. extern KeUserCallbackDispatcher:qword
  26. extern KiSystemServiceExit:proc
  27. extern MmGrowKernelStack:proc
  28. extern PsConvertToGuiThread:proc
  29. subttl "Call User Mode Function"
  30. ;++
  31. ;
  32. ; NTSTATUS
  33. ; KiCallUserMode (
  34. ; IN PVOID *Outputbuffer,
  35. ; IN PULONG OutputLength
  36. ; )
  37. ;
  38. ; Routine Description:
  39. ;
  40. ; This function calls a user mode function from kernel mode.
  41. ;
  42. ; N.B. This function calls out to user mode and the NtCallbackReturn
  43. ; function returns back to the caller of this function. Therefore,
  44. ; the stack layout must be consistent between the two routines.
  45. ;
  46. ; Arguments:
  47. ;
  48. ; OutputBuffer (rcx) - Supplies a pointer to the variable that receivies
  49. ; the address of the output buffer.
  50. ;
  51. ; OutputLength (rdx) - Supplies a pointer to a variable that receives
  52. ; the length of the output buffer.
  53. ;
  54. ; Return Value:
  55. ;
  56. ; The final status of the call out function is returned as the status
  57. ; of the function.
  58. ;
  59. ; N.B. This function does not return to its caller. A return to the
  60. ; caller is executed when a NtCallbackReturn system service is
  61. ; executed.
  62. ;
  63. ; N.B. This function does return to its caller if a kernel stack
  64. ; expansion is required and the attempted expansion fails.
  65. ;
  66. ;--
  67. NESTED_ENTRY KiCallUserMode, _TEXT$00
  68. GENERATE_EXCEPTION_FRAME <Rbp> ; generate exception frame
  69. ;
  70. ; Save argument registers in frame and allocate a legacy floating point
  71. ; save area.
  72. ;
  73. mov CuOutputBuffer[rbp], rcx ; save output buffer address
  74. mov CuOutputLength[rbp], rdx ; save output length address
  75. sub rsp, LEGACY_SAVE_AREA_LENGTH ; allocate legacy save area
  76. ;
  77. ; Check if sufficient room is available on the kernel stack for another
  78. ; system call.
  79. ;
  80. mov rbx, gs:[PcCurrentThread] ; get current thread address
  81. lea rax, (- KERNEL_LARGE_STACK_COMMIT)[rsp] ; compute bottom address
  82. cmp rax, ThStackLimit[rbx] ; check if limit exceeded
  83. jae short KiCU10 ; if ae, limit not exceeded
  84. mov rcx, rsp ; set current stack address
  85. call MmGrowKernelStack ; attempt to grow kernel stack
  86. or eax, eax ; check for successful completion
  87. jne short KiCU20 ; if ne, attempt to grow failed
  88. ;
  89. ; Save the previous trap frame and callback stack addresses in the current
  90. ; frame. Also save the new callback stack address in the thread object.
  91. ;
  92. KiCU10: mov rax, ThCallbackStack[rbx] ; save current callback stack address
  93. mov CuCallbackStack[rbp], rax ;
  94. mov rsi, ThTrapFrame[rbx] ; save current trap frame address
  95. mov CuTrapFrame[rbp], rsi ;
  96. mov rax, ThInitialStack[rbx] ; save initial stack address
  97. mov CuInitialStack[rbp], rax ;
  98. mov ThCallbackstack[rbx], rbp ; set new callback stack address
  99. ;
  100. ; Establish a new initial kernel stack address
  101. ;
  102. cli ; disable interrupts
  103. mov ThInitialStack[rbx], rsp ; set new initial stack address
  104. mov rdi, gs:[PcTss] ; get processor TSS address
  105. mov TssRsp0[rdi], rsp ; set initial stack address in TSS
  106. ;
  107. ; Construct a trap frame to facilitate the transfer into user mode via
  108. ; the standard system call exit.
  109. ;
  110. ; N.B. Interrupts are not enabled throughout the remainder of the system
  111. ; service exit.
  112. ;
  113. sub rsp, KTRAP_FRAME_LENGTH ; allocate a trap frame
  114. mov rdi, rsp ; set destination address
  115. mov rcx, (KTRAP_FRAME_LENGTH / 8) ; set length of copy
  116. rep movsq ; copy trap frame
  117. lea rbp, 128[rsp] ; set frame pointer address
  118. mov rax, KeUserCallbackDispatcher ; set user return address
  119. mov TrRip[rbp], rax ;
  120. jmp KiSystemServiceExit ; exit through service dispatch
  121. ;
  122. ; An attempt to grow the kernel stack failed.
  123. ;
  124. KiCU20: mov rsp, rbp ; deallocate legacy save area
  125. RESTORE_EXCEPTION_STATE <Rbp> ; restore exception state/deallocate
  126. ret ;
  127. NESTED_END KiCallUserMode, _TEXT$00
  128. subttl "Convert To Gui Thread"
  129. ;++
  130. ;
  131. ; NTSTATUS
  132. ; KiConvertToGuiThread (
  133. ; VOID
  134. ; );
  135. ;
  136. ; Routine Description:
  137. ;
  138. ; This routine is a stub routine which is called by the system service
  139. ; dispatcher to convert the current thread to a GUI thread. The process
  140. ; of converting to a GUI mode thread involves allocating a large stack,
  141. ; switching to the large stack, and then calling the win32k subsystem
  142. ; to record state. In order to switch the kernel stack the frame pointer
  143. ; used in the system service dispatch must be relocated.
  144. ;
  145. ; N.B. The address of the pushed rbp in this routine is located from the
  146. ; trap frame address in switch kernel stack.
  147. ;
  148. ; Arguments:
  149. ;
  150. ; None.
  151. ;
  152. ; Implicit arguments:
  153. ;
  154. ; rbp - Supplies a pointer to the trap frame.
  155. ;
  156. ; Return Value:
  157. ;
  158. ; The status returned by the real convert to GUI thread is returned as the
  159. ; function status.
  160. ;
  161. ;--
  162. NESTED_ENTRY KiConvertToGuiThread, _TEXT$00
  163. push_reg rbp ; save frame pointer
  164. END_PROLOGUE
  165. call PsConvertToGuiThread ; convert to GUI thread
  166. pop rbp ; restore frame pointer
  167. ret ;
  168. NESTED_END KiConvertToGuiThread, _TEXT$00
  169. subttl "Switch Kernel Stack"
  170. ;++
  171. ;
  172. ; PVOID
  173. ; KeSwitchKernelStack (
  174. ; IN PVOID StackBase,
  175. ; IN PVOID StackLimit
  176. ; )
  177. ;
  178. ; Routine Description:
  179. ;
  180. ; This function switches to the specified large kernel stack.
  181. ;
  182. ; N.B. This function can ONLY be called when there are no variables
  183. ; in the stack that refer to other variables in the stack, i.e.,
  184. ; there are no pointers into the stack.
  185. ;
  186. ; N.B. The address of the frame pointer used in the system service
  187. ; dispatcher is located using the trap frame.
  188. ;
  189. ; Arguments:
  190. ;
  191. ; StackBase (rcx) - Supplies a pointer to the base of the new kernel
  192. ; stack.
  193. ;
  194. ; StackLimit (rdx) - Suplies a pointer to the limit of the new kernel
  195. ; stack.
  196. ;
  197. ; Return Value:
  198. ;
  199. ; The previous stack base is returned as the function value.
  200. ;
  201. ;--
  202. SkFrame struct
  203. Fill dq ? ; fill to 8 mod 16
  204. SavedRdi dq ? ; saved register RDI
  205. SavedRsi dq ? ; saved register RSI
  206. SkFrame ends
  207. NESTED_ENTRY KeSwitchKernelStack, _TEXT$00
  208. push_reg rsi ; save nonvolatile registers
  209. push_reg rdi ;
  210. alloc_stack (sizeof SkFrame - (2 * 8)) ; allocate stack frame
  211. END_PROLOGUE
  212. ;
  213. ; Save the address of the new stack and copy the current stack to the new
  214. ; stack.
  215. ;
  216. mov r8, rcx ; save new stack base address
  217. mov r10, gs:[PcCurrentThread] ; get current thread address
  218. mov rcx, ThStackBase[r10] ; get current stack base address
  219. mov r9, ThTrapFrame[r10] ; get current trap frame address
  220. sub r9, rcx ; relocate trap frame address
  221. add r9, r8 ;
  222. mov ThTrapFrame[r10], r9 ; set new trap frame address
  223. sub rcx, rsp ; compute length of copy in bytes
  224. mov rdi, r8 ; compute destination address of copy
  225. sub rdi, rcx ;
  226. mov r9, rdi ; save new stack pointer address
  227. mov rsi, rsp ; set source address of copy
  228. shr rcx, 3 ; compute length of copy on quadwords
  229. rep movsq ; copy old stack to new stack
  230. mov rcx, ThTrapFrame[r10] ; get new trap frame address
  231. lea rax, 128[rcx] ; compute new frame address
  232. mov (-2 * 8)[rcx], rax ; set relocated frame pointer
  233. ;
  234. ; Switch to the new kernel stack and return the address of the old kernel
  235. ; stack.
  236. ;
  237. mov rax, ThStackBase[r10] ; get current stack base address
  238. cli ; disable interrupts
  239. mov byte ptr ThLargeStack[r10], 1 ; set large stack TRUE
  240. mov ThStackBase[r10], r8 ; set new stack base address
  241. sub r8, LEGACY_SAVE_AREA_LENGTH ; compute initial stack address
  242. mov ThInitialStack[r10], r8 ; set new initial stack address
  243. mov ThStackLimit[r10], rdx ; set new stack limit address
  244. mov r10, gs:[PcTss] ; get processor TSS address
  245. mov TssRsp0[r10], r8 ; set initial stack address in TSS
  246. mov rsp, r9 ; set new stack pointer address
  247. sti ;
  248. add rsp, sizeof SkFrame - (2 * 8) ; deallocate stack frame
  249. pop rdi ; restore nonvolatile registers
  250. pop rsi ;
  251. ret ; return
  252. NESTED_END KeSwitchKernelStack, _TEXT$00
  253. subttl "Return from User Mode Callback"
  254. ;++
  255. ;
  256. ; NTSTATUS
  257. ; NtCallbackReturn (
  258. ; IN PVOID OutputBuffer OPTIONAL,
  259. ; IN ULONG OutputLength,
  260. ; IN NTSTATUS Status
  261. ; )
  262. ;
  263. ; Routine Description:
  264. ;
  265. ; This function returns from a user mode callout to the kernel
  266. ; mode caller of the user mode callback function.
  267. ;
  268. ; N.B. This function returns to the function that called out to user
  269. ; mode and the KiCallUserMode function calls out to user mode.
  270. ; Therefore, the stack layout must be consistent between the
  271. ; two routines.
  272. ;
  273. ; Arguments:
  274. ;
  275. ; OutputBuffer (rcx) - Supplies an optional pointer to an output buffer.
  276. ;
  277. ; OutputLength (rdx) - Supplies the length of the output buffer.
  278. ;
  279. ; Status (r8) - Supplies the status value returned to the caller of the
  280. ; callback function.
  281. ;
  282. ; Return Value:
  283. ;
  284. ; If the callback return cannot be executed, then an error status is
  285. ; returned. Otherwise, the specified callback status is returned to
  286. ; the caller of the callback function.
  287. ;
  288. ; N.B. This function returns to the function that called out to user
  289. ; mode is a callout is currently active.
  290. ;
  291. ;--
  292. LEAF_ENTRY NtCallbackReturn, _TEXT$00
  293. mov r11, gs:[PcCurrentThread] ; get current thread address
  294. mov r10, ThCallbackStack[r11] ; get callback stack address
  295. cmp r10, 0 ; check if callback active
  296. je KiCb10 ; if zero, callback not active
  297. mov rax, r8 ; save completion status
  298. ;
  299. ; Store the output buffer address and length.
  300. ;
  301. mov r9, CuOutputBuffer[r10] ; get address to store output buffer
  302. mov [r9], rcx ; store output buffer address
  303. mov r9, CuOutputLength[r10] ; get address to store output length
  304. mov [r9], edx ; store output buffer length
  305. ;
  306. ; Restore the previous callback stack address and trap frame address.
  307. ;
  308. mov r8, CuTrapFrame[r10] ; get previous trap frame address
  309. mov ThTrapFrame[r11], r8 ; restore previous trap frame address
  310. mov r8, CuCallbackStack[r10] ; get previous callback stack address
  311. mov ThCallbackStack[r11], r8 ; restore previous callback stack address
  312. ;
  313. ; Restore initial stack address.
  314. ;
  315. mov r9, CuInitialStack[r10] ; get previous initial stack address
  316. cli ; disable interrupt
  317. mov ThInitialStack[r11], r9 ; restore initial stack address
  318. mov r8, gs:[PcTss] ; get processor TSS address
  319. mov TssRsp0[r8], r9 ; set initial stack address in TSS
  320. mov rsp, r10 ; trim stack back to callback frame
  321. RESTORE_EXCEPTION_STATE <Rbp> ; restore exception state/deallocate
  322. sti ; enable interrupts
  323. ret ; return
  324. ;
  325. ; No callback is currently active.
  326. ;
  327. KiCB10: mov eax, STATUS_NO_CALLBACK_ACTIVE ; set service status
  328. ret ; return
  329. LEAF_END NtCallbackReturn, _TEXT$00
  330. end