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.

395 lines
13 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 callback stack address and the initial stack address in the current
  90. ; frame.
  91. ;
  92. KiCU10: mov rax, ThCallbackStack[rbx] ; save current callback stack address
  93. mov CuCallbackStack[rbp], rax ;
  94. mov rsi, ThInitialStack[rbx] ; save initial stack address
  95. mov CuInitialStack[rbp], rsi ;
  96. mov ThCallbackstack[rbx], rbp ; set new callback stack address
  97. ;
  98. ; If the legacy state is scrub, then copy the legacy state template to the
  99. ; new legacy state area.
  100. ;
  101. cmp byte ptr ThNpxState[rbx], LEGACY_STATE_SCRUB ; check if scrub state
  102. jne short KiCU15 ; if ne, not scrubbing legacy state
  103. mov ecx, (LEGACY_SAVE_AREA_LENGTH / 8) ; set length of copy
  104. mov rdi, rsp ; set destination address
  105. movsq ; copy legacy floating template
  106. ;
  107. ; Save the current trap frame address and establish a new initial kernel stack
  108. ; address;
  109. ;
  110. KiCU15: mov rsi, ThTrapFrame[rbx] ; save current trap frame address
  111. mov CuTrapFrame[rbp], rsi ;
  112. mov rdi, gs:[PcTss] ; get processor TSS address
  113. cli ; disable interrupts
  114. mov ThInitialStack[rbx], rsp ; set new initial stack address
  115. mov TssRsp0[rdi], rsp ; set initial stack address in TSS
  116. ;
  117. ; Construct a trap frame to facilitate the transfer into user mode via
  118. ; the standard system call exit.
  119. ;
  120. ; N.B. Interrupts are not enabled throughout the remainder of the system
  121. ; service exit.
  122. ;
  123. sub rsp, KTRAP_FRAME_LENGTH ; allocate a trap frame
  124. mov rdi, rsp ; set destination address
  125. mov rcx, (KTRAP_FRAME_LENGTH / 8) ; set length of copy
  126. rep movsq ; copy trap frame
  127. lea rbp, 128[rsp] ; set frame pointer address
  128. mov rax, KeUserCallbackDispatcher ; set user return address
  129. mov TrRip[rbp], rax ;
  130. jmp KiSystemServiceExit ; exit through service dispatch
  131. ;
  132. ; An attempt to grow the kernel stack failed.
  133. ;
  134. KiCU20: mov rsp, rbp ; deallocate legacy save area
  135. RESTORE_EXCEPTION_STATE <Rbp> ; restore exception state/deallocate
  136. ret ;
  137. NESTED_END KiCallUserMode, _TEXT$00
  138. subttl "Convert To Gui Thread"
  139. ;++
  140. ;
  141. ; NTSTATUS
  142. ; KiConvertToGuiThread (
  143. ; VOID
  144. ; );
  145. ;
  146. ; Routine Description:
  147. ;
  148. ; This routine is a stub routine which is called by the system service
  149. ; dispatcher to convert the current thread to a GUI thread. The process
  150. ; of converting to a GUI mode thread involves allocating a large stack,
  151. ; switching to the large stack, and then calling the win32k subsystem
  152. ; to record state. In order to switch the kernel stack the frame pointer
  153. ; used in the system service dispatch must be relocated.
  154. ;
  155. ; N.B. The address of the pushed rbp in this routine is located from the
  156. ; trap frame address in switch kernel stack.
  157. ;
  158. ; Arguments:
  159. ;
  160. ; None.
  161. ;
  162. ; Implicit arguments:
  163. ;
  164. ; rbp - Supplies a pointer to the trap frame.
  165. ;
  166. ; Return Value:
  167. ;
  168. ; The status returned by the real convert to GUI thread is returned as the
  169. ; function status.
  170. ;
  171. ;--
  172. NESTED_ENTRY KiConvertToGuiThread, _TEXT$00
  173. push_reg rbp ; save frame pointer
  174. END_PROLOGUE
  175. call PsConvertToGuiThread ; convert to GUI thread
  176. pop rbp ; restore frame pointer
  177. ret ;
  178. NESTED_END KiConvertToGuiThread, _TEXT$00
  179. subttl "Switch Kernel Stack"
  180. ;++
  181. ;
  182. ; PVOID
  183. ; KeSwitchKernelStack (
  184. ; IN PVOID StackBase,
  185. ; IN PVOID StackLimit
  186. ; )
  187. ;
  188. ; Routine Description:
  189. ;
  190. ; This function switches to the specified large kernel stack.
  191. ;
  192. ; N.B. This function can ONLY be called when there are no variables
  193. ; in the stack that refer to other variables in the stack, i.e.,
  194. ; there are no pointers into the stack.
  195. ;
  196. ; N.B. The address of the frame pointer used in the system service
  197. ; dispatcher is located using the trap frame.
  198. ;
  199. ; Arguments:
  200. ;
  201. ; StackBase (rcx) - Supplies a pointer to the base of the new kernel
  202. ; stack.
  203. ;
  204. ; StackLimit (rdx) - Suplies a pointer to the limit of the new kernel
  205. ; stack.
  206. ;
  207. ; Return Value:
  208. ;
  209. ; The previous stack base is returned as the function value.
  210. ;
  211. ;--
  212. SkFrame struct
  213. Fill dq ? ; fill to 8 mod 16
  214. SavedRdi dq ? ; saved register RDI
  215. SavedRsi dq ? ; saved register RSI
  216. SkFrame ends
  217. NESTED_ENTRY KeSwitchKernelStack, _TEXT$00
  218. push_reg rsi ; save nonvolatile registers
  219. push_reg rdi ;
  220. alloc_stack (sizeof SkFrame - (2 * 8)) ; allocate stack frame
  221. END_PROLOGUE
  222. ;
  223. ; Save the address of the new stack and copy the current stack to the new
  224. ; stack.
  225. ;
  226. mov r8, rcx ; save new stack base address
  227. mov r10, gs:[PcCurrentThread] ; get current thread address
  228. mov rcx, ThStackBase[r10] ; get current stack base address
  229. mov r9, ThTrapFrame[r10] ; get current trap frame address
  230. sub r9, rcx ; relocate trap frame address
  231. add r9, r8 ;
  232. mov ThTrapFrame[r10], r9 ; set new trap frame address
  233. sub rcx, rsp ; compute length of copy in bytes
  234. mov rdi, r8 ; compute destination address of copy
  235. sub rdi, rcx ;
  236. mov r9, rdi ; save new stack pointer address
  237. mov rsi, rsp ; set source address of copy
  238. shr rcx, 3 ; compute length of copy on quadwords
  239. rep movsq ; copy old stack to new stack
  240. mov rcx, ThTrapFrame[r10] ; get new trap frame address
  241. lea rax, 128[rcx] ; compute new frame address
  242. mov (-2 * 8)[rcx], rax ; set relocated frame pointer
  243. ;
  244. ; Switch to the new kernel stack and return the address of the old kernel
  245. ; stack.
  246. ;
  247. mov rax, ThStackBase[r10] ; get current stack base address
  248. cli ; disable interrupts
  249. mov byte ptr ThLargeStack[r10], 1 ; set large stack TRUE
  250. mov ThStackBase[r10], r8 ; set new stack base address
  251. sub r8, LEGACY_SAVE_AREA_LENGTH ; compute initial stack address
  252. mov ThInitialStack[r10], r8 ; set new initial stack address
  253. mov ThStackLimit[r10], rdx ; set new stack limit address
  254. mov r10, gs:[PcTss] ; get processor TSS address
  255. mov TssRsp0[r10], r8 ; set initial stack address in TSS
  256. mov rsp, r9 ; set new stack pointer address
  257. sti ;
  258. add rsp, sizeof SkFrame - (2 * 8) ; deallocate stack frame
  259. pop rdi ; restore nonvolatile registers
  260. pop rsi ;
  261. ret ; return
  262. NESTED_END KeSwitchKernelStack, _TEXT$00
  263. subttl "Return from User Mode Callback"
  264. ;++
  265. ;
  266. ; NTSTATUS
  267. ; NtCallbackReturn (
  268. ; IN PVOID OutputBuffer OPTIONAL,
  269. ; IN ULONG OutputLength,
  270. ; IN NTSTATUS Status
  271. ; )
  272. ;
  273. ; Routine Description:
  274. ;
  275. ; This function returns from a user mode callout to the kernel
  276. ; mode caller of the user mode callback function.
  277. ;
  278. ; N.B. This function returns to the function that called out to user
  279. ; mode and the KiCallUserMode function calls out to user mode.
  280. ; Therefore, the stack layout must be consistent between the
  281. ; two routines.
  282. ;
  283. ; Arguments:
  284. ;
  285. ; OutputBuffer (rcx) - Supplies an optional pointer to an output buffer.
  286. ;
  287. ; OutputLength (rdx) - Supplies the length of the output buffer.
  288. ;
  289. ; Status (r8) - Supplies the status value returned to the caller of the
  290. ; callback function.
  291. ;
  292. ; Return Value:
  293. ;
  294. ; If the callback return cannot be executed, then an error status is
  295. ; returned. Otherwise, the specified callback status is returned to
  296. ; the caller of the callback function.
  297. ;
  298. ; N.B. This function returns to the function that called out to user
  299. ; mode is a callout is currently active.
  300. ;
  301. ;--
  302. LEAF_ENTRY NtCallbackReturn, _TEXT$00
  303. mov r11, gs:[PcCurrentThread] ; get current thread address
  304. mov r10, ThCallbackStack[r11] ; get callback stack address
  305. cmp r10, 0 ; check if callback active
  306. je KiCb10 ; if zero, callback not active
  307. mov rax, r8 ; save completion status
  308. ;
  309. ; Store the output buffer address and length.
  310. ;
  311. mov r9, CuOutputBuffer[r10] ; get address to store output buffer
  312. mov [r9], rcx ; store output buffer address
  313. mov r9, CuOutputLength[r10] ; get address to store output length
  314. mov [r9], edx ; store output buffer length
  315. ;
  316. ; Restore the previous callback stack address and trap frame address.
  317. ;
  318. cli ; disable interrupts
  319. mov r8, CuTrapFrame[r10] ; get previous trap frame address
  320. mov ThTrapFrame[r11], r8 ; restore previous trap frame address
  321. test byte ptr TrDr7[r8], DR7_ACTIVE ; test if previous debug active
  322. setnz byte ptr ThDebugActive[r11] ; set correct thread debug active
  323. mov r8, CuCallbackStack[r10] ; get previous callback stack address
  324. mov ThCallbackStack[r11], r8 ; restore previous callback stack address
  325. ;
  326. ; Restore initial stack address.
  327. ;
  328. mov r9, CuInitialStack[r10] ; get previous initial stack address
  329. mov ThInitialStack[r11], r9 ; restore initial stack address
  330. mov r8, gs:[PcTss] ; get processor TSS address
  331. mov TssRsp0[r8], r9 ; set initial stack address in TSS
  332. mov rsp, r10 ; trim stack back to callback frame
  333. RESTORE_EXCEPTION_STATE <Rbp> ; restore exception state/deallocate
  334. sti ; enable interrupts
  335. ret ; return
  336. ;
  337. ; No callback is currently active.
  338. ;
  339. KiCB10: mov eax, STATUS_NO_CALLBACK_ACTIVE ; set service status
  340. ret ; return
  341. LEAF_END NtCallbackReturn, _TEXT$00
  342. end