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.

369 lines
9.6 KiB

  1. /*++
  2. Module Name:
  3. context.c
  4. Abstract:
  5. This module implements user-mode callable context manipulation routines.
  6. The interfaces exported from this module are portable, but they must
  7. be re-implemented for each architecture.
  8. Author:
  9. Revision History:
  10. Ported to the IA64
  11. 27-Feb-1996 Revised to pass arguments to target thread by injecting
  12. arguments into the backing store.
  13. --*/
  14. #include "ntrtlp.h"
  15. #include "kxia64.h"
  16. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  17. #pragma alloc_text(PAGE,RtlInitializeContext)
  18. #pragma alloc_text(PAGE,RtlRemoteCall)
  19. #endif
  20. VOID
  21. RtlInitializeContext(
  22. IN HANDLE Process,
  23. OUT PCONTEXT Context,
  24. IN PVOID Parameter OPTIONAL,
  25. IN PVOID InitialPc OPTIONAL,
  26. IN PVOID InitialSp OPTIONAL
  27. )
  28. /*++
  29. Routine Description:
  30. This function initializes a context structure so that it can
  31. be used in a subsequent call to NtCreateThread.
  32. Arguments:
  33. Context - Supplies a context buffer to be initialized by this routine.
  34. InitialPc - Supplies an initial program counter value.
  35. InitialSp - Supplies an initial stack pointer value.
  36. Return Value:
  37. Raises STATUS_BAD_INITIAL_STACK if the value of InitialSp is not properly
  38. aligned.
  39. Raises STATUS_BAD_INITIAL_PC if the value of InitialPc is not properly
  40. aligned.
  41. --*/
  42. {
  43. ULONGLONG Argument;
  44. ULONG_PTR Wow64Info;
  45. NTSTATUS Status;
  46. RTL_PAGED_CODE();
  47. //
  48. // Check for proper initial stack (0 mod 16).
  49. //
  50. if (((ULONG_PTR)InitialSp & 0xf) != 0) {
  51. RtlRaiseStatus(STATUS_BAD_INITIAL_STACK);
  52. }
  53. //
  54. // Check for proper plabel address alignment.
  55. // Assumes InitialPc points to a plabel that must be 8-byte aligned.
  56. //
  57. if (((ULONG_PTR)InitialPc & 0x7) != 0) {
  58. //
  59. // Misaligned, See if we are running in a Wow64 process
  60. //
  61. Status = ZwQueryInformationProcess(Process,
  62. ProcessWow64Information,
  63. &Wow64Info,
  64. sizeof(Wow64Info),
  65. NULL);
  66. if (NT_SUCCESS(Status) && (Wow64Info == 0))
  67. {
  68. //
  69. // Native IA64 process must not be misaligned.
  70. //
  71. RtlRaiseStatus(STATUS_BAD_INITIAL_PC);
  72. }
  73. }
  74. //
  75. // Initialize the integer and floating registers to contain zeroes.
  76. //
  77. RtlZeroMemory(Context, sizeof(CONTEXT));
  78. //
  79. // Setup integer and control context.
  80. //
  81. Context->ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
  82. Context->RsBSPSTORE = Context->IntSp = (ULONG_PTR)InitialSp;
  83. Context->IntSp -= STACK_SCRATCH_AREA;
  84. //
  85. // InitialPc is the module entry point which is a function pointer
  86. // in IA64. StIIP and IntGp are initiailized with actual IP and GP
  87. // from the plabel in LdrInitializeThunk after the loader runs.
  88. //
  89. Context->IntS1 = Context->IntS0 = Context->StIIP = (ULONG_PTR)InitialPc;
  90. Context->IntGp = 0;
  91. //
  92. // Setup FPSR, PSR, and DCR
  93. // N.B. Values to be determined.
  94. //
  95. Context->StFPSR = USER_FPSR_INITIAL;
  96. Context->StIPSR = USER_PSR_INITIAL;
  97. Context->ApDCR = USER_DCR_INITIAL;
  98. //
  99. // Set the initial context of the thread in a machine specific way.
  100. // ie, pass the initial parameter to the RSE by saving it at the
  101. // bottom of the backing store.
  102. //
  103. // Setup Frame Marker after RFI
  104. // And other RSE states.
  105. //
  106. Argument = (ULONGLONG)Parameter;
  107. ZwWriteVirtualMemory(Process,
  108. (PVOID)((ULONG_PTR)Context->RsBSPSTORE),
  109. (PVOID)&Argument,
  110. sizeof(Argument),
  111. NULL);
  112. //
  113. // N.b. The IFS must be reinitialized in LdrInitializeThunk
  114. //
  115. Context->StIFS = 0x8000000000000081ULL; // Valid, 1 local register, 0 output register
  116. Context->RsBSP = Context->RsBSPSTORE;
  117. Context->RsRSC = USER_RSC_INITIAL;
  118. Context->ApUNAT = 0xFFFFFFFFFFFFFFFF;
  119. }
  120. NTSTATUS
  121. RtlRemoteCall(
  122. HANDLE Process,
  123. HANDLE Thread,
  124. PVOID CallSite,
  125. ULONG ArgumentCount,
  126. PULONG_PTR Arguments,
  127. BOOLEAN PassContext,
  128. BOOLEAN AlreadySuspended
  129. )
  130. /*++
  131. Routine Description:
  132. This function calls a procedure in another thread/process, using
  133. NtGetContext and NtSetContext. Parameters are passed to the
  134. target procedure via its stack.
  135. Arguments:
  136. Process - Handle of the target process
  137. Thread - Handle of the target thread within that process
  138. CallSite - Address of the procedure to call in the target process.
  139. ArgumentCount - Number of parameters to pass to the target
  140. procedure.
  141. Arguments - Pointer to the array of parameters to pass.
  142. PassContext - TRUE if an additional parameter is to be passed that
  143. points to a context record.
  144. AlreadySuspended - TRUE if the target thread is already in a suspended
  145. or waiting state.
  146. Return Value:
  147. Status - Status value
  148. --*/
  149. {
  150. NTSTATUS Status;
  151. CONTEXT Context;
  152. ULONG_PTR ContextAddress;
  153. ULONG_PTR NewSp;
  154. ULONG_PTR NewBsp;
  155. ULONGLONG ArgumentsCopy[9];
  156. PVOID ptr;
  157. ULONG ShiftCount;
  158. ULONG Count = 0;
  159. RTL_PAGED_CODE();
  160. if ((ArgumentCount > 8) || (PassContext && (ArgumentCount > 7))) {
  161. return STATUS_INVALID_PARAMETER;
  162. }
  163. //
  164. // If necessary, suspend the guy before with we mess with his stack.
  165. //
  166. if (AlreadySuspended == FALSE) {
  167. Status = NtSuspendThread(Thread, NULL);
  168. if (NT_SUCCESS(Status) == FALSE) {
  169. return(Status);
  170. }
  171. }
  172. //
  173. // Get the context record of the target thread.
  174. //
  175. Context.ContextFlags = CONTEXT_FULL;
  176. Status = NtGetContextThread(Thread, &Context);
  177. if (NT_SUCCESS(Status) == FALSE) {
  178. if (AlreadySuspended == FALSE) {
  179. NtResumeThread(Thread, NULL);
  180. }
  181. return(Status);
  182. }
  183. if (AlreadySuspended) {
  184. Context.IntV0 = STATUS_ALERTED;
  185. }
  186. //
  187. // Pass the parameters to the other thread via the backing store (r32-r39).
  188. // The context record is passed on the stack of the target thread.
  189. // N.B. Align the context record address, stack pointer, and allocate
  190. // stack scratch area.
  191. //
  192. ContextAddress = (((ULONG_PTR)Context.IntSp + 0xf) & ~0xfi64) - sizeof(CONTEXT);
  193. NewSp = ContextAddress - STACK_SCRATCH_AREA;
  194. Status = NtWriteVirtualMemory(Process, (PVOID)ContextAddress, &Context,
  195. sizeof(CONTEXT), NULL);
  196. if (NT_SUCCESS(Status) == FALSE) {
  197. if (AlreadySuspended == FALSE) {
  198. NtResumeThread(Thread, NULL);
  199. }
  200. return(Status);
  201. }
  202. RtlZeroMemory((PVOID)ArgumentsCopy, sizeof(ArgumentsCopy));
  203. NewBsp = RtlpRseGrowBySOF(Context.RsBSP, Context.StIFS);
  204. Context.RsBSP = NewBsp;
  205. if (PassContext) {
  206. ShiftCount = (ULONG)RtlpRseRNatCollectOffset(NewBsp);
  207. Context.RsRNAT &= ~(0x1i64 << ShiftCount);
  208. ArgumentsCopy[Count++] = ContextAddress;
  209. NewBsp += sizeof(ULONGLONG);
  210. }
  211. for (; ArgumentCount != 0 ; ArgumentCount--) {
  212. if (RtlpRseRNatCollectOffset(NewBsp) == 63) {
  213. ArgumentsCopy[Count++] = Context.RsRNAT;
  214. Context.RsRNAT = -1i64;
  215. NewBsp += sizeof(ULONGLONG);
  216. }
  217. ShiftCount = (ULONG)RtlpRseRNatCollectOffset(NewBsp);
  218. Context.RsRNAT &= ~(0x1i64 << ShiftCount);
  219. ArgumentsCopy[Count++] = (ULONGLONG)(*Arguments++);
  220. NewBsp += sizeof(ULONGLONG);
  221. }
  222. if (RtlpRseRNatCollectOffset(NewBsp) == 63) {
  223. ArgumentsCopy[Count++] = Context.RsRNAT;
  224. Context.RsRNAT = -1i64;
  225. NewBsp += sizeof(ULONGLONG);
  226. }
  227. //
  228. // Copy the arguments onto the target backing store.
  229. //
  230. if (Count) {
  231. Status = NtWriteVirtualMemory(Process,
  232. (PVOID)Context.RsBSP,
  233. ArgumentsCopy,
  234. Count * sizeof(ULONGLONG),
  235. NULL
  236. );
  237. if (NT_SUCCESS(Status) == FALSE) {
  238. if (AlreadySuspended == FALSE) {
  239. NtResumeThread(Thread, NULL);
  240. }
  241. return(Status);
  242. }
  243. }
  244. //
  245. // set up RSE
  246. //
  247. Context.RsRSC = (RSC_MODE_LY<<RSC_MODE)
  248. | (RSC_BE_LITTLE<<RSC_BE)
  249. | (0x3<<RSC_PL);
  250. Count = ArgumentCount + (PassContext ? 1 : 0);
  251. //
  252. // Inject all arguments as local stack registers in the target RSE frame
  253. //
  254. Context.StIFS = (0x3i64 << 62) | Count | (Count << PFS_SIZE_SHIFT);
  255. //
  256. // Set the address of the target code into IIP, the new target stack
  257. // into sp, setup ap, and reload context to make it happen.
  258. //
  259. Context.IntSp = (ULONG_PTR)NewSp;
  260. //
  261. // Set IP to the target call site PLABEL and GP to zero. IIP and GP
  262. // will be computed inside NtSetContextThread.
  263. //
  264. Context.StIIP = (ULONGLONG)CallSite;
  265. Context.IntGp = 0;
  266. //
  267. // sanitize the floating pointer status register
  268. //
  269. SANITIZE_FSR(Context.StFPSR, UserMode);
  270. Status = NtSetContextThread(Thread, &Context);
  271. if (!AlreadySuspended) {
  272. NtResumeThread(Thread, NULL);
  273. }
  274. return( Status );
  275. }