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.

324 lines
7.1 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. ULONGLONG OldStIFS;
  50. PKTRAP_FRAME TrapFrame;
  51. NTSTATUS Status;
  52. ULONG GdiBatchCount;
  53. ULONG Length;
  54. SHORT BsFrameSize;
  55. USHORT TearPointOffset;
  56. ASSERT(KeGetPreviousMode() == UserMode);
  57. ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
  58. //
  59. // Get the user mode stack pointer and attempt to copy input buffer
  60. // to the user stack.
  61. //
  62. TrapFrame = KeGetCurrentThread()->TrapFrame;
  63. OldStack = TrapFrame->IntSp;
  64. OldRsPFS = TrapFrame->RsPFS;
  65. OldStIFS = TrapFrame->StIFS;
  66. try {
  67. //
  68. // Compute new user mode stack address, probe for writability,
  69. // and copy the input buffer to the user stack.
  70. //
  71. // N.B. EM requires stacks to be 16-byte aligned, therefore
  72. // the input length must be rounded up to a 16-byte boundary.
  73. //
  74. Length = (InputLength + 16 - 1 + sizeof(UCALLOUT_FRAME) + STACK_SCRATCH_AREA) & ~(16 - 1);
  75. NewStack = OldStack - Length;
  76. CalloutFrame = (PUCALLOUT_FRAME)(NewStack + STACK_SCRATCH_AREA);
  77. ProbeForWrite((PVOID)NewStack, Length, sizeof(QUAD));
  78. RtlCopyMemory(CalloutFrame + 1, InputBuffer, InputLength);
  79. //
  80. // Fill in the callout arguments.
  81. //
  82. CalloutFrame->Buffer = (PVOID)(CalloutFrame + 1);
  83. CalloutFrame->Length = InputLength;
  84. CalloutFrame->ApiNumber = ApiNumber;
  85. CalloutFrame->IntSp = OldStack;
  86. CalloutFrame->RsPFS = TrapFrame->RsPFS;
  87. CalloutFrame->BrRp = TrapFrame->BrRp;
  88. //
  89. // Always flush out the user RSE so the debugger and
  90. // unwinding work across the call out.
  91. //
  92. KeFlushUserRseState (TrapFrame);
  93. //
  94. // If an exception occurs during the probe of the user stack, then
  95. // always handle the exception and return the exception code as the
  96. // status value.
  97. //
  98. } except (EXCEPTION_EXECUTE_HANDLER) {
  99. return GetExceptionCode();
  100. }
  101. //
  102. // Call user mode.
  103. //
  104. TrapFrame->RsPFS = 0xC000000000000000i64;
  105. TrapFrame->StIFS = 0x8000000000000000i64;
  106. TrapFrame->IntSp = NewStack;
  107. Status = KiCallUserMode(OutputBuffer, OutputLength);
  108. //
  109. // When returning from user mode, any drawing done to the GDI TEB
  110. // batch must be flushed. If the TEB cannot be accessed then blindly
  111. // flush the GDI batch anyway.
  112. //
  113. GdiBatchCount = 1;
  114. try {
  115. GdiBatchCount = ((PTEB)KeGetCurrentThread()->Teb)->GdiBatchCount;
  116. } except (EXCEPTION_EXECUTE_HANDLER) {
  117. NOTHING;
  118. }
  119. if (GdiBatchCount > 0) {
  120. //
  121. // Some of the call back functions store a return values in the
  122. // stack. The batch flush routine can sometimes overwrite these
  123. // values causing failures. Add some slop in the stack to
  124. // preserve these values.
  125. //
  126. TrapFrame->IntSp -= 256;
  127. //
  128. // call GDI batch flush routine
  129. //
  130. KeGdiFlushUserBatch();
  131. }
  132. TrapFrame->IntSp = OldStack;
  133. TrapFrame->RsPFS = OldRsPFS;
  134. TrapFrame->StIFS = OldStIFS;
  135. return Status;
  136. }
  137. NTSTATUS
  138. NtW32Call (
  139. IN ULONG ApiNumber,
  140. IN PVOID InputBuffer,
  141. IN ULONG InputLength,
  142. OUT PVOID *OutputBuffer,
  143. OUT PULONG OutputLength
  144. )
  145. /*++
  146. Routine Description:
  147. This function calls a W32 function.
  148. N.B. ************** This is a temporary service *****************
  149. Arguments:
  150. ApiNumber - Supplies the API number.
  151. InputBuffer - Supplies a pointer to a structure that is copied to
  152. the user stack.
  153. InputLength - Supplies the length of the input structure.
  154. Outputbuffer - Supplies a pointer to a variable that recevies the
  155. output buffer address.
  156. Outputlength - Supplies a pointer to a variable that recevies the
  157. output buffer length.
  158. Return Value:
  159. TBS.
  160. --*/
  161. {
  162. PVOID ValueBuffer;
  163. ULONG ValueLength;
  164. NTSTATUS Status;
  165. ASSERT(KeGetPreviousMode() == UserMode);
  166. //
  167. // If the current thread is not a GUI thread, then fail the service
  168. // since the thread does not have a large stack.
  169. //
  170. if (KeGetCurrentThread()->Win32Thread == (PVOID)&KeServiceDescriptorTable[0]) {
  171. return STATUS_NOT_IMPLEMENTED;
  172. }
  173. //
  174. // Probe the output buffer address and length for writeability.
  175. //
  176. try {
  177. ProbeForWriteUlong((PULONG)OutputBuffer);
  178. ProbeForWriteUlong(OutputLength);
  179. //
  180. // If an exception occurs during the probe of the output buffer or
  181. // length, then always handle the exception and return the exception
  182. // code as the status value.
  183. //
  184. } except(EXCEPTION_EXECUTE_HANDLER) {
  185. return GetExceptionCode();
  186. }
  187. //
  188. // Call out to user mode specifying the input buffer and API number.
  189. //
  190. Status = KeUserModeCallback(ApiNumber,
  191. InputBuffer,
  192. InputLength,
  193. &ValueBuffer,
  194. &ValueLength);
  195. //
  196. // If the callout is successful, then the output buffer address and
  197. // length.
  198. //
  199. if (NT_SUCCESS(Status)) {
  200. try {
  201. *OutputBuffer = ValueBuffer;
  202. *OutputLength = ValueLength;
  203. } except(EXCEPTION_EXECUTE_HANDLER) {
  204. }
  205. }
  206. return Status;
  207. }
  208. VOID
  209. KiTestGdiBatchCount (
  210. )
  211. /*++
  212. Routine Description:
  213. This function checks the GdiBatchCount and calls KeGdiFlushUserBatch if necessary.
  214. Arguments:
  215. None.
  216. Return Value:
  217. None.
  218. --*/
  219. {
  220. ULONG GdiBatchCount = 1;
  221. try {
  222. GdiBatchCount = ((PTEB)KeGetCurrentThread()->Teb)->GdiBatchCount;
  223. } except (EXCEPTION_EXECUTE_HANDLER) {
  224. NOTHING;
  225. }
  226. if (GdiBatchCount > 0) {
  227. KeGdiFlushUserBatch();
  228. }
  229. }