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.

335 lines
7.7 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. callback.c
  5. Abstract:
  6. This module implements user mode call back services.
  7. Author:
  8. William K. Cheung (wcheung) 30-Oct-1995
  9. based on David N. Cutler (davec) 29-Oct-1994
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text (PAGE, KeUserModeCallback)
  17. #pragma alloc_text (PAGE, NtW32Call)
  18. #endif
  19. NTSTATUS
  20. KeUserModeCallback (
  21. IN ULONG ApiNumber,
  22. IN PVOID InputBuffer,
  23. IN ULONG InputLength,
  24. OUT PVOID *OutputBuffer,
  25. IN PULONG OutputLength
  26. )
  27. /*++
  28. Routine Description:
  29. This function call out from kernel mode to a user mode function.
  30. Arguments:
  31. ApiNumber - Supplies the API number.
  32. InputBuffer - Supplies a pointer to a structure that is copied
  33. to the user stack.
  34. InputLength - Supplies the length of the input structure.
  35. Outputbuffer - Supplies a pointer to a variable that receives
  36. the address of the output buffer.
  37. Outputlength - Supplies a pointer to a variable that receives
  38. the length of the output buffer.
  39. Return Value:
  40. If the callout cannot be executed, then an error status is
  41. returned. Otherwise, the status returned by the callback function
  42. is returned.
  43. --*/
  44. {
  45. PUCALLOUT_FRAME CalloutFrame;
  46. ULONGLONG OldStack;
  47. ULONGLONG NewStack;
  48. ULONGLONG OldRsPFS;
  49. IA64_PFS OldStIFS;
  50. PKTRAP_FRAME TrapFrame;
  51. NTSTATUS Status;
  52. ULONG GdiBatchCount;
  53. ULONG Length;
  54. ASSERT(KeGetPreviousMode() == UserMode);
  55. ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
  56. //
  57. // Get the user mode stack pointer and attempt to copy input buffer
  58. // to the user stack.
  59. //
  60. TrapFrame = KeGetCurrentThread()->TrapFrame;
  61. OldStack = TrapFrame->IntSp;
  62. OldRsPFS = TrapFrame->RsPFS;
  63. OldStIFS.ull = TrapFrame->StIFS;
  64. try {
  65. //
  66. // Compute new user mode stack address, probe for writability,
  67. // and copy the input buffer to the user stack.
  68. //
  69. // N.B. EM requires stacks to be 16-byte aligned, therefore
  70. // the input length must be rounded up to a 16-byte boundary.
  71. //
  72. Length = (InputLength + 16 - 1 + sizeof(UCALLOUT_FRAME) + STACK_SCRATCH_AREA) & ~(16 - 1);
  73. NewStack = OldStack - Length;
  74. CalloutFrame = (PUCALLOUT_FRAME)(NewStack + STACK_SCRATCH_AREA);
  75. ProbeForWrite((PVOID)NewStack, Length, sizeof(QUAD));
  76. RtlCopyMemory(CalloutFrame + 1, InputBuffer, InputLength);
  77. //
  78. // Fill in the callout arguments.
  79. //
  80. CalloutFrame->Buffer = (PVOID)(CalloutFrame + 1);
  81. CalloutFrame->Length = InputLength;
  82. CalloutFrame->ApiNumber = ApiNumber;
  83. CalloutFrame->IntSp = OldStack;
  84. CalloutFrame->RsPFS = TrapFrame->RsPFS;
  85. CalloutFrame->BrRp = TrapFrame->BrRp;
  86. //
  87. // Always flush out the user RSE so the debugger and
  88. // unwinding work across the call out.
  89. //
  90. KeFlushUserRseState (TrapFrame);
  91. //
  92. // If an exception occurs during the probe of the user stack, then
  93. // always handle the exception and return the exception code as the
  94. // status value.
  95. //
  96. } except (EXCEPTION_EXECUTE_HANDLER) {
  97. return GetExceptionCode();
  98. }
  99. //
  100. // Set the PFS and IFS to be equal to the number of
  101. // output registers call the function that called the
  102. // system service. This makes it look like that function
  103. // called call back.
  104. //
  105. TrapFrame->RsPFS = (ULONGLONG) 0xC000000000000000i64 | (OldStIFS.sb.pfs_sof - OldStIFS.sb.pfs_sol);
  106. TrapFrame->StIFS = (ULONGLONG) 0x8000000000000000i64 | (OldStIFS.sb.pfs_sof - OldStIFS.sb.pfs_sol);
  107. //
  108. // Set the user stack.
  109. //
  110. TrapFrame->IntSp = NewStack;
  111. //
  112. // Call user mode.
  113. //
  114. Status = KiCallUserMode(OutputBuffer, OutputLength);
  115. //
  116. // When returning from user mode, any drawing done to the GDI TEB
  117. // batch must be flushed. If the TEB cannot be accessed then blindly
  118. // flush the GDI batch anyway.
  119. //
  120. GdiBatchCount = 1;
  121. try {
  122. GdiBatchCount = ((PTEB)KeGetCurrentThread()->Teb)->GdiBatchCount;
  123. } except (EXCEPTION_EXECUTE_HANDLER) {
  124. NOTHING;
  125. }
  126. if (GdiBatchCount > 0) {
  127. //
  128. // Some of the call back functions store a return values in the
  129. // stack. The batch flush routine can sometimes overwrite these
  130. // values causing failures. Add some slop in the stack to
  131. // preserve these values.
  132. //
  133. TrapFrame->IntSp -= 256;
  134. //
  135. // call GDI batch flush routine
  136. //
  137. KeGdiFlushUserBatch();
  138. }
  139. TrapFrame->IntSp = OldStack;
  140. TrapFrame->RsPFS = OldRsPFS;
  141. TrapFrame->StIFS = OldStIFS.ull;
  142. return Status;
  143. }
  144. NTSTATUS
  145. NtW32Call (
  146. IN ULONG ApiNumber,
  147. IN PVOID InputBuffer,
  148. IN ULONG InputLength,
  149. OUT PVOID *OutputBuffer,
  150. OUT PULONG OutputLength
  151. )
  152. /*++
  153. Routine Description:
  154. This function calls a W32 function.
  155. N.B. ************** This is a temporary service *****************
  156. Arguments:
  157. ApiNumber - Supplies the API number.
  158. InputBuffer - Supplies a pointer to a structure that is copied to
  159. the user stack.
  160. InputLength - Supplies the length of the input structure.
  161. Outputbuffer - Supplies a pointer to a variable that recevies the
  162. output buffer address.
  163. Outputlength - Supplies a pointer to a variable that recevies the
  164. output buffer length.
  165. Return Value:
  166. TBS.
  167. --*/
  168. {
  169. PVOID ValueBuffer;
  170. ULONG ValueLength;
  171. NTSTATUS Status;
  172. ASSERT(KeGetPreviousMode() == UserMode);
  173. //
  174. // If the current thread is not a GUI thread, then fail the service
  175. // since the thread does not have a large stack.
  176. //
  177. if (KeGetCurrentThread()->Win32Thread == (PVOID)&KeServiceDescriptorTable[0]) {
  178. return STATUS_NOT_IMPLEMENTED;
  179. }
  180. //
  181. // Probe the output buffer address and length for writeability.
  182. //
  183. try {
  184. ProbeForWriteUlong((PULONG)OutputBuffer);
  185. ProbeForWriteUlong(OutputLength);
  186. //
  187. // If an exception occurs during the probe of the output buffer or
  188. // length, then always handle the exception and return the exception
  189. // code as the status value.
  190. //
  191. } except(EXCEPTION_EXECUTE_HANDLER) {
  192. return GetExceptionCode();
  193. }
  194. //
  195. // Call out to user mode specifying the input buffer and API number.
  196. //
  197. Status = KeUserModeCallback(ApiNumber,
  198. InputBuffer,
  199. InputLength,
  200. &ValueBuffer,
  201. &ValueLength);
  202. //
  203. // If the callout is successful, then the output buffer address and
  204. // length.
  205. //
  206. if (NT_SUCCESS(Status)) {
  207. try {
  208. *OutputBuffer = ValueBuffer;
  209. *OutputLength = ValueLength;
  210. } except(EXCEPTION_EXECUTE_HANDLER) {
  211. }
  212. }
  213. return Status;
  214. }
  215. VOID
  216. KiTestGdiBatchCount (
  217. )
  218. /*++
  219. Routine Description:
  220. This function checks the GdiBatchCount and calls KeGdiFlushUserBatch if necessary.
  221. Arguments:
  222. None.
  223. Return Value:
  224. None.
  225. --*/
  226. {
  227. ULONG GdiBatchCount = 1;
  228. try {
  229. GdiBatchCount = ((PTEB)KeGetCurrentThread()->Teb)->GdiBatchCount;
  230. } except (EXCEPTION_EXECUTE_HANDLER) {
  231. NOTHING;
  232. }
  233. if (GdiBatchCount > 0) {
  234. KeGdiFlushUserBatch();
  235. }
  236. }