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.

172 lines
3.6 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. PVOID ValueBuffer;
  49. ULONG ValueLength;
  50. ULONG GdiBatchCount;
  51. PEXCEPTION_REGISTRATION_RECORD ExceptionList;
  52. PTEB Teb;
  53. ASSERT(KeGetPreviousMode() == UserMode);
  54. ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
  55. //
  56. // Get the user mode stack pointer and attempt to copy input buffer
  57. // to the user stack.
  58. //
  59. UserStack = KiGetUserModeStackAddress();
  60. OldStack = *UserStack;
  61. try {
  62. //
  63. // Compute new user mode stack address, probe for writability,
  64. // and copy the input buffer to the user stack.
  65. //
  66. Length = (InputLength + sizeof(CHAR) - 1) & ~(sizeof(CHAR) - 1);
  67. NewStack = OldStack - Length;
  68. ProbeForWrite((PCHAR)(NewStack - 16), Length + 16, sizeof(CHAR));
  69. RtlCopyMemory((PVOID)NewStack, InputBuffer, Length);
  70. //
  71. // Push arguments onto user stack.
  72. //
  73. *(PULONG)(NewStack - 4) = (ULONG)InputLength;
  74. *(PULONG)(NewStack - 8) = (ULONG)NewStack;
  75. *(PULONG)(NewStack - 12) = ApiNumber;
  76. *(PULONG)(NewStack - 16) = 0;
  77. NewStack -= 16;
  78. //
  79. // Save the exception list in case another handler is defined during
  80. // the callout.
  81. //
  82. Teb = (PTEB)KeGetCurrentThread()->Teb;
  83. ExceptionList = Teb->NtTib.ExceptionList;
  84. //
  85. // Call user mode.
  86. //
  87. *UserStack = NewStack;
  88. Status = KiCallUserMode(OutputBuffer, OutputLength);
  89. //
  90. // Restore exception list.
  91. //
  92. Teb->NtTib.ExceptionList = ExceptionList;
  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. // When returning from user mode, any drawing done to the GDI TEB
  103. // batch must be flushed. If the TEB cannot be accessed then blindly
  104. // flush the GDI batch anyway.
  105. //
  106. GdiBatchCount = 1;
  107. try {
  108. GdiBatchCount = Teb->GdiBatchCount;
  109. } except (EXCEPTION_EXECUTE_HANDLER) {
  110. NOTHING;
  111. }
  112. if (GdiBatchCount > 0) {
  113. //
  114. // call GDI batch flush routine
  115. //
  116. *UserStack -= 256;
  117. KeGdiFlushUserBatch();
  118. }
  119. *UserStack = OldStack;
  120. return Status;
  121. }