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.

318 lines
6.8 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. context.c
  5. Abstract:
  6. This module implements user mode callable context manipulation routines.
  7. The interfaces exported from this module are portable, but they must
  8. be re-implemented for each architecture.
  9. Author:
  10. David N. Cutler (davec) 13-May-2000
  11. Revision History:
  12. --*/
  13. #include "ntrtlp.h"
  14. #if defined(NTOS_KERNEL_RUNTIME)
  15. #pragma alloc_text(PAGE, RtlInitializeContext)
  16. #pragma alloc_text(PAGE, RtlRemoteCall)
  17. #endif
  18. VOID
  19. RtlInitializeContext(
  20. IN HANDLE Process,
  21. OUT PCONTEXT Context,
  22. IN PVOID Parameter OPTIONAL,
  23. IN PVOID InitialPc OPTIONAL,
  24. IN PVOID InitialSp OPTIONAL
  25. )
  26. /*++
  27. Routine Description:
  28. This function initializes a context record so that it can be used in a
  29. subsequent call to create thread.
  30. Arguments:
  31. Process - Supplies a handle to the process in which a thread is being
  32. created.
  33. Context - Supplies a pointer to a context record.
  34. InitialPc - Supplies an initial program counter value.
  35. InitialSp - Supplies an initial stack pointer value.
  36. Return Value:
  37. STATUS_BAD_INITIAL_STACK is raised if initial stack pointer value is not
  38. properly aligned.
  39. --*/
  40. {
  41. RTL_PAGED_CODE();
  42. //
  43. // Check stack alignment.
  44. //
  45. if (((ULONG64)InitialSp & 0xf) != 0) {
  46. RtlRaiseStatus(STATUS_BAD_INITIAL_STACK);
  47. }
  48. //
  49. // Initialize the EFflags field.
  50. //
  51. Context->EFlags = EFLAGS_IF_MASK | EFLAGS_AC_MASK;
  52. //
  53. // Initialize the integer registers.
  54. //
  55. Context->Rax = 0L;
  56. Context->Rcx = 2L;
  57. Context->Rbx = 1L;
  58. Context->Rsp = (ULONG64)InitialSp;
  59. Context->Rbp = 0L;
  60. Context->Rsi = 4L;
  61. Context->Rdi = 5L;
  62. Context->R8 = 8;
  63. Context->R9 = 9;
  64. Context->R10 = 10;
  65. Context->R11 = 11;
  66. Context->R12 = 12;
  67. Context->R13 = 13;
  68. Context->R14 = 14;
  69. Context->R15 = 15;
  70. //
  71. // Initialize the floating registers.
  72. //
  73. Context->Xmm0.Low = 0;
  74. Context->Xmm0.High = 0;
  75. Context->Xmm1.Low = 1;
  76. Context->Xmm1.High = 1;
  77. Context->Xmm2.Low = 2;
  78. Context->Xmm2.High = 2;
  79. Context->Xmm3.Low = 3;
  80. Context->Xmm3.High = 3;
  81. Context->Xmm4.Low = 4;
  82. Context->Xmm4.High = 4;
  83. Context->Xmm5.Low = 5;
  84. Context->Xmm5.High = 5;
  85. Context->Xmm6.Low = 6;
  86. Context->Xmm6.High = 6;
  87. Context->Xmm7.Low = 7;
  88. Context->Xmm7.High = 7;
  89. Context->Xmm8.Low = 8;
  90. Context->Xmm8.High = 8;
  91. Context->Xmm9.Low = 9;
  92. Context->Xmm9.High = 9;
  93. Context->Xmm10.Low = 10;
  94. Context->Xmm10.High = 10;
  95. Context->Xmm11.Low = 11;
  96. Context->Xmm11.High = 11;
  97. Context->Xmm12.Low = 12;
  98. Context->Xmm12.High = 12;
  99. Context->Xmm13.Low = 13;
  100. Context->Xmm13.High = 13;
  101. Context->Xmm14.Low = 14;
  102. Context->Xmm14.High = 14;
  103. Context->Xmm15.Low = 15;
  104. Context->Xmm15.High = 15;
  105. Context->MxCsr = INITIAL_MXCSR;
  106. //
  107. // Initialize the lagacy floatin point.
  108. //
  109. Context->FltSave.ControlWord = 0x23f;
  110. Context->FltSave.StatusWord = 0;
  111. Context->FltSave.TagWord = 0xffff;
  112. Context->FltSave.ErrorOffset = 0;
  113. Context->FltSave.ErrorSelector = 0;
  114. Context->FltSave.ErrorOpcode = 0;
  115. Context->FltSave.DataOffset = 0;
  116. Context->FltSave.DataSelector = 0;
  117. //
  118. // Initialize the program counter.
  119. //
  120. Context->Rip = (ULONG64)InitialPc;
  121. //
  122. // Set context record flags.
  123. //
  124. Context->ContextFlags = CONTEXT_FULL;
  125. //
  126. // Set the initial context of the thread in a machine specific way.
  127. //
  128. Context->Rcx = (ULONG64)Parameter;
  129. return;
  130. }
  131. NTSTATUS
  132. RtlRemoteCall(
  133. HANDLE Process,
  134. HANDLE Thread,
  135. PVOID CallSite,
  136. ULONG ArgumentCount,
  137. PULONG_PTR Arguments,
  138. BOOLEAN PassContext,
  139. BOOLEAN AlreadySuspended
  140. )
  141. /*++
  142. Routine Description:
  143. This function calls a procedure in another thread/process, using the
  144. system functins NtGetContext and NtSetContext. Parameters are passed
  145. to the target procedure via the nonvolatile registers ().
  146. Arguments:
  147. Process - Supplies an open handle to the target process.
  148. Thread - Supplies an open handle to the target thread within the target
  149. process.
  150. CallSite - Supplies the address of the procedure to call in the target
  151. process.
  152. ArgumentCount - Supplies the number of parameters to pass to the target
  153. procedure.
  154. Arguments - Supplies a pointer to the array of parameters to pass.
  155. PassContext - Supplies a boolean value that determines whether a parameter
  156. is to be passed that points to a context record.
  157. AlreadySuspended - Supplies a boolean value that determines whether the
  158. target thread is already in a suspended or waiting state.
  159. Return Value:
  160. Status - Status value
  161. --*/
  162. {
  163. CONTEXT Context;
  164. ULONG Index;
  165. ULONG64 NewSp;
  166. NTSTATUS Status;
  167. RTL_PAGED_CODE();
  168. //
  169. // Check if too many arguments are specified.
  170. //
  171. if (ArgumentCount > 4) {
  172. return STATUS_INVALID_PARAMETER;
  173. }
  174. //
  175. // If necessary, suspend the target thread before getting the thread's
  176. // current state.
  177. //
  178. if (AlreadySuspended == FALSE) {
  179. Status = NtSuspendThread(Thread, NULL);
  180. if (!NT_SUCCESS(Status)) {
  181. return Status;
  182. }
  183. }
  184. //
  185. // Get the current context of the target thread.
  186. //
  187. Context.ContextFlags = CONTEXT_FULL;
  188. Status = NtGetContextThread(Thread, &Context);
  189. if (!NT_SUCCESS(Status)) {
  190. if (AlreadySuspended == FALSE) {
  191. NtResumeThread(Thread, NULL);
  192. }
  193. return Status;
  194. }
  195. if (AlreadySuspended != FALSE) {
  196. Context.Rax = STATUS_ALERTED;
  197. }
  198. //
  199. // Write previous thread context into the stack of the target thread.
  200. //
  201. NewSp = Context.Rsp - sizeof(CONTEXT);
  202. Status = NtWriteVirtualMemory(Process,
  203. (PVOID)NewSp,
  204. &Context,
  205. sizeof(CONTEXT),
  206. NULL);
  207. if (!NT_SUCCESS(Status)) {
  208. if (AlreadySuspended == FALSE) {
  209. NtResumeThread(Thread, NULL);
  210. }
  211. return Status;
  212. }
  213. //
  214. // Pass the parameters to the target thread via the nonvolatile registers
  215. // R11-R15.
  216. //
  217. Context.Rsp = NewSp;
  218. if (PassContext != FALSE) {
  219. Context.R11 = NewSp;
  220. for (Index = 0; Index < ArgumentCount; Index += 1) {
  221. (&Context.R12)[Index] = Arguments[Index];
  222. }
  223. } else {
  224. for (Index = 0; Index < ArgumentCount; Index += 1) {
  225. (&Context.R11)[Index] = Arguments[Index];
  226. }
  227. }
  228. //
  229. // Set the address of the target code into RIP and set the thread context
  230. // to cause the target procedure to be executed.
  231. //
  232. Context.Rip = (ULONG64)CallSite;
  233. Status = NtSetContextThread(Thread, &Context);
  234. if (AlreadySuspended == FALSE) {
  235. NtResumeThread(Thread, NULL);
  236. }
  237. return Status;
  238. }