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.

171 lines
3.8 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. David N. Cutler (davec) 29-Oct-1994
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "ki.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text (PAGE, KeUserModeCallback)
  16. #endif
  17. NTSTATUS
  18. KeUserModeCallback (
  19. IN ULONG ApiNumber,
  20. IN PVOID InputBuffer,
  21. IN ULONG InputLength,
  22. OUT PVOID *OutputBuffer,
  23. IN PULONG OutputLength
  24. )
  25. /*++
  26. Routine Description:
  27. This function call out from kernel mode to a user mode function.
  28. Arguments:
  29. ApiNumber - Supplies the API number.
  30. InputBuffer - Supplies a pointer to a structure that is copied
  31. to the user stack.
  32. InputLength - Supplies the length of the input structure.
  33. Outputbuffer - Supplies a pointer to a variable that receives
  34. the address of the output buffer.
  35. Outputlength - Supplies a pointer to a variable that receives
  36. the length of the output buffer.
  37. Return Value:
  38. If the callout cannot be executed, then an error status is
  39. returned. Otherwise, the status returned by the callback function
  40. is returned.
  41. --*/
  42. {
  43. ULONG Length;
  44. ULONG NewStack;
  45. ULONG OldStack;
  46. NTSTATUS Status;
  47. PULONG UserStack;
  48. ULONG GdiBatchCount;
  49. PEXCEPTION_REGISTRATION_RECORD ExceptionList;
  50. PTEB Teb;
  51. ASSERT(KeGetPreviousMode() == UserMode);
  52. ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
  53. // ASSERT(KeGetCurrentThread()->CombinedApcDisable == 0);
  54. //
  55. // Get the user mode stack pointer and attempt to copy input buffer
  56. // to the user stack.
  57. //
  58. UserStack = KiGetUserModeStackAddress();
  59. OldStack = *UserStack;
  60. try {
  61. //
  62. // Compute new user mode stack address, probe for writability,
  63. // and copy the input buffer to the user stack.
  64. //
  65. Length = InputLength;
  66. NewStack = OldStack - Length;
  67. ProbeForWrite((PCHAR)(NewStack - 16), Length + 16, sizeof(CHAR));
  68. RtlCopyMemory((PVOID)NewStack, InputBuffer, Length);
  69. //
  70. // Push arguments onto user stack.
  71. //
  72. *(PULONG)(NewStack - 4) = (ULONG)InputLength;
  73. *(PULONG)(NewStack - 8) = (ULONG)NewStack;
  74. *(PULONG)(NewStack - 12) = ApiNumber;
  75. *(PULONG)(NewStack - 16) = 0;
  76. NewStack -= 16;
  77. //
  78. // Save the exception list in case another handler is defined during
  79. // the callout.
  80. //
  81. Teb = (PTEB)KeGetCurrentThread()->Teb;
  82. ExceptionList = Teb->NtTib.ExceptionList;
  83. //
  84. // Call user mode.
  85. //
  86. *UserStack = NewStack;
  87. Status = KiCallUserMode(OutputBuffer, OutputLength);
  88. //
  89. // Restore exception list.
  90. //
  91. Teb->NtTib.ExceptionList = ExceptionList;
  92. //
  93. // If an exception occurs during the probe of the user stack, then
  94. // always handle the exception and return the exception code as the
  95. // status value.
  96. //
  97. } except (EXCEPTION_EXECUTE_HANDLER) {
  98. return GetExceptionCode();
  99. }
  100. //
  101. // When returning from user mode, any drawing done to the GDI TEB
  102. // batch must be flushed. If the TEB cannot be accessed then blindly
  103. // flush the GDI batch anyway.
  104. //
  105. GdiBatchCount = 1;
  106. try {
  107. GdiBatchCount = Teb->GdiBatchCount;
  108. } except (EXCEPTION_EXECUTE_HANDLER) {
  109. NOTHING;
  110. }
  111. if (GdiBatchCount > 0) {
  112. //
  113. // call GDI batch flush routine
  114. //
  115. *UserStack -= 256;
  116. KeGdiFlushUserBatch();
  117. }
  118. *UserStack = OldStack;
  119. return Status;
  120. }