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.

943 lines
25 KiB

  1. /*++
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. suspend.c
  5. Abstract:
  6. This module implements CpuSuspendThread, CpuGetContext and CpuSetContext for
  7. AMD64.
  8. Author:
  9. 12-Dec-2001 Samer Arafeh (samera)
  10. Revision History:
  11. --*/
  12. #define _WOW64CPUAPI_
  13. #ifdef _X86_
  14. #include "amd6432.h"
  15. #else
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <ntos.h>
  20. #include "wow64.h"
  21. #include "wow64cpu.h"
  22. #include "amd64cpu.h"
  23. #endif
  24. #include "cpup.h"
  25. #include <stdio.h>
  26. #include <stdarg.h>
  27. ASSERTNAME;
  28. ULONG_PTR ia32ShowContext = 0;
  29. VOID
  30. CpupDebugPrint(
  31. IN ULONG_PTR Flags,
  32. IN PCHAR Format,
  33. ...)
  34. {
  35. va_list ArgList;
  36. int BytesWritten;
  37. CHAR Buffer[ 512 ];
  38. if ((ia32ShowContext & Flags) || (Flags == ERRORLOG))
  39. {
  40. va_start(ArgList, Format);
  41. BytesWritten = _vsnprintf(Buffer,
  42. sizeof(Buffer) - 1,
  43. Format,
  44. ArgList);
  45. if (BytesWritten > 0)
  46. {
  47. DbgPrint(Buffer);
  48. }
  49. va_end(ArgList);
  50. }
  51. return;
  52. }
  53. VOID
  54. CpupPrintContext(
  55. IN PCHAR str,
  56. IN PCPUCONTEXT cpu
  57. )
  58. /*++
  59. Routine Description:
  60. Print out the ia32 context based on the passed in cpu context
  61. Arguments:
  62. str - String to print out as a header
  63. cpu - Pointer to the per-thread wow64 ia32 context.
  64. Return Value:
  65. none
  66. --*/
  67. {
  68. DbgPrint(str);
  69. DbgPrint("Context addr(0x%p): EIP=0x%08x\n", &(cpu->Context), cpu->Context.Eip);
  70. DbgPrint("Context EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n",
  71. cpu->Context.Eax,
  72. cpu->Context.Ebx,
  73. cpu->Context.Ecx,
  74. cpu->Context.Edx);
  75. DbgPrint("Context ESP=0x%08x, EBP=0x%08x, ESI=0x%08x, EDI=0x%08x\n",
  76. cpu->Context.Esp,
  77. cpu->Context.Ebp,
  78. cpu->Context.Esi,
  79. cpu->Context.Edi);
  80. try {
  81. //
  82. // The stack may not yet be fully formed, so don't
  83. // let a missing stack cause the process to abort
  84. //
  85. DbgPrint("Context stack=0x%08x 0x%08x 0x%08x 0x%08x\n",
  86. *((PULONG) cpu->Context.Esp),
  87. *(((PULONG) cpu->Context.Esp) + 1),
  88. *(((PULONG) cpu->Context.Esp) + 2),
  89. *(((PULONG) cpu->Context.Esp) + 3));
  90. } except ((GetExceptionCode() == STATUS_ACCESS_VIOLATION)?1:0) {
  91. //
  92. // Got an access violation, so don't print any of the stack
  93. //
  94. DbgPrint("Context stack: Can't get stack contents\n");
  95. }
  96. DbgPrint("Context EFLAGS=0x%08x\n", cpu->Context.EFlags);
  97. }
  98. WOW64CPUAPI
  99. NTSTATUS
  100. CpuSuspendThread(
  101. IN HANDLE ThreadHandle,
  102. IN HANDLE ProcessHandle,
  103. IN PTEB Teb,
  104. OUT PULONG PreviousSuspendCount OPTIONAL)
  105. /*++
  106. Routine Description:
  107. This routine is entered while the target thread is actually suspended, however, it's
  108. not known if the target thread is in a consistent state relative to
  109. the CPU.
  110. Arguments:
  111. ThreadHandle - Handle of target thread to suspend
  112. ProcessHandle - Handle of target thread's process
  113. Teb - Address of the target thread's TEB
  114. PreviousSuspendCount - Previous suspend count
  115. Return Value:
  116. NTSTATUS.
  117. --*/
  118. {
  119. return STATUS_SUCCESS;
  120. }
  121. NTSTATUS CpupReadBuffer(
  122. IN HANDLE ProcessHandle,
  123. IN PVOID Source,
  124. OUT PVOID Destination,
  125. IN ULONG Size)
  126. /*++
  127. Routine Description:
  128. This routine setup the arguments for the remoted SuspendThread call.
  129. Arguments:
  130. ProcessHandle - Target process handle to read data from
  131. Source - Target base address to read data from
  132. Destination - Address of buffer to receive data read from the specified address space
  133. Size - Size of data to read
  134. Return Value:
  135. NTSTATUS.
  136. --*/
  137. {
  138. NTSTATUS NtStatus = STATUS_SUCCESS;
  139. if (ProcessHandle == NtCurrentProcess ()) {
  140. try {
  141. RtlCopyMemory (Destination,
  142. Source,
  143. Size);
  144. } except (EXCEPTION_EXECUTE_HANDLER) {
  145. NtStatus = GetExceptionCode ();
  146. }
  147. } else {
  148. NtStatus = NtReadVirtualMemory (ProcessHandle,
  149. Source,
  150. Destination,
  151. Size,
  152. NULL);
  153. }
  154. return NtStatus;
  155. }
  156. NTSTATUS
  157. CpupWriteBuffer(
  158. IN HANDLE ProcessHandle,
  159. IN PVOID Target,
  160. IN PVOID Source,
  161. IN ULONG Size)
  162. /*++
  163. Routine Description:
  164. Writes data to memory taken into consideration if the write is cross-process
  165. or not
  166. Arguments:
  167. ProcessHandle - Target process handle to write data into
  168. Target - Target base address to write data at
  169. Source - Address of contents to write in the specified address space
  170. Size - Size of data to write
  171. Return Value:
  172. NTSTATUS.
  173. --*/
  174. {
  175. NTSTATUS NtStatus = STATUS_SUCCESS;
  176. if (ProcessHandle == NtCurrentProcess ()) {
  177. try {
  178. RtlCopyMemory (Target,
  179. Source,
  180. Size);
  181. } except (EXCEPTION_EXECUTE_HANDLER) {
  182. NtStatus = GetExceptionCode ();
  183. }
  184. } else {
  185. NtStatus = NtWriteVirtualMemory (ProcessHandle,
  186. Target,
  187. Source,
  188. Size,
  189. NULL);
  190. }
  191. return NtStatus;
  192. }
  193. NTSTATUS
  194. GetContextRecord(
  195. IN PCPUCONTEXT cpu,
  196. IN PCONTEXT ContextAmd64 OPTIONAL,
  197. IN OUT PCONTEXT32 Context
  198. )
  199. /*++
  200. Routine Description:
  201. Retrevies the context record of the specified CPU. This routine updates
  202. only the registers that are saved on transition to 64-bit mode, and SHOULD
  203. be kept in sync with the thunk-transition code.
  204. Arguments:
  205. cpu - CPU to retreive the context record for.
  206. ContextAmd64 - Full native context.
  207. Context - IN/OUT pointer to CONTEXT32 to fill in. Context->ContextFlags
  208. should be used to determine how much of the context to copy.
  209. Return Value:
  210. NTSTATUS
  211. --*/
  212. {
  213. NTSTATUS NtStatus = STATUS_SUCCESS;
  214. ULONG ContextFlags;
  215. try {
  216. ContextFlags = Context->ContextFlags;
  217. //
  218. // Get the initial 32-bit context.
  219. //
  220. //
  221. // Caller will fillup Context with the native context and pass ContextAmd64 as NULL.
  222. //
  223. if (ARGUMENT_PRESENT (ContextAmd64)) {
  224. Wow64CtxFromAmd64 (ContextFlags,
  225. ContextAmd64,
  226. Context);
  227. //
  228. // If the thread is running 32-bit code at the time of retreiving the context,
  229. // the direct conversion is enough.
  230. //
  231. if (ContextAmd64->SegCs == (KGDT64_R3_CMCODE | RPL_MASK)) {
  232. return NtStatus;
  233. }
  234. }
  235. if (ContextFlags & CONTEXT_AMD64) {
  236. LOGPRINT((ERRORLOG, "CpuGetContext: Request for amd64 context (0x%x) being FAILED\n", ContextFlags));
  237. ASSERT((ContextFlags & CONTEXT_AMD64) == 0);
  238. }
  239. if ((ContextFlags & CONTEXT32_CONTROL) == CONTEXT32_CONTROL) {
  240. //
  241. // control registers
  242. //
  243. Context->Ebp = cpu->Context.Ebp;
  244. Context->Eip = cpu->Context.Eip;
  245. Context->SegCs = (KGDT64_R3_CMCODE | RPL_MASK);
  246. Context->EFlags = SANITIZE_X86EFLAGS (cpu->Context.EFlags);
  247. Context->Esp = cpu->Context.Esp;
  248. Context->SegSs = (KGDT64_R3_DATA | RPL_MASK);
  249. }
  250. if ((ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER) {
  251. //
  252. // i386 integer registers are:
  253. // edi, esi, ebx, edx, ecx, eax
  254. //
  255. Context->Edi = cpu->Context.Edi;
  256. Context->Esi = cpu->Context.Esi;
  257. Context->Ebx = cpu->Context.Ebx;
  258. Context->Edx = cpu->Context.Edx;
  259. Context->Ecx = cpu->Context.Ecx;
  260. Context->Eax = cpu->Context.Eax;
  261. }
  262. if ((ContextFlags & CONTEXT32_SEGMENTS) == CONTEXT32_SEGMENTS) {
  263. //
  264. // i386 segment registers are:
  265. // ds, es, fs, gs
  266. // And since they are a constant, force them to be the right values
  267. //
  268. Context->SegDs = (KGDT64_R3_DATA | RPL_MASK);
  269. Context->SegEs = (KGDT64_R3_DATA | RPL_MASK);
  270. Context->SegFs = (KGDT64_R3_CMTEB | RPL_MASK);
  271. Context->SegGs = (KGDT64_R3_DATA | RPL_MASK);
  272. }
  273. if ((ContextFlags & CONTEXT32_FLOATING_POINT) == CONTEXT32_FLOATING_POINT) {
  274. //
  275. // floating point (legacy) registers (ST0-ST7)
  276. //
  277. //
  278. // This must have already been done.
  279. //
  280. }
  281. if ((ContextFlags & CONTEXT32_DEBUG_REGISTERS) == CONTEXT32_DEBUG_REGISTERS) {
  282. //
  283. // Debug registers (Dr0-Dr7)
  284. //
  285. //
  286. // This must have already been done
  287. //
  288. }
  289. if ((ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS) {
  290. //
  291. // extended floating point registers (XMM0-XMM7)
  292. //
  293. }
  294. } except (EXCEPTION_EXECUTE_HANDLER) {
  295. NtStatus = GetExceptionCode ();
  296. }
  297. if (ia32ShowContext & LOG_CONTEXT_GETSET) {
  298. CpupPrintContext ("Getting ia32 context: ", cpu);
  299. }
  300. return NtStatus;
  301. }
  302. NTSTATUS
  303. CpupGetContext(
  304. IN PCONTEXT ContextAmd64,
  305. IN OUT PCONTEXT32 Context
  306. )
  307. /*++
  308. Routine Description:
  309. This routine extracts the context record for the currently executing thread.
  310. Arguments:
  311. ContextAmd64 - Full native context
  312. Context - Context record to fill
  313. Return Value:
  314. NTSTATUS.
  315. --*/
  316. {
  317. DECLARE_CPU;
  318. return GetContextRecord (cpu, ContextAmd64, Context);
  319. }
  320. NTSTATUS
  321. CpupGetContextThread(
  322. IN HANDLE ThreadHandle,
  323. IN HANDLE ProcessHandle,
  324. IN PTEB Teb,
  325. IN OUT PCONTEXT32 Context)
  326. /*++
  327. Routine Description:
  328. This routine extract the context record of any thread. This is a generic routine.
  329. When entered, if the target thread isn't the current thread, then it should be
  330. guaranteed that the target thread is suspended at a proper CPU state.
  331. Arguments:
  332. ThreadHandle - Target thread handle to retreive the context for
  333. ProcessHandle - Open handle to the process that the thread runs in
  334. Teb - Pointer to the target's thread TEB
  335. Context - Context record to fill
  336. Return Value:
  337. NTSTATUS.
  338. --*/
  339. {
  340. NTSTATUS NtStatus = STATUS_SUCCESS;
  341. CONTEXT ContextEM;
  342. PCPUCONTEXT CpuRemoteContext;
  343. CPUCONTEXT CpuContext;
  344. //
  345. // Get the whole native context
  346. //
  347. ContextEM.ContextFlags = (CONTEXT_FULL |
  348. CONTEXT_DEBUG_REGISTERS |
  349. CONTEXT_SEGMENTS);
  350. NtStatus = NtGetContextThread (ThreadHandle,
  351. &ContextEM);
  352. if (!NT_SUCCESS(NtStatus)) {
  353. LOGPRINT((ERRORLOG, "CpupGetContextThread: NtGetContextThread (%lx) failed - %lx\n",
  354. ThreadHandle, NtStatus));
  355. return NtStatus;
  356. }
  357. //
  358. // If we are running 64-bit code, then get the context off the 64-bit
  359. // thread stack, which was spilled by the transition code...
  360. //
  361. if (ContextEM.SegCs != (KGDT64_R3_CMCODE | RPL_MASK)) {
  362. LOGPRINT((TRACELOG, "Getting context while thread is executing 64-bit instructions\n"));
  363. NtStatus = CpupReadBuffer( ProcessHandle,
  364. ((PCHAR)Teb + FIELD_OFFSET(TEB, TlsSlots[WOW64_TLS_CPURESERVED])),
  365. &CpuRemoteContext,
  366. sizeof(CpuRemoteContext));
  367. if (NT_SUCCESS(NtStatus)) {
  368. NtStatus = CpupReadBuffer (ProcessHandle,
  369. CpuRemoteContext,
  370. &CpuContext,
  371. sizeof(CpuContext));
  372. if (!NT_SUCCESS(NtStatus)) {
  373. LOGPRINT((ERRORLOG, "CpupGetContextThread: Couldn't read CPU context %lx - %lx\n",
  374. CpuRemoteContext, NtStatus));
  375. }
  376. } else {
  377. LOGPRINT((ERRORLOG, "CpupGetContextThread: Couldn't read CPU context address - %lx\n",
  378. NtStatus));
  379. }
  380. }
  381. //
  382. // Get the actual context context for the caller
  383. //
  384. if (NT_SUCCESS (NtStatus)) {
  385. NtStatus = GetContextRecord (&CpuContext, &ContextEM, Context);
  386. }
  387. return NtStatus;
  388. }
  389. WOW64CPUAPI
  390. NTSTATUS
  391. CpuGetContext(
  392. IN HANDLE ThreadHandle,
  393. IN HANDLE ProcessHandle,
  394. IN PTEB Teb,
  395. OUT PCONTEXT32 Context)
  396. /*++
  397. Routine Description:
  398. Extracts the cpu context of the specified thread.
  399. When entered, it is guaranteed that the target thread is suspended at
  400. a proper CPU state.
  401. Arguments:
  402. ThreadHandle - Target thread handle to retreive the context for
  403. ProcessHandle - Open handle to the process that the thread runs in
  404. Teb - Pointer to the target's thread TEB
  405. Context - Context record to fill
  406. Return Value:
  407. NTSTATUS.
  408. --*/
  409. {
  410. return CpupGetContextThread(ThreadHandle,
  411. ProcessHandle,
  412. Teb,
  413. Context);
  414. }
  415. NTSTATUS
  416. SetContextRecord(
  417. IN OUT PCPUCONTEXT cpu,
  418. IN OUT PCONTEXT ContextAmd64 OPTIONAL,
  419. IN PCONTEXT32 Context,
  420. OUT PBOOLEAN UpdateNativeContext
  421. )
  422. /*++
  423. Routine Description:
  424. Update the CPU's register set for the specified CPU. This routine updates
  425. only the registers that are saved on transition to 64-bit mode, and SHOULD
  426. be kept in sync with the thunk-transition code.
  427. Arguments:
  428. cpu - CPU to update its registers
  429. Context - Pointer to CONTEXT32 to use. Context->ContextFlags
  430. should be used to determine how much of the context to update.
  431. ContextAmd64 - Full native context, and will hold the updated 32-bit context.
  432. UpdateNativeContext - Updated on return to indicate if a NtSetContextThread call is required.
  433. Return Value:
  434. NTSTATUS
  435. --*/
  436. {
  437. NTSTATUS NtStatus = STATUS_SUCCESS;
  438. ULONG ContextFlags;
  439. ULONG NewContextFlags = 0;
  440. BOOLEAN CmMode;
  441. try {
  442. *UpdateNativeContext = FALSE;
  443. ContextFlags = Context->ContextFlags;
  444. if (ContextFlags & CONTEXT_AMD64) {
  445. LOGPRINT((ERRORLOG, "CpuSetContext: Request with amd64 context (0x%x) FAILED\n", ContextFlags));
  446. ASSERT((ContextFlags & CONTEXT_AMD64) == 0);
  447. }
  448. //
  449. // Caller might pass NativeContext == NULL if they already know what to do.
  450. //
  451. if (ARGUMENT_PRESENT (ContextAmd64)) {
  452. CmMode = (ContextAmd64->SegCs == (KGDT64_R3_CMCODE | RPL_MASK));
  453. Wow64CtxToAmd64 (ContextFlags,
  454. Context,
  455. ContextAmd64);
  456. //
  457. // If we are running 32-bit code
  458. //
  459. if (CmMode == TRUE) {
  460. *UpdateNativeContext = TRUE;
  461. return NtStatus;
  462. }
  463. NewContextFlags = 0;
  464. }
  465. if ((ContextFlags & CONTEXT32_CONTROL) == CONTEXT32_CONTROL) {
  466. //
  467. // Control registers
  468. //
  469. cpu->Context.Ebp = Context->Ebp;
  470. cpu->Context.Eip = Context->Eip;
  471. cpu->Context.SegCs = (KGDT64_R3_CMCODE | RPL_MASK);
  472. cpu->Context.EFlags = SANITIZE_X86EFLAGS (Context->EFlags);
  473. cpu->Context.Esp = Context->Esp;
  474. cpu->Context.SegSs = Context->SegSs;
  475. }
  476. if ((ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER) {
  477. //
  478. // Integer registers
  479. //
  480. cpu->Context.Edi = Context->Edi;
  481. cpu->Context.Esi = Context->Esi;
  482. cpu->Context.Ebx = Context->Ebx;
  483. cpu->Context.Edx = Context->Edx;
  484. cpu->Context.Ecx = Context->Ecx;
  485. cpu->Context.Eax = Context->Eax;
  486. }
  487. if ((ContextFlags & CONTEXT32_SEGMENTS) == CONTEXT32_SEGMENTS) {
  488. //
  489. // Segment registers
  490. //
  491. //
  492. // shouldn't be touched
  493. //
  494. }
  495. if ((ContextFlags & CONTEXT32_FLOATING_POINT) == CONTEXT32_FLOATING_POINT) {
  496. //
  497. // floating point registers
  498. //
  499. NewContextFlags |= CONTEXT_FLOATING_POINT;
  500. }
  501. if ((ContextFlags & CONTEXT32_DEBUG_REGISTERS) == CONTEXT32_DEBUG_REGISTERS) {
  502. //
  503. // debug registers (Dr0-Dr7)
  504. //
  505. NewContextFlags |= CONTEXT_DEBUG_REGISTERS;
  506. }
  507. if ((ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS) {
  508. //
  509. // extended floating point registers (ST0-ST7)
  510. //
  511. NewContextFlags |= CONTEXT_FLOATING_POINT;
  512. //
  513. // Save the extended registers so that the trap frame may restore them.
  514. // The system will ALWAYS scrub XMM0-XMM5 on return from system calls.
  515. //
  516. RtlCopyMemory (cpu->Context.ExtendedRegisters,
  517. Context->ExtendedRegisters,
  518. sizeof (Context->ExtendedRegisters));
  519. }
  520. //
  521. // Whatever they passed in before, it's an X86 context now...
  522. //
  523. cpu->Context.ContextFlags = ContextFlags;
  524. } except (EXCEPTION_EXECUTE_HANDLER) {
  525. NtStatus = GetExceptionCode();
  526. }
  527. if (ia32ShowContext & LOG_CONTEXT_GETSET) {
  528. CpupPrintContext("Setting ia32 context: ", cpu);
  529. }
  530. if (NewContextFlags != 0) {
  531. if (ARGUMENT_PRESENT (ContextAmd64)) {
  532. ContextAmd64->ContextFlags = NewContextFlags;
  533. *UpdateNativeContext = TRUE;
  534. }
  535. }
  536. return NtStatus;
  537. }
  538. NTSTATUS
  539. CpupSetContextThread(
  540. IN HANDLE ThreadHandle,
  541. IN HANDLE ProcessHandle,
  542. IN PTEB Teb,
  543. IN OUT PCONTEXT32 Context)
  544. /*++
  545. Routine Description:
  546. This routine sets the context record of any thread. This is a generic routine.
  547. When entered, if the target thread isn't the currently executing thread, then it should be
  548. guaranteed that the target thread is suspended at a proper CPU state.
  549. Arguments:
  550. ThreadHandle - Target thread handle to retreive the context for
  551. ProcessHandle - Open handle to the process that the thread runs in
  552. Teb - Pointer to the target's thread TEB
  553. Context - Context record to set
  554. Return Value:
  555. NTSTATUS.
  556. --*/
  557. {
  558. NTSTATUS NtStatus = STATUS_SUCCESS;
  559. CONTEXT ContextEM;
  560. PCPUCONTEXT CpuRemoteContext;
  561. CPUCONTEXT CpuContext;
  562. BOOLEAN CmMode;
  563. BOOLEAN UpdateNativeContext;
  564. //
  565. // Get the whole native context
  566. //
  567. ContextEM.ContextFlags = (CONTEXT_FULL |
  568. CONTEXT_DEBUG_REGISTERS |
  569. CONTEXT_SEGMENTS);
  570. NtStatus = NtGetContextThread (ThreadHandle,
  571. &ContextEM);
  572. if (!NT_SUCCESS(NtStatus)) {
  573. LOGPRINT((ERRORLOG, "CpupGetContextThread: NtGetContextThread (%lx) failed - %lx\n",
  574. ThreadHandle, NtStatus));
  575. return NtStatus;
  576. }
  577. CmMode = (ContextEM.SegCs == (KGDT64_R3_CMCODE | RPL_MASK));
  578. //
  579. // If we are running 64-bit code, make sure to update the cpu context off the
  580. // 64-bit thread stack...
  581. //
  582. if (CmMode == FALSE) {
  583. LOGPRINT((TRACELOG, "Setting context while thread is executing 64-bit instructions\n"));
  584. NtStatus = CpupReadBuffer (ProcessHandle,
  585. ((PCHAR)Teb + FIELD_OFFSET(TEB, TlsSlots[WOW64_TLS_CPURESERVED])),
  586. &CpuRemoteContext,
  587. sizeof(CpuRemoteContext));
  588. if (NT_SUCCESS(NtStatus)) {
  589. NtStatus = CpupReadBuffer (ProcessHandle,
  590. CpuRemoteContext,
  591. &CpuContext,
  592. sizeof(CpuContext));
  593. } else {
  594. LOGPRINT((ERRORLOG, "CpupSetContextThread: Couldn't read CPU context address - %lx\n",
  595. NtStatus));
  596. }
  597. }
  598. //
  599. // We are ready to set the context now
  600. //
  601. if (NT_SUCCESS (NtStatus)) {
  602. NtStatus = SetContextRecord (&CpuContext,
  603. &ContextEM,
  604. Context,
  605. &UpdateNativeContext);
  606. if (NT_SUCCESS (NtStatus)) {
  607. if (CmMode == FALSE) {
  608. //
  609. // If the call is coming thru Wow64, then restore the volatile XMMI and integer registers on the next
  610. // tranisition to compatibility mode
  611. //
  612. if (ThreadHandle == NtCurrentThread ()) {
  613. if (((Context->ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS) ||
  614. ((Context->ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER)) {
  615. CpuContext.TrapFrameFlags = TRAP_FRAME_RESTORE_VOLATILE;
  616. }
  617. }
  618. NtStatus = CpupWriteBuffer(ProcessHandle,
  619. CpuRemoteContext,
  620. &CpuContext,
  621. sizeof(CpuContext));
  622. if (!NT_SUCCESS (NtStatus)) {
  623. LOGPRINT((ERRORLOG, "CpupSetContextThread: Couldn't write remote context %lx - %lx\n",
  624. CpuRemoteContext, NtStatus));
  625. }
  626. }
  627. //
  628. // Set the context ultimately. This shouldn't change except the FP and debug
  629. // state if the thread is executing in 64-bit (long) mode.
  630. //
  631. if ((NT_SUCCESS (NtStatus)) &&
  632. (UpdateNativeContext == TRUE)) {
  633. NtStatus = NtSetContextThread (ThreadHandle, &ContextEM);
  634. }
  635. } else {
  636. LOGPRINT((ERRORLOG, "CpupSetContextThread: Couldn't update native context %lx - %lx\n",
  637. &ContextEM, NtStatus));
  638. }
  639. }
  640. return NtStatus;
  641. }
  642. WOW64CPUAPI
  643. NTSTATUS
  644. CpuSetContext(
  645. IN HANDLE ThreadHandle,
  646. IN HANDLE ProcessHandle,
  647. IN PTEB Teb,
  648. PCONTEXT32 Context)
  649. /*++
  650. Routine Description:
  651. Sets the cpu context for the specified thread.
  652. When entered, if the target thread isn't the currently executing thread, then it is
  653. guaranteed that the target thread is suspended at a proper CPU state.
  654. Arguments:
  655. ThreadHandle - Target thread handle to retreive the context for
  656. ProcessHandle - Open handle to the process that the thread runs in
  657. Teb - Pointer to the target's thread TEB
  658. Context - Context record to set
  659. Return Value:
  660. NTSTATUS.
  661. --*/
  662. {
  663. return CpupSetContextThread(ThreadHandle,
  664. ProcessHandle,
  665. Teb,
  666. Context);
  667. }