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.

169 lines
4.6 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. apcuser.c
  5. Abstract:
  6. This module implements the machine dependent code necessary to initialize
  7. a user mode APC.
  8. Author:
  9. David N. Cutler (davec) 23-Apr-1990
  10. Environment:
  11. Kernel mode only, IRQL APC_LEVEL.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. VOID
  16. KiInitializeUserApc (
  17. IN PKEXCEPTION_FRAME ExceptionFrame,
  18. IN PKTRAP_FRAME TrapFrame,
  19. IN PKNORMAL_ROUTINE NormalRoutine,
  20. IN PVOID NormalContext,
  21. IN PVOID SystemArgument1,
  22. IN PVOID SystemArgument2
  23. )
  24. /*++
  25. Routine Description:
  26. This function is called to initialize the context for a user mode APC.
  27. Arguments:
  28. ExceptionFrame - Supplies a pointer to an exception frame.
  29. TrapFrame - Supplies a pointer to a trap frame.
  30. NormalRoutine - Supplies a pointer to the user mode APC routine.
  31. NormalContext - Supplies a pointer to the user context for the APC
  32. routine.
  33. SystemArgument1 - Supplies the first system supplied value.
  34. SystemArgument2 - Supplies the second system supplied value.
  35. Return Value:
  36. None.
  37. --*/
  38. {
  39. EXCEPTION_RECORD ExceptionRecord;
  40. CONTEXT ContextFrame;
  41. LONG Length;
  42. ULONG UserStack;
  43. //
  44. // APCs are not defined for V86 mode; however, it is possible a
  45. // thread is trying to set it's context to V86 mode - this isn't
  46. // going to work, but we don't want to crash the system so we
  47. // check for the possibility before hand.
  48. //
  49. if (TrapFrame->EFlags & EFLAGS_V86_MASK) {
  50. return ;
  51. }
  52. //
  53. // Move machine state from trap and exception frames to the context frame.
  54. //
  55. ContextFrame.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
  56. KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame);
  57. //
  58. // Transfer the context information to the user stack, initialize the
  59. // APC routine parameters, and modify the trap frame so execution will
  60. // continue in user mode at the user mode APC dispatch routine.
  61. //
  62. try {
  63. ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode); // Assert usermode frame
  64. //
  65. // Compute length of context record and new aligned user stack pointer.
  66. //
  67. Length = ((sizeof(CONTEXT) + CONTEXT_ROUND) &
  68. ~CONTEXT_ROUND) + sizeof(KAPC_RECORD);
  69. UserStack = (ContextFrame.Esp & ~CONTEXT_ROUND) - Length;
  70. //
  71. // Probe user stack area for writability and then transfer the
  72. // context record to the user stack.
  73. //
  74. ProbeForWrite((PCHAR)UserStack, Length, CONTEXT_ALIGN);
  75. RtlCopyMemory((PULONG)(UserStack + (sizeof(KAPC_RECORD))),
  76. &ContextFrame, sizeof(CONTEXT));
  77. //
  78. // Force correct R3 selectors into TrapFrame.
  79. //
  80. TrapFrame->SegCs = SANITIZE_SEG(KGDT_R3_CODE, UserMode);
  81. TrapFrame->HardwareSegSs = SANITIZE_SEG(KGDT_R3_DATA, UserMode);
  82. TrapFrame->SegDs = SANITIZE_SEG(KGDT_R3_DATA, UserMode);
  83. TrapFrame->SegEs = SANITIZE_SEG(KGDT_R3_DATA, UserMode);
  84. TrapFrame->SegFs = SANITIZE_SEG(KGDT_R3_TEB, UserMode);
  85. TrapFrame->SegGs = 0;
  86. TrapFrame->EFlags = SANITIZE_FLAGS( ContextFrame.EFlags, UserMode );
  87. //
  88. // If thread is supposed to have IOPL, then force it on in eflags
  89. //
  90. if (KeGetCurrentThread()->Iopl) {
  91. TrapFrame->EFlags |= (EFLAGS_IOPL_MASK & -1); // IOPL = 3
  92. }
  93. //
  94. // Set the address of the user APC routine, the APC parameters, the
  95. // new frame pointer, and the new stack pointer in the current trap
  96. // frame. Set the continuation address so control will be transferred
  97. // to the user APC dispatcher.
  98. //
  99. TrapFrame->HardwareEsp = UserStack;
  100. TrapFrame->Eip = (ULONG)KeUserApcDispatcher;
  101. TrapFrame->ErrCode = 0;
  102. *((PULONG)UserStack)++ = (ULONG)NormalRoutine;
  103. *((PULONG)UserStack)++ = (ULONG)NormalContext;
  104. *((PULONG)UserStack)++ = (ULONG)SystemArgument1;
  105. *((PULONG)UserStack)++ = (ULONG)SystemArgument2;
  106. } except (KiCopyInformation(&ExceptionRecord,
  107. (GetExceptionInformation())->ExceptionRecord)) {
  108. //
  109. // Set the address of the exception to the current program address
  110. // and raise the exception by calling the exception dispatcher.
  111. //
  112. ExceptionRecord.ExceptionAddress = (PVOID)(TrapFrame->Eip);
  113. KiDispatchException(&ExceptionRecord,
  114. ExceptionFrame,
  115. TrapFrame,
  116. UserMode,
  117. TRUE);
  118. }
  119. return;
  120. }
  121.