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.

451 lines
16 KiB

  1. title "Call Out to User Mode"
  2. ;++
  3. ;
  4. ; Copyright (c) 1994 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) 1-Nov-1994
  18. ;
  19. ; Environment:
  20. ;
  21. ; Kernel mode only.
  22. ;
  23. ; Revision History:
  24. ;
  25. ;--
  26. .386p
  27. .xlist
  28. include ks386.inc
  29. include i386\kimacro.inc
  30. include callconv.inc
  31. .list
  32. extrn _KiServiceExit:PROC
  33. extrn _KeUserCallbackDispatcher:DWORD
  34. EXTRNP _MmGrowKernelStack,1
  35. _TEXT SEGMENT DWORD PUBLIC 'CODE'
  36. ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
  37. page ,132
  38. subttl "Call User Mode Function"
  39. ;++
  40. ;
  41. ; NTSTATUS
  42. ; KiCallUserMode (
  43. ; IN PVOID *Outputbuffer,
  44. ; IN PULONG OutputLength
  45. ; )
  46. ;
  47. ; Routine Description:
  48. ;
  49. ; This function calls a user mode function from kernel mode.
  50. ;
  51. ; N.B. This function calls out to user mode and the NtCallbackReturn
  52. ; function returns back to the caller of this function. Therefore,
  53. ; the stack layout must be consistent between the two routines.
  54. ;
  55. ; Arguments:
  56. ;
  57. ; OutputBuffer - Supplies a pointer to the variable that receivies
  58. ; the address of the output buffer.
  59. ;
  60. ; OutputLength - Supplies a pointer to a variable that receives
  61. ; the length of the output buffer.
  62. ;
  63. ; Return Value:
  64. ;
  65. ; The final status of the call out function is returned as the status
  66. ; of the function.
  67. ;
  68. ; N.B. This function does not return to its caller. A return to the
  69. ; caller is executed when a NtCallbackReturn system service is
  70. ; executed.
  71. ;
  72. ; N.B. This function does return to its caller if a kernel stack
  73. ; expansion is required and the attempted expansion fails.
  74. ;
  75. ;--
  76. ;
  77. ; To support the debugger, the callback stack frame is now defined in i386.h.
  78. ; If the stack frame is changed, i386.h must be updated and geni386
  79. ; rebuilt and run, then rebuild this file and ntos\kd.
  80. ;
  81. ; The FPO record below must also be updated to correctly represent
  82. ; the stack frame.
  83. ;
  84. cPublicProc _KiCallUserMode, 2
  85. .FPO (3, 2, 4, 4, 0, 0)
  86. ;
  87. ; Save nonvolatile registers.
  88. ;
  89. push ebp ; save nonvolatile registers
  90. push ebx ;
  91. push esi ;
  92. push edi ;
  93. ;
  94. ; Check if sufficient room is available on the kernel stack for another
  95. ; system call.
  96. ;
  97. mov ebx,PCR[PcPrcbData + PbCurrentThread] ; get current thread address
  98. lea eax,[esp]-KERNEL_LARGE_STACK_COMMIT ; compute bottom address
  99. cmp eax,[ebx]+ThStackLimit ; check if limit exceeded
  100. jae short Kcb10 ; if ae, limit not exceeded
  101. stdCall _MmGrowKernelStack,<esp> ; attempt to grow kernel stack
  102. or eax, eax ; check for successful completion
  103. jne Kcb20 ; if ne, attempt to grow failed
  104. ;
  105. ; Get the address of the current thread and save the previous trap frame
  106. ; and calback stack addresses in the current frame. Also save the new
  107. ; callback stack address in the thread object.
  108. ;
  109. Kcb10: push [ebx].ThCallbackStack ; save callback stack address
  110. mov edx,[ebx].ThTrapFrame ; get current trap frame address
  111. push edx ; save trap frame address
  112. mov esi,[ebx].ThInitialStack ; get initial stack address
  113. push esi ; save initial stack address
  114. mov [ebx].ThCallbackStack,esp ; save callback stack address
  115. KcbPrologEnd: ; help for the debugger
  116. ;
  117. ; Copy the numeric save area from the previous save area to the new save
  118. ; area and establish a new initial kernel stack.
  119. ;
  120. ;
  121. ; Make sure that the destination NPX Save area is 16-byte aligned
  122. ; as required by fxsave\fxrstor
  123. ;
  124. and esp, 0fffffff0h
  125. mov edi,esp ; set new initial stack address
  126. sub esp,NPX_FRAME_LENGTH ; compute destination NPX save area
  127. sub esi,NPX_FRAME_LENGTH ; compute source NPX save area
  128. cli ; disable interrupts
  129. mov ecx,[esi].FpControlWord ; copy NPX state to new frame
  130. mov [esp].FpControlWord,ecx ;
  131. mov ecx,[esi].FpStatusWord ;
  132. mov [esp].FpStatusWord,ecx ;
  133. mov ecx,[esi].FpTagWord ;
  134. mov [esp].FpTagWord,ecx ;
  135. mov ecx,[esi].FxMXCsr ;
  136. mov [esp].FxMXCsr,ecx ;
  137. mov ecx,[esi].FpCr0NpxState ;
  138. mov [esp].FpCr0NpxState,ecx ;
  139. mov esi,PCR[PcTss] ; get address of task switch segment
  140. mov [ebx].ThInitialStack,edi ; reset initial stack address
  141. mov ecx, esp
  142. sub esp,TsV86Gs - TsHardwareSegSs ; bias for missing V86 fields
  143. test dword ptr [edx].TsEFlags,EFLAGS_V86_MASK ; is this a V86 frame?
  144. jne @f
  145. mov ecx, esp ; Use adjusted esp (normal case)
  146. @@: mov [esi].TssEsp0,ecx ; set kernel entry stack address
  147. ;
  148. ; Construct a trap frame to facilitate the transfer into user mode via
  149. ; the standard system call exit.
  150. ;
  151. sub esp,TsHardwareSegSs + 4 ; allocate trap frame
  152. mov ebp,esp ; set address of trap frame
  153. mov ecx,(TsHardwareSegSs - TsSegFs + 4) / 4; set repeat count
  154. lea edi,[esp].TsSegFs ; set destination address
  155. lea esi,[edx].TsSegFs ; set source address
  156. rep movsd ; copy trap information
  157. mov edi, [edx].TsDr7 ; Fetch control register
  158. test edi, DR7_ACTIVE ; Do we need to restore Debug reg?
  159. mov [esp].TsDr7, edi ; Save away Dr7
  160. jnz short Kcb18 ; Yes, go save them.
  161. Kcb15: mov eax,_KeUserCallbackDispatcher ; st address of callback dispatchr
  162. mov [esp].TsEip,eax ;
  163. mov eax,PCR[PcExceptionList] ; get current exception list
  164. mov [esp].TsExceptionList,eax ; set previous exception list
  165. mov eax,[edx].TsPreviousPreviousMode ; get previous mode
  166. mov [esp].TsPreviousPreviousMode,eax ; set previous mode
  167. sti ; enable interrupts
  168. SET_DEBUG_DATA ; set system call debug data for exit
  169. jmp _KiServiceExit ; exit through service dispatch
  170. Kcb18:
  171. mov ecx,(TsDr6 - TsDr0 + 4) / 4; set repeat count
  172. lea edi,[esp].TsDr0 ; set destination address
  173. lea esi,[edx].TsDr0 ; set source address
  174. rep movsd ; copy trap information
  175. jmp short Kcb15
  176. ;
  177. ; An attempt to grow the kernel stack failed.
  178. ;
  179. Kcb20: pop edi ; restore nonvolitile register
  180. pop esi ;
  181. pop ebx ;
  182. pop ebp ;
  183. stdRET _KiCallUserMode
  184. stdENDP _KiCallUserMode
  185. page ,132
  186. subttl "Switch Kernel Stack"
  187. ;++
  188. ;
  189. ; PVOID
  190. ; KeSwitchKernelStack (
  191. ; IN PVOID StackBase,
  192. ; IN PVOID StackLimit
  193. ; )
  194. ;
  195. ; Routine Description:
  196. ;
  197. ; This function switches to the specified large kernel stack.
  198. ;
  199. ; N.B. This function can ONLY be called when there are no variables
  200. ; in the stack that refer to other variables in the stack, i.e.,
  201. ; there are no pointers into the stack.
  202. ;
  203. ; Arguments:
  204. ;
  205. ; StackBase (esp + 4) - Supplies a pointer to the base of the new kernel
  206. ; stack.
  207. ;
  208. ; StackLimit (esp + 8) - Suplies a pointer to the limit of the new kernel
  209. ; stack.
  210. ;
  211. ; Return Value:
  212. ;
  213. ; The old kernel stack is returned as the function value.
  214. ;
  215. ;--
  216. SsStkBs equ 4 ; new kernel stack base address
  217. SsStkLm equ 8 ; new kernel stack limit address
  218. cPublicProc _KeSwitchKernelStack, 2
  219. ;
  220. ; Save the address of the new stack and copy the old stack to the new
  221. ; stack.
  222. ;
  223. push esi ; save string move registers
  224. push edi ;
  225. mov edx,PCR[PcPrcbData + PbCurrentThread] ; get current thread address
  226. mov edi,[esp]+SsStkBs + 8 ; get new kernel stack base address
  227. mov ecx,[edx].ThStackBase ; get current stack base address
  228. sub ebp,ecx ; relocate the callers frame pointer
  229. add ebp,edi ;
  230. mov eax,[edx].ThTrapFrame ; relocate the current trap frame address
  231. sub eax,ecx ;
  232. add eax,edi ;
  233. mov [edx].ThTrapFrame,eax ;
  234. sub ecx,esp ; compute length of copy
  235. sub edi,ecx ; set destination address of copy
  236. mov esi,esp ; set source address of copy
  237. push edi ; save new stack pointer address
  238. rep movsb ; copy old stack to new stack
  239. pop edi ; restore new stack pointer address
  240. ;
  241. ; Switch to the new kernel stack and return the address of the old kernel
  242. ; stack.
  243. ;
  244. mov eax,[edx].ThStackBase ; get old kernel stack base address
  245. mov ecx,[esp]+SsStkBs + 8 ; get new kernel stack base address
  246. mov esi,[esp]+SsStkLm + 8 ; get new kernel stack limit address
  247. cli ; disable interrupts
  248. mov [edx].ThStackBase,ecx ; set new kernel stack base address
  249. mov [edx].ThStackLimit,esi ; set new kernel stack limit address
  250. mov byte ptr [edx].ThLargeStack, 1 ; set large stack TRUE
  251. mov [edx].ThInitialStack,ecx ; set new initial stack address
  252. sub ecx,NPX_FRAME_lENGTH ; compute NPX save area address
  253. mov esi,[edx].ThTrapFrame ; Get current trap frame address
  254. mov edx,PCR[PcTss] ; get address of task switch segment
  255. test dword ptr [esi]+TsEFlags,EFLAGS_V86_MASK ; is this a V86 frame?
  256. jne @f
  257. sub ecx,TsV86Gs - TsHardwareSegSs ; bias for missing V86 fields
  258. @@: mov [edx].TssEsp0,ecx ; set kernel entry stack address
  259. mov esp,edi ; set new stack pointer address
  260. sti ;
  261. pop edi ; restore string move registers
  262. pop esi ;
  263. stdRET _KeSwitchKernelStack
  264. stdENDP _KeSwitchKernelStack
  265. page ,132
  266. subttl "Get User Mode Stack Address"
  267. ;++
  268. ;
  269. ; PULONG
  270. ; KiGetUserModeStackAddress (
  271. ; VOID
  272. ; )
  273. ;
  274. ; Routine Description:
  275. ;
  276. ; This function returns the address of the user stack address in the
  277. ; current trap frame.
  278. ;
  279. ; Arguments:
  280. ;
  281. ; None.
  282. ;
  283. ; Return Value:
  284. ;
  285. ; The address of the user stack address.
  286. ;
  287. ;--
  288. cPublicProc _KiGetUserModeStackAddress, 0
  289. mov eax,PCR[PcPrcbData + PbCurrentThread] ; get current thread address
  290. mov eax,[eax].ThTrapFrame ; get current trap frame address
  291. lea eax,[eax].TsHardwareEsp ; get address of stack address
  292. stdRET _KiGetUserModeStackAddress
  293. stdENDP _KiGetUserModeStackAddress
  294. page ,132
  295. subttl "Return from User Mode Callback"
  296. ;++
  297. ;
  298. ; NTSTATUS
  299. ; NtCallbackReturn (
  300. ; IN PVOID OutputBuffer OPTIONAL,
  301. ; IN ULONG OutputLength,
  302. ; IN NTSTATUS Status
  303. ; )
  304. ;
  305. ; Routine Description:
  306. ;
  307. ; This function returns from a user mode callout to the kernel
  308. ; mode caller of the user mode callback function.
  309. ;
  310. ; N.B. This function returns to the function that called out to user
  311. ; mode and the KiCallUserMode function calls out to user mode.
  312. ; Therefore, the stack layout must be consistent between the
  313. ; two routines.
  314. ;
  315. ; Arguments:
  316. ;
  317. ; OutputBuffer - Supplies an optional pointer to an output buffer.
  318. ;
  319. ; OutputLength - Supplies the length of the output buffer.
  320. ;
  321. ; Status - Supplies the status value returned to the caller of the
  322. ; callback function.
  323. ;
  324. ; Return Value:
  325. ;
  326. ; If the callback return cannot be executed, then an error status is
  327. ; returned. Otherwise, the specified callback status is returned to
  328. ; the caller of the callback function.
  329. ;
  330. ; N.B. This function returns to the function that called out to user
  331. ; mode is a callout is currently active.
  332. ;
  333. ;--
  334. cPublicProc _NtCallbackReturn, 3
  335. mov eax,PCR[PcPrcbData + PbCurrentThread] ; get current thread address
  336. mov ecx,[eax].ThCallbackStack ; get callback stack address
  337. test ecx, ecx
  338. je CbExit ; if zero, no callback stack present
  339. ;
  340. ; Restore the current exception list from the saved exception list in the
  341. ; current trap frame, restore the trap frame and callback stack addresses,
  342. ; store the output buffer address and length, and set the service status.
  343. ;
  344. mov ebx,[eax].ThTrapFrame ; get current trap frame address
  345. mov edx,[ebx].TsExceptionList ; get saved exception list address
  346. mov PCR[PcExceptionList],edx ; restore exception list address
  347. mov edi,[esp] + 4 ; get output buffer address
  348. mov esi,[esp] + 8 ; get output buffer length
  349. mov ebp,[esp] + 12 ; get callout service status
  350. mov ebx,[ecx].CuOutBf ; get address to store output buffer
  351. mov [ebx],edi ; store output buffer address
  352. mov ebx,[ecx].CuOutLn ; get address to store output length
  353. mov [ebx],esi ; store output buffer length
  354. mov ebx,[ecx] ; get previous initial stack address
  355. cli ; disable interrupt
  356. mov esi,[eax].ThInitialStack ; get source NPX save area address
  357. mov [eax].ThInitialStack,ebx ; restore initial stack address
  358. sub esi,NPX_FRAME_LENGTH ; compute destination NPX save area
  359. sub ebx,NPX_FRAME_LENGTH ; compute destination NPX save area
  360. mov edx,[esi].FpControlWord ; copy NPX state to previous frame
  361. mov [ebx].FpControlWord,edx ;
  362. mov edx,[esi].FpStatusWord ;
  363. mov [ebx].FpStatusWord,edx ;
  364. mov edx,[esi].FpTagWord ;
  365. mov [ebx].FpTagWord,edx ;
  366. mov edx,[esi].FxMXCsr ;
  367. mov [ebx].FxMXCsr,edx ;
  368. mov edx,[esi].FpCr0NpxState ;
  369. mov [ebx].FpCr0NpxState,edx ;
  370. mov edx,PCR[PcTss] ; get address of task switch segment
  371. lea esp, [ecx+4] ; trim stack back to callback frame
  372. pop edi
  373. test dword ptr [edi]+TsEFlags,EFLAGS_V86_MASK ; is this a V86 frame?
  374. jne @f
  375. sub ebx,TsV86Gs - TsHardwareSegSs ; bias for missing V86 fields
  376. @@: test [edi].TsDr7, DR7_ACTIVE
  377. mov [edx].TssEsp0,ebx ; restore kernel entry stack address
  378. setnz byte ptr [eax].ThDebugActive ; Set debug active to match saved DR7
  379. mov [eax].ThTrapFrame, edi ; restore current trap frame address
  380. sti ; enable interrupts
  381. pop [eax].ThCallbackStack ; restore callback stack address
  382. mov eax,ebp ; set callback service status
  383. ;
  384. ; Restore nonvolatile registers, clean call parameters from stack, and
  385. ; return to callback caller.
  386. ;
  387. pop edi ; restore nonvolatile registers
  388. pop esi ;
  389. pop ebx ;
  390. pop ebp ;
  391. pop edx ; save return address
  392. add esp,8 ; remove parameters from stack
  393. jmp edx ; return to callback caller
  394. ;
  395. ; No callback is currently active.
  396. ;
  397. CbExit: mov eax,STATUS_NO_CALLBACK_ACTIVE ; set service status
  398. stdRET _NtCallBackReturn
  399. stdENDP _NtCallbackReturn
  400. _TEXT ends
  401. end