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.

2637 lines
75 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. patchfn.c
  5. Abstract:
  6. This module contains generic functions to patch fragments. Structures
  7. that describe the fragments to be patched. The structures live in
  8. the processor specific directory.
  9. Author:
  10. Dave Hastings (daveh) creation-date 24-Jun-1995
  11. Revision History:
  12. Barry Bond (barrybo) 1-Apr-1995
  13. Switch the PPC build to the AXP model of patching
  14. 24-Aug-1999 [askhalid] copied from 32-bit wx86 directory and make work for 64bit.
  15. 20-Sept-1999[barrybo] added FRAG2REF(LockCmpXchg8bFrag32, ULONGLONG)
  16. Notes:
  17. --*/
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #define _WX86CPUAPI_
  23. #include "wx86.h"
  24. #include "wx86nt.h"
  25. #include "wx86cpu.h"
  26. #include "cpuassrt.h"
  27. #include "instr.h"
  28. #include "config.h"
  29. #include "fragp.h"
  30. #include "entrypt.h"
  31. #include "compiler.h"
  32. #include "ctrltrns.h"
  33. #include "threadst.h"
  34. #include "instr.h"
  35. #include "frag.h"
  36. #include "ptchstrc.h"
  37. #include "mrsw.h"
  38. #include "tc.h"
  39. #include "codeseq.h"
  40. #include "codesize.h"
  41. #include "opt.h"
  42. #if _ALPHA_
  43. #define _codegen_
  44. #include "soalpha.h"
  45. #undef fTCUnlocked // this is a field in CPUCONTEXT
  46. ULONG
  47. GetCurrentECU(
  48. PULONG CodeLocation
  49. );
  50. #endif
  51. ASSERTNAME;
  52. extern CHAR CallJxxHelper[];
  53. extern CHAR CallJmpDirectHelper[];
  54. extern CHAR IndirectControlTransferHelper[];
  55. extern CHAR IndirectControlTransferFarHelper[];
  56. extern CHAR CallDirectHelper[];
  57. extern CHAR CallDirectHelper2[];
  58. extern CHAR CallIndirectHelper[];
  59. extern CHAR JumpToNextCompilationUnitHelper[];
  60. #define OFFSET(type, field) ((LONG)(ULONGLONG)(&((type *)0)->field))
  61. ULONG RegisterOffset[] = {
  62. OFFSET(THREADSTATE, GpRegs[GP_EAX].i4), // EAX
  63. OFFSET(THREADSTATE, GpRegs[GP_ECX].i4), // ECX
  64. OFFSET(THREADSTATE, GpRegs[GP_EDX].i4), // EDX
  65. OFFSET(THREADSTATE, GpRegs[GP_EBX].i4), // EBX
  66. OFFSET(THREADSTATE, GpRegs[GP_ESP].i4), // ESP
  67. OFFSET(THREADSTATE, GpRegs[GP_EBP].i4), // EBP
  68. OFFSET(THREADSTATE, GpRegs[GP_ESI].i4), // ESI
  69. OFFSET(THREADSTATE, GpRegs[GP_EDI].i4), // EDI
  70. OFFSET(THREADSTATE, GpRegs[REG_ES]), // ES
  71. OFFSET(THREADSTATE, GpRegs[REG_CS]), // CS
  72. OFFSET(THREADSTATE, GpRegs[REG_SS]), // SS
  73. OFFSET(THREADSTATE, GpRegs[REG_DS]), // DS
  74. OFFSET(THREADSTATE, GpRegs[REG_FS]), // FS
  75. OFFSET(THREADSTATE, GpRegs[REG_GS]), // GS
  76. OFFSET(THREADSTATE, GpRegs[GP_EAX].i2), // AX
  77. OFFSET(THREADSTATE, GpRegs[GP_ECX].i2), // CX
  78. OFFSET(THREADSTATE, GpRegs[GP_EDX].i2), // DX
  79. OFFSET(THREADSTATE, GpRegs[GP_EBX].i2), // BX
  80. OFFSET(THREADSTATE, GpRegs[GP_ESP].i2), // SP
  81. OFFSET(THREADSTATE, GpRegs[GP_EBP].i2), // BP
  82. OFFSET(THREADSTATE, GpRegs[GP_ESI].i2), // SI
  83. OFFSET(THREADSTATE, GpRegs[GP_EDI].i2), // DI
  84. OFFSET(THREADSTATE, GpRegs[GP_EAX].i1), // AL
  85. OFFSET(THREADSTATE, GpRegs[GP_ECX].i1), // CL
  86. OFFSET(THREADSTATE, GpRegs[GP_EDX].i1), // DL
  87. OFFSET(THREADSTATE, GpRegs[GP_EBX].i1), // BL
  88. OFFSET(THREADSTATE, GpRegs[GP_EAX].hb), // AH
  89. OFFSET(THREADSTATE, GpRegs[GP_ECX].hb), // CH
  90. OFFSET(THREADSTATE, GpRegs[GP_EDX].hb), // DH
  91. OFFSET(THREADSTATE, GpRegs[GP_EBX].hb) // BH
  92. };
  93. ULONG
  94. PatchJumpToNextCompilationUnit(
  95. IN PULONG PatchAddr,
  96. IN ULONG IntelDest
  97. )
  98. /*++
  99. Routine Description:
  100. This routine ends basic blocks when the native address of the next
  101. basic block is known.
  102. Arguments:
  103. PatchAddr -- address of JumpToNextCompilationUnit code in the TC
  104. IntelDest -- intel address of the next basic block
  105. Return Value:
  106. Native address to jump to to resume execution.
  107. --*/
  108. {
  109. DWORD TCTimestamp;
  110. ULONG NativeDest;
  111. ULONG NativeSize;
  112. DECLARE_CPU;
  113. if (cpu->flag_tf) {
  114. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  115. }
  116. //
  117. // Switch from being a TC reader to a writer
  118. //
  119. TCTimestamp = TranslationCacheTimestamp;
  120. MrswReaderExit(&MrswTC);
  121. //
  122. // Compile the next basic block, and get the TC write lock
  123. //
  124. NativeDest = (ULONG)(ULONGLONG)NativeAddressFromEip((PVOID)IntelDest, TRUE)->nativeStart;
  125. if (TCTimestamp == TranslationCacheTimestamp) {
  126. PULONG CodeLocation = PatchAddr - JumpToNextCompilationUnit_SIZE;
  127. //
  128. // The Translation Cache wasn't flushed - replace the
  129. // JumpToNextCompilationUnit fragment by JumpToNextCompilationUnit2
  130. //
  131. NativeSize=GenJumpToNextCompilationUnit2(CodeLocation,
  132. FALSE, // patching, not compiling
  133. #if _ALPHA_
  134. GetCurrentECU(CodeLocation),
  135. #endif
  136. NativeDest,
  137. 0);
  138. NtFlushInstructionCache(
  139. NtCurrentProcess(),
  140. CodeLocation,
  141. NativeSize
  142. );
  143. } else {
  144. TCTimestamp = TranslationCacheTimestamp;
  145. if (cpu->CSTimestamp != TCTimestamp) {
  146. //
  147. // The cache was flushed by another thread in the small window
  148. // between mrsw calls in this thread, we plan on jumping directly
  149. // to NativeDest, so the CPU callstack needs to be flushed.
  150. // Normally this would be done in the CpuSimulate() loop as a
  151. // result of jumping to EndTranslatedCode.
  152. //
  153. FlushCallstack(cpu);
  154. }
  155. }
  156. //
  157. // Switch back to being a TC reader
  158. //
  159. MrswWriterExit(&MrswTC);
  160. MrswReaderEnter(&MrswTC);
  161. if (TCTimestamp == TranslationCacheTimestamp) {
  162. //
  163. // TC was not flushed - NativeDest is valid
  164. //
  165. return NativeDest;
  166. } else {
  167. //
  168. // TC was flushed while becomming a TC reader again - NativeDest
  169. // is now bogus.
  170. //
  171. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  172. }
  173. }
  174. ULONG
  175. PlaceJxx(
  176. IN PULONG CodeLocation,
  177. #if _ALPHA_
  178. IN ULONG CurrentECU,
  179. #endif
  180. IN PINSTRUCTION Instruction
  181. )
  182. /*++
  183. Routine Description:
  184. This routine copies the fragment into place, and modifies the
  185. instructions that load the destination into the register
  186. Arguments:
  187. Instruction - Supplies a description of the instruction the fragment
  188. represents
  189. CodeLocation - Supplies the address the code for the fragment has been
  190. copied to
  191. Return Value:
  192. Size of code placed at CodeLocation
  193. --*/
  194. {
  195. DWORD IntelDest;
  196. PPLACEOPERATIONFN pfn;
  197. PENTRYPOINT EP;
  198. ULONG NativeSize;
  199. //
  200. // Generate the code to determine if the branch is taken or not
  201. //
  202. pfn = (PPLACEOPERATIONFN)FragmentArray[Instruction->Operation];
  203. NativeSize = (*pfn)(CodeLocation,
  204. #if _ALPHA_
  205. CurrentECU,
  206. #endif
  207. Instruction);
  208. CodeLocation += NativeSize/sizeof(ULONG);
  209. // Let's see if we can place the patched version immediately
  210. // ASSUME: The first argument is always a NOCODEGEN
  211. CPUASSERT( Instruction->Operand1.Type == OPND_NOCODEGEN );
  212. IntelDest = Instruction->Operand1.Immed;
  213. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)IntelDest);
  214. if (EP == NULL) {
  215. //
  216. // knowing NativeDest requires compilation. Just place the unpatched
  217. // version to be patched later.
  218. //
  219. NativeSize += GenJxxBody(CodeLocation,
  220. #if _ALPHA_
  221. CurrentECU,
  222. #endif
  223. Instruction);
  224. } else {
  225. //
  226. // We can place the patched version right away!
  227. //
  228. NativeSize += GenJxxBody2(CodeLocation,
  229. TRUE, // compiling, not patching
  230. #if _ALPHA_
  231. CurrentECU,
  232. #endif
  233. (ULONG)IntelDest,
  234. (ULONG)(ULONGLONG)EP);
  235. }
  236. return NativeSize;
  237. }
  238. ULONG
  239. PlaceJxxSlow(
  240. IN PULONG CodeLocation,
  241. #if _ALPHA_
  242. IN ULONG CurrentECU,
  243. #endif
  244. IN PINSTRUCTION Instruction
  245. )
  246. /*++
  247. Routine Description:
  248. This routine copies the fragment into place, and modifies the
  249. instructions that load the destination into the register
  250. Arguments:
  251. Instruction - Supplies a description of the instruction the fragment
  252. represents
  253. CodeLocation - Supplies the address the code for the fragment has been
  254. copied to
  255. Return Value:
  256. Size of code placed at CodeLocation
  257. --*/
  258. {
  259. DWORD IntelDest;
  260. PPLACEOPERATIONFN pfn;
  261. PENTRYPOINT EP;
  262. ULONG NativeSize;
  263. //
  264. // Generate the code to load RegEip with the branch-not-taken value
  265. //
  266. NativeSize = GenJxxStartSlow(CodeLocation,
  267. #if _ALPHA_
  268. CurrentECU,
  269. #endif
  270. Instruction);
  271. //
  272. // Generate the code to determine if the branch is taken or not
  273. //
  274. pfn = (PPLACEOPERATIONFN)FragmentArray[Instruction->Operation];
  275. NativeSize += (*pfn)(CodeLocation+NativeSize/sizeof(ULONG),
  276. #if _ALPHA_
  277. CurrentECU,
  278. #endif
  279. Instruction);
  280. CodeLocation += NativeSize/sizeof(ULONG);
  281. // Let's see if we can place the patched version immediately
  282. // ASSUME: The first argument is always a NOCODEGEN
  283. CPUASSERT( Instruction->Operand1.Type == OPND_NOCODEGEN );
  284. IntelDest = Instruction->Operand1.Immed;
  285. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)IntelDest);
  286. if (EP == NULL) {
  287. //
  288. // knowing NativeDest requires compilation. Just place the unpatched
  289. // version to be patched later.
  290. //
  291. NativeSize += GenJxxBodySlow(CodeLocation,
  292. #if _ALPHA_
  293. CurrentECU,
  294. #endif
  295. Instruction);
  296. } else {
  297. //
  298. // We can place the patched version right away!
  299. //
  300. NativeSize += GenJxxBodySlow2(CodeLocation,
  301. TRUE, // compiling, not patching
  302. #if _ALPHA_
  303. CurrentECU,
  304. #endif
  305. (ULONG)IntelDest,
  306. (ULONG)(ULONGLONG)EP);
  307. }
  308. return NativeSize;
  309. }
  310. ULONG
  311. PlaceJxxFwd(
  312. IN PULONG CodeLocation,
  313. #if _ALPHA_
  314. IN ULONG CurrentECU,
  315. #endif
  316. IN PINSTRUCTION Instruction
  317. )
  318. /*++
  319. Routine Description:
  320. This routine copies the fragment into place, and modifies the
  321. instructions that load the destination into the register
  322. Arguments:
  323. Instruction - Supplies a description of the instruction the fragment
  324. represents
  325. CodeLocation - Supplies the address the code for the fragment has been
  326. copied to
  327. Return Value:
  328. Size of code placed at CodeLocation
  329. --*/
  330. {
  331. DWORD IntelDest;
  332. PPLACEOPERATIONFN pfn;
  333. PENTRYPOINT EP;
  334. ULONG NativeSize;
  335. //
  336. // Generate the code to determine if the branch is taken or not
  337. //
  338. pfn = (PPLACEOPERATIONFN)FragmentArray[Instruction->Operation];
  339. NativeSize = (*pfn)(CodeLocation,
  340. #if _ALPHA_
  341. CurrentECU,
  342. #endif
  343. Instruction);
  344. CodeLocation += NativeSize/sizeof(ULONG);
  345. // Let's see if we can place the patched version immediately
  346. // ASSUME: The first argument is always a NOCODEGEN
  347. CPUASSERT( Instruction->Operand1.Type == OPND_NOCODEGEN );
  348. IntelDest = Instruction->Operand1.Immed;
  349. // Assert that the branch is going forward.
  350. CPUASSERT(IntelDest > Instruction->IntelAddress);
  351. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)IntelDest);
  352. if (EP == NULL) {
  353. //
  354. // knowing NativeDest requires compilation. Just place the unpatched
  355. // version to be patched later.
  356. NativeSize += GenJxxBodyFwd(CodeLocation,
  357. #if _ALPHA_
  358. CurrentECU,
  359. #endif
  360. Instruction);
  361. } else {
  362. //
  363. // We can place the patched version right away!
  364. //
  365. NativeSize += GenJxxBodyFwd2(CodeLocation,
  366. TRUE, // compiling, not patching
  367. #if _ALPHA_
  368. CurrentECU,
  369. #endif
  370. (ULONG)(ULONGLONG)EP,
  371. 0);
  372. }
  373. return NativeSize;
  374. }
  375. ULONG
  376. PatchJxx(
  377. IN ULONG IntelDest,
  378. IN PULONG PatchAddr
  379. )
  380. /*++
  381. Routine Description:
  382. This routine replaces a JXXSTRUC by a JXXSTRC2 at runtime. It is called
  383. when the conditional branch is taken, and the native address of the
  384. destination is not yet known.
  385. Arguments:
  386. inteldest -- Intel destination address if the branch is taken
  387. patchaddr -- address of the JXXSTRUC in the Translation Cache
  388. Return Value:
  389. Native address to jump to in order to resume execution.
  390. --*/
  391. {
  392. ULONG NativeDest; // branch-taken address
  393. PULONG fragaddr; // address of START of the fragment
  394. DWORD TCTimestamp; // old timestamp of the Translation Cache
  395. ULONG NativeSize;
  396. DECLARE_CPU;
  397. if (cpu->flag_tf) {
  398. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  399. }
  400. //
  401. // Switch over to being a TC writer
  402. //
  403. TCTimestamp = TranslationCacheTimestamp;
  404. MrswReaderExit(&MrswTC);
  405. //
  406. // Get the native destination address of the branch and get the TC
  407. // write lock
  408. //
  409. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip((PVOID)IntelDest, TRUE)->nativeStart;
  410. if (TCTimestamp == TranslationCacheTimestamp) {
  411. PULONG CodeLocation = PatchAddr - CallJxx_PATCHRA_OFFSET;
  412. //
  413. // The Translation Cache was not flushed while switching to a TC
  414. // writer or by the compilation. Replace JxxBody by the faster
  415. // JxxBody2
  416. //
  417. NativeSize=GenJxxBody2(CodeLocation,
  418. FALSE, // patching, not compiling
  419. #if _ALPHA_
  420. GetCurrentECU(CodeLocation),
  421. #endif
  422. (DWORD)IntelDest,
  423. (DWORD)NativeDest);
  424. NtFlushInstructionCache(
  425. NtCurrentProcess(),
  426. CodeLocation,
  427. NativeSize
  428. );
  429. } else {
  430. TCTimestamp = TranslationCacheTimestamp;
  431. if (cpu->CSTimestamp != TCTimestamp) {
  432. //
  433. // The cache was flushed by another thread in the small window
  434. // between mrsw calls in this thread, we plan on jumping directly
  435. // to NativeDest, so the CPU callstack needs to be flushed.
  436. // Normally this would be done in the CpuSimulate() loop as a
  437. // result of jumping to EndTranslatedCode.
  438. //
  439. FlushCallstack(cpu);
  440. }
  441. }
  442. //
  443. // Switch back to being a TC reader again
  444. //
  445. MrswWriterExit(&MrswTC);
  446. MrswReaderEnter(&MrswTC);
  447. if (TCTimestamp == TranslationCacheTimestamp) {
  448. //
  449. // TC was not flushed while becomming a reader again
  450. //
  451. return NativeDest;
  452. } else {
  453. //
  454. // TC was flushed while becomming a reader. nativedest is invalid
  455. // so do an EndTranslatedCode instead.
  456. //
  457. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  458. }
  459. }
  460. ULONG
  461. PatchJxxSlow(
  462. IN ULONG IntelDest,
  463. IN PULONG PatchAddr
  464. )
  465. /*++
  466. Routine Description:
  467. This routine replaces a JXXSTRUC by a JXXSTRC2 at runtime. It is called
  468. when the conditional branch is taken, and the native address of the
  469. destination is not yet known.
  470. Arguments:
  471. inteldest -- Intel destination address if the branch is taken
  472. patchaddr -- address of the JXXSTRUC in the Translation Cache
  473. Return Value:
  474. Native address to jump to in order to resume execution.
  475. --*/
  476. {
  477. ULONG NativeDest; // branch-taken address
  478. PULONG fragaddr; // address of START of the fragment
  479. DWORD TCTimestamp; // old timestamp of the Translation Cache
  480. ULONG NativeSize;
  481. DECLARE_CPU;
  482. if (cpu->flag_tf) {
  483. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  484. }
  485. //
  486. // Switch over to being a TC writer
  487. //
  488. TCTimestamp = TranslationCacheTimestamp;
  489. MrswReaderExit(&MrswTC);
  490. //
  491. // Get the native destination address of the branch and get the TC
  492. // write lock
  493. //
  494. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip((PVOID)IntelDest, TRUE)->nativeStart;
  495. if (TCTimestamp == TranslationCacheTimestamp) {
  496. PULONG CodeLocation = PatchAddr - CallJxxSlow_PATCHRA_OFFSET;
  497. //
  498. // The Translation Cache was not flushed while switching to a TC
  499. // writer or by the compilation. Replace JxxBody by the faster
  500. // JxxBody2
  501. //
  502. NativeSize = GenJxxBodySlow2(CodeLocation,
  503. FALSE, // patching, not compiling
  504. #if _ALPHA_
  505. GetCurrentECU(CodeLocation),
  506. #endif
  507. (DWORD)IntelDest,
  508. (DWORD)NativeDest);
  509. NtFlushInstructionCache(
  510. NtCurrentProcess(),
  511. CodeLocation,
  512. NativeSize
  513. );
  514. } else {
  515. TCTimestamp = TranslationCacheTimestamp;
  516. if (cpu->CSTimestamp != TCTimestamp) {
  517. //
  518. // The cache was flushed by another thread in the small window
  519. // between mrsw calls in this thread, we plan on jumping directly
  520. // to NativeDest, so the CPU callstack needs to be flushed.
  521. // Normally this would be done in the CpuSimulate() loop as a
  522. // result of jumping to EndTranslatedCode.
  523. //
  524. FlushCallstack(cpu);
  525. }
  526. }
  527. //
  528. // Switch back to being a TC reader again
  529. //
  530. MrswWriterExit(&MrswTC);
  531. MrswReaderEnter(&MrswTC);
  532. if (TCTimestamp == TranslationCacheTimestamp) {
  533. //
  534. // TC was not flushed while becomming a reader again
  535. //
  536. return NativeDest;
  537. } else {
  538. //
  539. // TC was flushed while becomming a reader. nativedest is invalid
  540. // so do an EndTranslatedCode instead.
  541. //
  542. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  543. }
  544. }
  545. ULONG
  546. PatchJxxFwd(
  547. IN ULONG IntelDest,
  548. IN PULONG PatchAddr
  549. )
  550. /*++
  551. Routine Description:
  552. This routine replaces a JXXBODYFWD by a JXXBODYFWD2 at runtime. It is
  553. called when the conditional branch is taken, and the native address of the
  554. destination is not yet known.
  555. Arguments:
  556. inteldest -- Intel destination address if the branch is taken
  557. patchaddr -- address of the JXXSTRUCFWD in the Translation Cache
  558. Return Value:
  559. Native address to jump to in order to resume execution.
  560. --*/
  561. {
  562. ULONG NativeDest; // branch-taken address
  563. PULONG fragaddr; // address of START of the fragment
  564. DWORD TCTimestamp; // old timestamp of the Translation Cache
  565. ULONG NativeSize;
  566. DECLARE_CPU;
  567. if (cpu->flag_tf) {
  568. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  569. }
  570. //
  571. // Switch over to being a TC writer
  572. //
  573. TCTimestamp = TranslationCacheTimestamp;
  574. MrswReaderExit(&MrswTC);
  575. //
  576. // Get the native destination address of the branch and get the TC write lock
  577. //
  578. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip((PVOID)IntelDest, TRUE)->nativeStart;
  579. if (TCTimestamp == TranslationCacheTimestamp) {
  580. PULONG CodeLocation = PatchAddr - CallJxxFwd_PATCHRA_OFFSET;
  581. //
  582. // The Translation Cache was not flushed while switching to a TC
  583. // writer or by the compilation. Replace JxxBody by the faster
  584. // JxxBodyFwd2
  585. //
  586. NativeSize = GenJxxBodyFwd2(CodeLocation,
  587. FALSE, // patching, not compiling
  588. #if _ALPHA_
  589. GetCurrentECU(CodeLocation),
  590. #endif
  591. (DWORD)NativeDest,
  592. 0);
  593. NtFlushInstructionCache(
  594. NtCurrentProcess(),
  595. CodeLocation,
  596. NativeSize
  597. );
  598. } else {
  599. TCTimestamp = TranslationCacheTimestamp;
  600. if (cpu->CSTimestamp != TCTimestamp) {
  601. //
  602. // The cache was flushed by another thread in the small window
  603. // between mrsw calls in this thread, we plan on jumping directly
  604. // to NativeDest, so the CPU callstack needs to be flushed.
  605. // Normally this would be done in the CpuSimulate() loop as a
  606. // result of jumping to EndTranslatedCode.
  607. //
  608. FlushCallstack(cpu);
  609. }
  610. }
  611. //
  612. // Switch back to being a TC reader again
  613. //
  614. MrswWriterExit(&MrswTC);
  615. MrswReaderEnter(&MrswTC);
  616. if (TCTimestamp == TranslationCacheTimestamp) {
  617. //
  618. // TC was not flushed while becomming a reader again
  619. //
  620. return NativeDest;
  621. } else {
  622. //
  623. // TC was flushed while becomming a reader. nativedest is invalid
  624. // so do an EndTranslatedCode instead.
  625. //
  626. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  627. }
  628. }
  629. ULONG
  630. PlaceJmpDirect(
  631. IN PULONG CodeLocation,
  632. #if _ALPHA_
  633. IN ULONG CurrentECU,
  634. #endif
  635. IN PINSTRUCTION Instruction
  636. )
  637. /*++
  638. Routine Description:
  639. This routine copies the unconditional jump fragment into place and patches
  640. the instructions that jump to EndTranslatedCode
  641. Arguments:
  642. Instruction - Supplies a description of the instruction the fragment
  643. represents
  644. CodeLocation - Supplies the address the code for the fragment has been
  645. copied to
  646. Return Value:
  647. Size of code placed at CodeLocation
  648. --*/
  649. {
  650. DWORD IntelDest;
  651. PENTRYPOINT EP;
  652. ULONG NativeSize;
  653. // ASSUME: The first argument is always an immediate
  654. CPUASSERT( Instruction->Operand1.Type == OPND_NOCODEGEN );
  655. IntelDest = Instruction->Operand1.Immed;
  656. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)IntelDest);
  657. if (EP == NULL) {
  658. //
  659. // Knowing NativeDest requires compilation. Just place the unpatched version for
  660. // now and patch it later if necessary
  661. //
  662. NativeSize = GenCallJmpDirect(CodeLocation,
  663. #if _ALPHA_
  664. CurrentECU,
  665. #endif
  666. Instruction);
  667. } else {
  668. //
  669. // We can place the patched version right away!
  670. //
  671. NativeSize = GenCallJmpDirect2(CodeLocation,
  672. TRUE, // compiling, not patching
  673. #if _ALPHA_
  674. CurrentECU,
  675. #endif
  676. (ULONG)(ULONGLONG) EP,
  677. IntelDest);
  678. }
  679. return NativeSize;
  680. }
  681. ULONG
  682. PatchJmpDirect(
  683. IN PULONG PatchAddr,
  684. IN ULONG IntelDest
  685. )
  686. /*++
  687. Routine Description:
  688. This routine patches a JMPDIRECT to a JMPDIRECT2. It is called when
  689. the native destination address of a jmp instruction is not yet known.
  690. It patches the jmp to jump directly to the corresponding native code.
  691. Arguments:
  692. PatchAddr -- address of the JMPDIRECT in the Translation Cache
  693. IntelDest -- intel address of the destination of the jmp
  694. Return Value:
  695. Native address to jump to in order to resume execution
  696. --*/
  697. {
  698. DWORD TCTimestamp;
  699. ULONG NativeDest;
  700. ULONG NativeSize;
  701. DECLARE_CPU;
  702. if (cpu->flag_tf) {
  703. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  704. }
  705. //
  706. // Switch from being a TC reader to a writer
  707. //
  708. TCTimestamp = TranslationCacheTimestamp;
  709. MrswReaderExit(&MrswTC);
  710. //
  711. // Compile the destination of the jmp and get the TC write lock
  712. //
  713. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip((PVOID)IntelDest, TRUE)->nativeStart;
  714. if (TCTimestamp == TranslationCacheTimestamp) {
  715. PULONG CodeLocation = PatchAddr - CallJmpDirect_PATCHRA_OFFSET;
  716. //
  717. // The Translation Cache wasn't flushed - replace the JMPDIRECT
  718. // fragment by JMPDIRECT2
  719. //
  720. NativeSize = GenCallJmpDirect2(CodeLocation,
  721. FALSE, // patching, not compiling
  722. #if _ALPHA_
  723. GetCurrentECU(CodeLocation),
  724. #endif
  725. (ULONG)NativeDest,
  726. IntelDest);
  727. NtFlushInstructionCache(
  728. NtCurrentProcess(),
  729. (PVOID)CodeLocation,
  730. NativeSize
  731. );
  732. } else {
  733. TCTimestamp = TranslationCacheTimestamp;
  734. if (cpu->CSTimestamp != TCTimestamp) {
  735. //
  736. // The cache was flushed by another thread in the small window
  737. // between mrsw calls in this thread, we plan on jumping directly
  738. // to NativeDest, so the CPU callstack needs to be flushed.
  739. // Normally this would be done in the CpuSimulate() loop as a
  740. // result of jumping to EndTranslatedCode.
  741. //
  742. FlushCallstack(cpu);
  743. }
  744. }
  745. //
  746. // Switch back to being a TC reader
  747. //
  748. MrswWriterExit(&MrswTC);
  749. MrswReaderEnter(&MrswTC);
  750. if (TCTimestamp == TranslationCacheTimestamp) {
  751. //
  752. // TC was not flushed - nativedest is valid
  753. //
  754. return NativeDest;
  755. } else {
  756. //
  757. // TC was flushed while becomming a TC reader again - nativedest
  758. // is now bogus.
  759. //
  760. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  761. }
  762. }
  763. ULONG
  764. PlaceJmpDirectSlow(
  765. IN PULONG CodeLocation,
  766. #if _ALPHA_
  767. IN ULONG CurrentECU,
  768. #endif
  769. IN PINSTRUCTION Instruction
  770. )
  771. /*++
  772. Routine Description:
  773. This routine copies the unconditional jump fragment into place and patches
  774. the instructions that jump to EndTranslatedCode
  775. Arguments:
  776. Instruction - Supplies a description of the instruction the fragment
  777. represents
  778. CodeLocation - Supplies the address the code for the fragment has been
  779. copied to
  780. Return Value:
  781. Size of code placed at CodeLocation
  782. --*/
  783. {
  784. DWORD IntelDest;
  785. PENTRYPOINT EP;
  786. ULONG NativeSize;
  787. // ASSUME: The first argument is always an immediate
  788. CPUASSERT( Instruction->Operand1.Type == OPND_NOCODEGEN );
  789. IntelDest = Instruction->Operand1.Immed;
  790. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)IntelDest);
  791. if (EP == NULL) {
  792. //
  793. // Knowing NativeDest requires compilation. Just place the unpatched version for
  794. // now and patch it later if necessary
  795. //
  796. NativeSize = GenCallJmpDirectSlow(CodeLocation,
  797. #if _ALPHA_
  798. CurrentECU,
  799. #endif
  800. Instruction);
  801. } else {
  802. //
  803. // We can place the patched version right away!
  804. //
  805. NativeSize = GenCallJmpDirectSlow2(CodeLocation,
  806. TRUE, // compiling, not patching
  807. #if _ALPHA_
  808. CurrentECU,
  809. #endif
  810. (ULONG)(ULONGLONG) EP,
  811. IntelDest);
  812. }
  813. return NativeSize;
  814. }
  815. ULONG
  816. PatchJmpDirectSlow(
  817. IN PULONG PatchAddr,
  818. IN ULONG IntelDest
  819. )
  820. /*++
  821. Routine Description:
  822. This routine patches a JMPDIRECT to a JMPDIRECT2. It is called when
  823. the native destination address of a jmp instruction is not yet known.
  824. It patches the jmp to jump directly to the corresponding native code.
  825. Arguments:
  826. PatchAddr -- address of the JMPDIRECT in the Translation Cache
  827. IntelDest -- intel address of the destination of the jmp
  828. Return Value:
  829. Native address to jump to in order to resume execution
  830. --*/
  831. {
  832. DWORD TCTimestamp;
  833. ULONG NativeDest;
  834. ULONG NativeSize;
  835. DECLARE_CPU;
  836. if (cpu->flag_tf) {
  837. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  838. }
  839. //
  840. // Switch from being a TC reader to a writer
  841. //
  842. TCTimestamp = TranslationCacheTimestamp;
  843. MrswReaderExit(&MrswTC);
  844. //
  845. // Compile the destination of the jmp and get the TC write lock
  846. //
  847. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip((PVOID)IntelDest, TRUE)->nativeStart;
  848. if (TCTimestamp == TranslationCacheTimestamp) {
  849. PULONG CodeLocation = PatchAddr - CallJmpDirectSlow_PATCHRA_OFFSET;
  850. //
  851. // The Translation Cache wasn't flushed - replace the JMPDIRECT
  852. // fragment by JMPDIRECT2
  853. //
  854. NativeSize = GenCallJmpDirectSlow2(CodeLocation,
  855. FALSE, // patching, not compiling
  856. #if _ALPHA_
  857. GetCurrentECU(CodeLocation),
  858. #endif
  859. (ULONG)NativeDest,
  860. IntelDest);
  861. NtFlushInstructionCache(
  862. NtCurrentProcess(),
  863. (PVOID)CodeLocation,
  864. NativeSize
  865. );
  866. } else {
  867. TCTimestamp = TranslationCacheTimestamp;
  868. if (cpu->CSTimestamp != TCTimestamp) {
  869. //
  870. // The cache was flushed by another thread in the small window
  871. // between mrsw calls in this thread, we plan on jumping directly
  872. // to NativeDest, so the CPU callstack needs to be flushed.
  873. // Normally this would be done in the CpuSimulate() loop as a
  874. // result of jumping to EndTranslatedCode.
  875. //
  876. FlushCallstack(cpu);
  877. }
  878. }
  879. //
  880. // Switch back to being a TC reader
  881. //
  882. MrswWriterExit(&MrswTC);
  883. MrswReaderEnter(&MrswTC);
  884. if (TCTimestamp == TranslationCacheTimestamp) {
  885. //
  886. // TC was not flushed - nativedest is valid
  887. //
  888. return NativeDest;
  889. } else {
  890. //
  891. // TC was flushed while becomming a TC reader again - nativedest
  892. // is now bogus.
  893. //
  894. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  895. }
  896. }
  897. ULONG
  898. PlaceJmpFwdDirect(
  899. IN PULONG CodeLocation,
  900. #if _ALPHA_
  901. IN ULONG CurrentECU,
  902. #endif
  903. IN PINSTRUCTION Instruction
  904. )
  905. /*++
  906. Routine Description:
  907. This routine copies the unconditional jump fragment into place and patches
  908. the instructions that jump to EndTranslatedCode
  909. Arguments:
  910. Instruction - Supplies a description of the instruction the fragment
  911. represents
  912. CodeLocation - Supplies the address the code for the fragment has been
  913. copied to
  914. Return Value:
  915. Size of code placed at CodeLocation
  916. --*/
  917. {
  918. DWORD IntelDest;
  919. PENTRYPOINT EP;
  920. ULONG NativeSize;
  921. // ASSUME: The first argument is always an immediate
  922. CPUASSERT( Instruction->Operand1.Type == OPND_NOCODEGEN );
  923. IntelDest = Instruction->Operand1.Immed;
  924. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)IntelDest);
  925. if (EP == NULL) {
  926. //
  927. // Knowing NativeDest requires compilation. Just place the unpatched version for
  928. // now and patch it later if necessary
  929. //
  930. NativeSize = GenCallJmpFwdDirect(CodeLocation,
  931. #if _ALPHA_
  932. CurrentECU,
  933. #endif
  934. Instruction);
  935. } else {
  936. //
  937. // We can place the patched version right away!
  938. //
  939. NativeSize = GenCallJmpFwdDirect2(CodeLocation,
  940. TRUE, // compiling, not patching
  941. #if _ALPHA_
  942. CurrentECU,
  943. #endif
  944. (ULONG)(ULONGLONG) EP,
  945. 0);
  946. }
  947. return NativeSize;
  948. }
  949. ULONG
  950. PatchJmpFwdDirect(
  951. IN PULONG PatchAddr,
  952. IN ULONG IntelDest
  953. )
  954. /*++
  955. Routine Description:
  956. This routine patches a JMPDIRECT to a JMPDIRECT2. It is called when
  957. the native destination address of a jmp instruction is not yet known.
  958. It patches the jmp to jump directly to the corresponding native code.
  959. Arguments:
  960. PatchAddr -- address of the JMPDIRECT in the Translation Cache
  961. IntelDest -- intel address of the destination of the jmp
  962. Return Value:
  963. Native address to jump to in order to resume execution
  964. --*/
  965. {
  966. DWORD TCTimestamp;
  967. ULONG NativeDest;
  968. ULONG NativeSize;
  969. DECLARE_CPU;
  970. if (cpu->flag_tf) {
  971. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  972. }
  973. //
  974. // Switch from being a TC reader to a writer
  975. //
  976. TCTimestamp = TranslationCacheTimestamp;
  977. MrswReaderExit(&MrswTC);
  978. //
  979. // Compile the destination of the jmp and get the TC write lock
  980. //
  981. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip((PVOID)IntelDest, TRUE)->nativeStart;
  982. if (TCTimestamp == TranslationCacheTimestamp) {
  983. PULONG CodeLocation = PatchAddr - CallJmpFwdDirect_PATCHRA_OFFSET;
  984. //
  985. // The Translation Cache wasn't flushed - replace the JMPDIRECT
  986. // fragment by JMPDIRECT2
  987. //
  988. NativeSize = GenCallJmpFwdDirect2(CodeLocation,
  989. FALSE, // patching, not compiling
  990. #if _ALPHA_
  991. GetCurrentECU(CodeLocation),
  992. #endif
  993. (ULONG)NativeDest,
  994. 0);
  995. NtFlushInstructionCache(
  996. NtCurrentProcess(),
  997. (PVOID)CodeLocation,
  998. NativeSize
  999. );
  1000. } else {
  1001. TCTimestamp = TranslationCacheTimestamp;
  1002. if (cpu->CSTimestamp != TCTimestamp) {
  1003. //
  1004. // The cache was flushed by another thread in the small window
  1005. // between mrsw calls in this thread, we plan on jumping directly
  1006. // to NativeDest, so the CPU callstack needs to be flushed.
  1007. // Normally this would be done in the CpuSimulate() loop as a
  1008. // result of jumping to EndTranslatedCode.
  1009. //
  1010. FlushCallstack(cpu);
  1011. }
  1012. }
  1013. //
  1014. // Switch back to being a TC reader
  1015. //
  1016. MrswWriterExit(&MrswTC);
  1017. MrswReaderEnter(&MrswTC);
  1018. if (TCTimestamp == TranslationCacheTimestamp) {
  1019. //
  1020. // TC was not flushed - nativedest is valid
  1021. //
  1022. return NativeDest;
  1023. } else {
  1024. //
  1025. // TC was flushed while becomming a TC reader again - nativedest
  1026. // is now bogus.
  1027. //
  1028. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1029. }
  1030. }
  1031. ULONG
  1032. PlaceJmpfDirect(
  1033. IN PULONG CodeLocation,
  1034. #if _ALPHA_
  1035. IN ULONG CurrentECU,
  1036. #endif
  1037. IN PINSTRUCTION Instruction
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. This routine copies the unconditional jump fragment into place and patches
  1042. the instructions that jump to EndTranslatedCode
  1043. Arguments:
  1044. Instruction - Supplies a description of the instruction the fragment
  1045. represents
  1046. CodeLocation - Supplies the address the code for the fragment has been
  1047. copied to
  1048. Return Value:
  1049. Size of code placed at CodeLocation
  1050. --*/
  1051. {
  1052. DWORD IntelDest;
  1053. PENTRYPOINT EP;
  1054. ULONG NativeSize;
  1055. // ASSUME: The first argument is always an IMM, pointing at the address
  1056. CPUASSERT( Instruction->Operand1.Type == OPND_IMM );
  1057. IntelDest = Instruction->Operand1.Immed;
  1058. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)*(UNALIGNED DWORD *)IntelDest);
  1059. if (EP == NULL) {
  1060. //
  1061. // Knowing NativeDest requires compilation. Just place the unpatched
  1062. // version for now and patch it later if necessary
  1063. //
  1064. NativeSize = GenCallJmpfDirect(CodeLocation,
  1065. #if _ALPHA_
  1066. CurrentECU,
  1067. #endif
  1068. Instruction);
  1069. } else {
  1070. //
  1071. // We can place the patched version right away!
  1072. //
  1073. NativeSize = GenCallJmpfDirect2(CodeLocation,
  1074. TRUE, // compiling, not patching
  1075. #if _ALPHA_
  1076. CurrentECU,
  1077. #endif
  1078. (ULONG)(ULONGLONG) EP,
  1079. 0);
  1080. }
  1081. return NativeSize;
  1082. }
  1083. ULONG
  1084. PatchJmpfDirect(
  1085. PTHREADSTATE cpu,
  1086. IN PULONG pIntelDest,
  1087. IN PULONG PatchAddr
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. This routine patches a JMPFDIRECT to a JMPFDIRECT2. It is called when
  1092. the native destination address of a jmp instruction is not yet known.
  1093. It patches the jmp to jump directly to the corresponding native code.
  1094. Arguments:
  1095. PatchAddr -- address of the JMPDIRECT in the Translation Cache
  1096. pIntelDest -- intel address of the destination of the jmp
  1097. Return Value:
  1098. Native address to jump to in order to resume execution
  1099. --*/
  1100. {
  1101. DWORD TCTimestamp;
  1102. ULONG NativeDest;
  1103. PVOID IntelDest;
  1104. USHORT Sel;
  1105. ULONG NativeSize;
  1106. if (cpu->flag_tf) {
  1107. return (ULONG)(ULONGLONG)&EndTranslatedCode;
  1108. }
  1109. //
  1110. // Switch from being a TC reader to a writer
  1111. //
  1112. TCTimestamp = TranslationCacheTimestamp;
  1113. MrswReaderExit(&MrswTC);
  1114. //
  1115. // Compile the destination of the jmp and get the TC write lock
  1116. //
  1117. IntelDest = (PVOID)*(UNALIGNED DWORD *)pIntelDest;
  1118. Sel = *(UNALIGNED PUSHORT)(pIntelDest+1);
  1119. eip = (ULONG)(ULONGLONG) IntelDest;
  1120. CS = Sel;
  1121. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip(IntelDest, TRUE)->nativeStart;
  1122. if (TCTimestamp == TranslationCacheTimestamp) {
  1123. PULONG CodeLocation = PatchAddr - CallJmpfDirect_PATCHRA_OFFSET;
  1124. //
  1125. // The Translation Cache wasn't flushed - replace the JMPFDIRECT
  1126. // fragment by JMPFDIRECT2
  1127. //
  1128. NativeSize = GenCallJmpfDirect2(CodeLocation,
  1129. FALSE, // patching, not compiling
  1130. #if _ALPHA_
  1131. GetCurrentECU(CodeLocation),
  1132. #endif
  1133. (ULONG)NativeDest,
  1134. 0);
  1135. NtFlushInstructionCache(
  1136. NtCurrentProcess(),
  1137. (PVOID)CodeLocation,
  1138. NativeSize
  1139. );
  1140. } else {
  1141. TCTimestamp = TranslationCacheTimestamp;
  1142. if (cpu->CSTimestamp != TCTimestamp) {
  1143. //
  1144. // The cache was flushed by another thread in the small window
  1145. // between mrsw calls in this thread, we plan on jumping directly
  1146. // to NativeDest, so the CPU callstack needs to be flushed.
  1147. // Normally this would be done in the CpuSimulate() loop as a
  1148. // result of jumping to EndTranslatedCode.
  1149. //
  1150. FlushCallstack(cpu);
  1151. }
  1152. }
  1153. //
  1154. // Switch back to being a TC reader
  1155. //
  1156. MrswWriterExit(&MrswTC);
  1157. MrswReaderEnter(&MrswTC);
  1158. if (TCTimestamp == TranslationCacheTimestamp) {
  1159. //
  1160. // TC was not flushed - nativedest is valid
  1161. //
  1162. return NativeDest;
  1163. } else {
  1164. //
  1165. // TC was flushed while becomming a TC reader again - nativedest
  1166. // is now bogus.
  1167. //
  1168. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1169. }
  1170. }
  1171. ULONG
  1172. PlaceCallDirect(
  1173. IN PULONG CodeLocation,
  1174. #if _ALPHA_
  1175. IN ULONG CurrentECU,
  1176. #endif
  1177. IN PINSTRUCTION Instruction
  1178. )
  1179. /*++
  1180. Routine Description:
  1181. This routine copies the unconditional call fragment into place.
  1182. Arguments:
  1183. Instruction - Supplies a description of the instruction the fragment
  1184. represents
  1185. CodeLocation - Supplies the address the code for the fragment has been
  1186. copied to
  1187. Return Value:
  1188. Size of code placed at CodeLocation
  1189. --*/
  1190. {
  1191. DWORD IntelDest;
  1192. DWORD IntelNext;
  1193. PENTRYPOINT EP;
  1194. // ASSUME: The first argument is always an immediate
  1195. CPUASSERT( Instruction->Operand1.Type == OPND_IMM );
  1196. IntelDest = Instruction->Operand1.Immed;
  1197. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)IntelDest);
  1198. if (EP == NULL) {
  1199. //
  1200. // Knowing NativeDest requires compilation. Just place the unpatched
  1201. // version for now and patch it later if necessary
  1202. //
  1203. GenCallDirect(CodeLocation,
  1204. #if _ALPHA_
  1205. CurrentECU,
  1206. #endif
  1207. Instruction);
  1208. } else {
  1209. //
  1210. // We can place the patched version right away! Deterime if the
  1211. // NativeNext address is known.
  1212. //
  1213. IntelNext = Instruction->Operand2.Immed;
  1214. //
  1215. // If the current instruction is not the last one compiled, then
  1216. // NativeNext is CodeLocation+CallDirect_SIZE and CallDirect3 can
  1217. // be placed right away.
  1218. //
  1219. if (Instruction != &InstructionStream[NumberOfInstructions-1]) {
  1220. GenCallDirect3(CodeLocation,
  1221. TRUE, // compiling, not patching
  1222. #if _ALPHA_
  1223. CurrentECU,
  1224. #endif
  1225. (ULONG)(ULONGLONG) EP,
  1226. (ULONG)(ULONGLONG) (CodeLocation+CallDirect_SIZE));
  1227. } else {
  1228. GenCallDirect2(CodeLocation,
  1229. TRUE, // compiling, not patching
  1230. #if _ALPHA_
  1231. CurrentECU,
  1232. #endif
  1233. (ULONG)(ULONGLONG) EP,
  1234. 0);
  1235. }
  1236. }
  1237. return CallDirect_SIZE * sizeof(ULONG);
  1238. }
  1239. ULONG
  1240. PlaceCallfDirect(
  1241. IN PULONG CodeLocation,
  1242. #if _ALPHA_
  1243. IN ULONG CurrentECU,
  1244. #endif
  1245. IN PINSTRUCTION Instruction
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. This routine copies the unconditional FAR call fragment into place.
  1250. Arguments:
  1251. Instruction - Supplies a description of the instruction the fragment
  1252. represents
  1253. CodeLocation - Supplies the address the code for the fragment has been
  1254. copied to
  1255. Return Value:
  1256. Size of code placed at CodeLocation
  1257. --*/
  1258. {
  1259. DWORD IntelDest;
  1260. DWORD IntelAddr;
  1261. DWORD IntelNext;
  1262. PVOID NativeNext;
  1263. PENTRYPOINT EP;
  1264. // ASSUME: The first two arguments are pIntelDest and IntelNext, stored
  1265. // as immediates.
  1266. CPUASSERT( Instruction->Operand1.Type == OPND_IMM );
  1267. CPUASSERT( Instruction->Operand2.Type == OPND_IMM );
  1268. IntelAddr = Instruction->Operand1.Immed;
  1269. // Get the offset portion of the address (skipping the selector)
  1270. IntelDest = *(UNALIGNED DWORD *)(IntelAddr+2);
  1271. EP = NativeAddressFromEipNoCompileEPWrite((PVOID)IntelDest);
  1272. if (EP == NULL) {
  1273. //
  1274. // Knowing NativeDest requires compilation. Just place the unpatched
  1275. // version for now and patch it later if necessary
  1276. //
  1277. GenCallfDirect(CodeLocation,
  1278. #if _ALPHA_
  1279. CurrentECU,
  1280. #endif
  1281. Instruction);
  1282. } else {
  1283. //
  1284. // We can place the patched version right away! Deterime if the
  1285. // NativeNext address is known.
  1286. //
  1287. IntelNext = Instruction->Operand2.Immed;
  1288. //
  1289. // If the current instruction is not the last one compiled, then
  1290. // NativeNext is CodeLocation+CallfDirect_SIZE and CallDirect3 can
  1291. // be placed right away.
  1292. //
  1293. if (Instruction != &InstructionStream[NumberOfInstructions-1]) {
  1294. GenCallfDirect3(CodeLocation,
  1295. TRUE, // compiling, not patching
  1296. #if _ALPHA_
  1297. CurrentECU,
  1298. #endif
  1299. (ULONG)(ULONGLONG) EP,
  1300. (ULONG)(ULONGLONG) (CodeLocation+CallfDirect_SIZE));
  1301. } else {
  1302. GenCallfDirect2(CodeLocation,
  1303. TRUE, // compiling, not patching
  1304. #if _ALPHA_
  1305. CurrentECU,
  1306. #endif
  1307. (ULONG)(ULONGLONG) EP,
  1308. 0);
  1309. }
  1310. }
  1311. return CallfDirect_SIZE * sizeof(ULONG);
  1312. }
  1313. DWORD
  1314. PatchCallDirectExceptionFilter(
  1315. PTHREADSTATE cpu
  1316. )
  1317. /*++
  1318. Routine Description:
  1319. Called if CTRL_CallFrag() throws an exception from within
  1320. PatchCallDirect(). If this happens, the Translation Cache is in fact
  1321. unlocked, although cpu->fTCUnlocked == FALSE. Need to fix this up before
  1322. CpuResetToConsistentState() gets run and unlocks the cache a second time.
  1323. Arguments:
  1324. cpu
  1325. Return Value:
  1326. None.
  1327. --*/
  1328. {
  1329. //
  1330. // Indicate the TC read lock is not held.
  1331. //
  1332. cpu->fTCUnlocked = TRUE;
  1333. //
  1334. // Continue unwinding the stack
  1335. //
  1336. return EXCEPTION_CONTINUE_SEARCH;
  1337. }
  1338. ULONG
  1339. PatchCallDirect(
  1340. IN PTHREADSTATE Cpu,
  1341. IN ULONG IntelDest,
  1342. IN ULONG IntelNext,
  1343. IN PULONG PatchAddr
  1344. )
  1345. /*++
  1346. Routine Description:
  1347. This routine patches a CALLDIRECT to a CALLDIRECT2. It is called when
  1348. the native destination address of a call instruction is not yet known.
  1349. It patches the call to jump directly to the corresponding native code.
  1350. Arguments:
  1351. Cpu -- per-thread info
  1352. IntelDest -- intel address of the destination of the call
  1353. IntelNext -- intel address of the instruction following the call
  1354. PatchAddr -- address of the CALLDIRECT in the Translation Cache
  1355. Return Value:
  1356. Native address to jump to in order to resume execution
  1357. --*/
  1358. {
  1359. DWORD TCTimestamp;
  1360. ULONG NativeDest;
  1361. ULONG NativeSize;
  1362. //
  1363. // Switch from being a TC reader to a writer
  1364. //
  1365. TCTimestamp = TranslationCacheTimestamp;
  1366. MrswReaderExit(&MrswTC);
  1367. //
  1368. // Compile the code at the destination of the call and get the TC write lock
  1369. //
  1370. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip((PVOID)IntelDest, TRUE)->nativeStart;
  1371. if (TCTimestamp == TranslationCacheTimestamp) {
  1372. PULONG CodeLocation = PatchAddr - CallDirect_PATCHRA_OFFSET;
  1373. //
  1374. // The Translation Cache wasn't flushed - replace the CALLDIRECT
  1375. // fragment by CALLDIRECT2
  1376. //
  1377. NativeSize = GenCallDirect2(CodeLocation,
  1378. FALSE, // patching, not compiling
  1379. #if _ALPHA_
  1380. GetCurrentECU(CodeLocation),
  1381. #endif
  1382. NativeDest,
  1383. 0);
  1384. NtFlushInstructionCache(
  1385. NtCurrentProcess(),
  1386. CodeLocation,
  1387. NativeSize
  1388. );
  1389. } else {
  1390. TCTimestamp = TranslationCacheTimestamp;
  1391. if (Cpu->CSTimestamp != TCTimestamp) {
  1392. //
  1393. // The cache was flushed by another thread in the small window
  1394. // between mrsw calls in this thread, we plan on jumping directly
  1395. // to NativeDest, so the CPU callstack needs to be flushed.
  1396. // Normally this would be done in the CpuSimulate() loop as a
  1397. // result of jumping to EndTranslatedCode.
  1398. //
  1399. FlushCallstack(Cpu);
  1400. }
  1401. }
  1402. //
  1403. // Push IntelNext on the stack and update the stack optimization code.
  1404. // This must be done while still in TC write mode. If it isn't, then
  1405. // the transition back to TC reader may allow a TC cache flush, invalidating
  1406. // nativedest before it is written into the stack optimization. (The
  1407. // stack optimization is blown away whenever the TC is flushed, so if
  1408. // it is written in BEFORE the flush, it will just get blown away.
  1409. //
  1410. try {
  1411. CTRL_CallFrag(Cpu, IntelDest, IntelNext, 0 /* nativenext is unknown */);
  1412. } _except(PatchCallDirectExceptionFilter(Cpu)) {
  1413. // nothing to do - the exception filter does everything
  1414. }
  1415. //
  1416. // Become a TC reader again.
  1417. //
  1418. MrswWriterExit(&MrswTC);
  1419. MrswReaderEnter(&MrswTC);
  1420. Cpu->fTCUnlocked = FALSE;
  1421. if (TCTimestamp == TranslationCacheTimestamp) {
  1422. //
  1423. // TC was not flushed while becomming a reader again.
  1424. //
  1425. return NativeDest;
  1426. } else {
  1427. //
  1428. // TC was flushed - nativedest is invalid. The callstack optimization
  1429. // was deleted when the TC flush occurred, so do an EndTranslatedCode
  1430. // instead.
  1431. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1432. }
  1433. }
  1434. ULONG
  1435. PatchCallfDirect(
  1436. IN PTHREADSTATE cpu,
  1437. IN PUSHORT pIntelDest,
  1438. IN ULONG IntelNext,
  1439. IN PULONG PatchAddr
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. This routine patches a CALLFDIRECT to a CALLFDIRECT2. It is called when
  1444. the native destination address of a call instruction is not yet known.
  1445. It patches the call to jump directly to the corresponding native code.
  1446. Arguments:
  1447. cpu -- per-thread info
  1448. pIntelDest-- ptr to SEL:OFFSET intel address of the destination of the call
  1449. IntelNext -- intel address of the instruction following the call
  1450. PatchAddr -- address of the CALLDIRECT in the Translation Cache
  1451. Return Value:
  1452. Native address to jump to in order to resume execution
  1453. --*/
  1454. {
  1455. DWORD TCTimestamp;
  1456. ULONG NativeDest;
  1457. PVOID IntelDest;
  1458. ULONG NativeSize;
  1459. //
  1460. // Switch from being a TC reader to a writer
  1461. //
  1462. TCTimestamp = TranslationCacheTimestamp;
  1463. MrswReaderExit(&MrswTC);
  1464. //
  1465. // Compile the code at the destination of the call and get the TC write lock
  1466. //
  1467. IntelDest = (PVOID)*(UNALIGNED DWORD *)pIntelDest;
  1468. NativeDest = (ULONG)(ULONGLONG) NativeAddressFromEip(IntelDest, TRUE)->nativeStart;
  1469. if (TCTimestamp == TranslationCacheTimestamp) {
  1470. PULONG CodeLocation = PatchAddr - CallfDirect_PATCHRA_OFFSET;
  1471. //
  1472. // The Translation Cache wasn't flushed - replace the CALLDIRECT
  1473. // fragment by CALLDIRECT2
  1474. //
  1475. NativeSize = GenCallfDirect2(CodeLocation,
  1476. FALSE, // patching, not compiling
  1477. #if _ALPHA_
  1478. GetCurrentECU(CodeLocation),
  1479. #endif
  1480. NativeDest,
  1481. 0);
  1482. NtFlushInstructionCache(
  1483. NtCurrentProcess(),
  1484. CodeLocation,
  1485. NativeSize
  1486. );
  1487. } else {
  1488. TCTimestamp = TranslationCacheTimestamp;
  1489. if (cpu->CSTimestamp != TCTimestamp) {
  1490. //
  1491. // The cache was flushed by another thread in the small window
  1492. // between mrsw calls in this thread, we plan on jumping directly
  1493. // to NativeDest, so the CPU callstack needs to be flushed.
  1494. // Normally this would be done in the CpuSimulate() loop as a
  1495. // result of jumping to EndTranslatedCode.
  1496. //
  1497. FlushCallstack(cpu);
  1498. }
  1499. }
  1500. //
  1501. // Push IntelNext on the stack and update the stack optimization code.
  1502. // This must be done while still in TC write mode. If it isn't, then
  1503. // the transition back to TC reader may allow a TC cache flush, invalidating
  1504. // nativedest before it is written into the stack optimization. (The
  1505. // stack optimization is blown away whenever the TC is flushed, so if
  1506. // it is written in BEFORE the flush, it will just get blown away.
  1507. //
  1508. try {
  1509. CTRL_CallfFrag(cpu, pIntelDest, IntelNext, 0 /* nativenext is unknown */);
  1510. } _except(PatchCallDirectExceptionFilter(cpu)) {
  1511. // nothing to do - the exception filter does everything
  1512. }
  1513. //
  1514. // Become a TC reader again.
  1515. //
  1516. MrswWriterExit(&MrswTC);
  1517. MrswReaderEnter(&MrswTC);
  1518. cpu->fTCUnlocked = FALSE;
  1519. if (TCTimestamp == TranslationCacheTimestamp) {
  1520. //
  1521. // TC was not flushed while becomming a reader again.
  1522. //
  1523. return NativeDest;
  1524. } else {
  1525. //
  1526. // TC was flushed - nativedest is invalid. The callstack optimization
  1527. // was deleted when the TC flush occurred, so do an EndTranslatedCode
  1528. // instead.
  1529. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1530. }
  1531. }
  1532. ULONG
  1533. PatchCallDirect2(
  1534. IN PTHREADSTATE Cpu,
  1535. IN ULONG IntelDest,
  1536. IN ULONG IntelNext,
  1537. IN ULONG NativeDest,
  1538. IN PULONG PatchAddr
  1539. )
  1540. /*++
  1541. Routine Description:
  1542. This routine patches a CALLDIRECT2 to a CALLDIRECT3. It is called when
  1543. the native destination address of the instruction after the call is not yet
  1544. known. It patches the fragment to place the native address of the
  1545. instruction after the call on the optimized callstack.
  1546. Arguments:
  1547. Cpu -- per-thread info
  1548. IntelDest -- intel address of the destination of the call
  1549. IntelNext -- intel address of the instruction following the call
  1550. NativeDest -- native address of the destination of the call
  1551. PatchAddr -- address of the CALLDIRECT2 in the Translation Cache
  1552. Return Value:
  1553. Native address to jump to in order to resume execution
  1554. --*/
  1555. {
  1556. DWORD TCTimestamp;
  1557. ULONG NativeNext;
  1558. ULONG NativeSize;
  1559. TCTimestamp = TranslationCacheTimestamp;
  1560. MrswReaderExit(&MrswTC);
  1561. NativeNext = (ULONG)(ULONGLONG) NativeAddressFromEipNoCompile((PVOID)IntelNext);
  1562. if (NativeNext) {
  1563. PULONG CodeLocation;
  1564. //
  1565. // The code at the return address from the call has already been
  1566. // compiled. Replace CALLDIRECT2 by CALLDIRECT3. TC is locked
  1567. // for write.
  1568. //
  1569. if (TCTimestamp != TranslationCacheTimestamp) {
  1570. //
  1571. // The TC was flushed while switching from reader to writer.
  1572. // Become a TC reader again
  1573. //
  1574. MrswWriterExit(&MrswTC);
  1575. MrswReaderEnter(&MrswTC);
  1576. // The CALLDIRECT2 code is now gone, so set up for the call and
  1577. // then go to EndTranslatedCode to make the control transfer.
  1578. //
  1579. CTRL_CallFrag(Cpu,
  1580. IntelDest,
  1581. IntelNext,
  1582. 0 // nativenext is also unknown
  1583. );
  1584. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1585. }
  1586. CodeLocation = PatchAddr - CallDirect2_PATCHRA_OFFSET;
  1587. //
  1588. // Else the TC was not flushed, and nativenext is now known. Patch
  1589. // CALLDIRECT2 to be CALLDIRECT3
  1590. //
  1591. NativeSize = GenCallDirect3(CodeLocation,
  1592. FALSE, // patching, not compiling
  1593. #if _ALPHA_
  1594. GetCurrentECU(CodeLocation),
  1595. #endif
  1596. NativeDest,
  1597. NativeNext);
  1598. NtFlushInstructionCache(
  1599. NtCurrentProcess(),
  1600. CodeLocation,
  1601. NativeSize
  1602. );
  1603. //
  1604. // Push IntelNext on the stack and update the stack optimization code.
  1605. // This must be done while still in TC write mode. If it isn't, then
  1606. // the transition back to TC reader may allow a TC cache flush, invalidating
  1607. // nativedest before it is written into the stack optimization. (The
  1608. // stack optimization is blown away whenever the TC is flushed, so if
  1609. // it is written in BEFORE the flush, it will just get blown away.
  1610. //
  1611. CTRL_CallFrag(Cpu, IntelDest, IntelNext, NativeNext);
  1612. //
  1613. // Switch back to being a TC reader
  1614. //
  1615. MrswWriterExit(&MrswTC);
  1616. MrswReaderEnter(&MrswTC);
  1617. if (TCTimestamp != TranslationCacheTimestamp) {
  1618. //
  1619. // TC was flushed while we were becomming a reader again.
  1620. // nativedest and nativenext are invalid, but stack optimization
  1621. // code was flushed.
  1622. //
  1623. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1624. }
  1625. } else { // NativeNext == NULL, TC locked for Read
  1626. CTRL_CallFrag(Cpu, IntelDest, IntelNext, 0);
  1627. if (TCTimestamp != TranslationCacheTimestamp) {
  1628. //
  1629. // Cache was flushed by another thread. NativeDest is invalid.
  1630. //
  1631. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1632. }
  1633. }
  1634. return NativeDest;
  1635. }
  1636. ULONG
  1637. PatchCallfDirect2(
  1638. IN PTHREADSTATE Cpu,
  1639. IN PUSHORT pIntelDest,
  1640. IN ULONG IntelNext,
  1641. IN ULONG NativeDest,
  1642. IN PULONG PatchAddr
  1643. )
  1644. /*++
  1645. Routine Description:
  1646. This routine patches a CALLFDIRECT2 to a CALLFDIRECT3. It is called when
  1647. the native destination address of the instruction after the call is not yet
  1648. known. It patches the fragment to place the native address of the
  1649. instruction after the call on the optimized callstack.
  1650. Arguments:
  1651. Cpu -- per-thread info
  1652. pIntelDest-- ptr to SEL:OFFSET intel address of the destination of the call
  1653. IntelNext -- intel address of the instruction following the call
  1654. NativeDest -- native address of the destination of the call
  1655. PatchAddr -- address of the CALLDIRECT2 in the Translation Cache
  1656. Return Value:
  1657. Native address to jump to in order to resume execution
  1658. --*/
  1659. {
  1660. DWORD TCTimestamp;
  1661. ULONG NativeNext;
  1662. ULONG NativeSize;
  1663. TCTimestamp = TranslationCacheTimestamp;
  1664. MrswReaderExit(&MrswTC);
  1665. NativeNext = (ULONG)(ULONGLONG) NativeAddressFromEipNoCompile((PVOID)IntelNext);
  1666. if (NativeNext) {
  1667. PULONG CodeLocation;
  1668. //
  1669. // The code at the return address from the call has already been
  1670. // compiled. Replace CALLDIRECT2 by CALLDIRECT3. TC is locked
  1671. // for write.
  1672. //
  1673. if (TCTimestamp != TranslationCacheTimestamp) {
  1674. //
  1675. // The TC was flushed while switching from reader to writer.
  1676. // Become a TC reader again
  1677. //
  1678. MrswWriterExit(&MrswTC);
  1679. MrswReaderEnter(&MrswTC);
  1680. // The CALLFDIRECT2 code is now gone, so set up for the call and
  1681. // then go to EndTranslatedCode to make the control transfer.
  1682. //
  1683. CTRL_CallfFrag(Cpu,
  1684. pIntelDest,
  1685. IntelNext,
  1686. 0 // nativenext is also unknown
  1687. );
  1688. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1689. }
  1690. CodeLocation = PatchAddr - CallfDirect2_PATCHRA_OFFSET;
  1691. //
  1692. // Else the TC was not flushed, and nativenext is now known. Patch
  1693. // CALLFDIRECT2 to be CALLFDIRECT3
  1694. //
  1695. NativeSize = GenCallfDirect3(CodeLocation,
  1696. FALSE, // patching, not compiling
  1697. #if _ALPHA_
  1698. GetCurrentECU(CodeLocation),
  1699. #endif
  1700. NativeDest,
  1701. NativeNext);
  1702. NtFlushInstructionCache(
  1703. NtCurrentProcess(),
  1704. CodeLocation,
  1705. NativeSize
  1706. );
  1707. //
  1708. // Push IntelNext on the stack and update the stack optimization code.
  1709. // This must be done while still in TC write mode. If it isn't, then
  1710. // the transition back to TC reader may allow a TC cache flush, invalidating
  1711. // nativedest before it is written into the stack optimization. (The
  1712. // stack optimization is blown away whenever the TC is flushed, so if
  1713. // it is written in BEFORE the flush, it will just get blown away.
  1714. //
  1715. CTRL_CallfFrag(Cpu, pIntelDest, IntelNext, NativeNext);
  1716. //
  1717. // Switch back to being a TC reader
  1718. //
  1719. MrswWriterExit(&MrswTC);
  1720. MrswReaderEnter(&MrswTC);
  1721. if (TCTimestamp != TranslationCacheTimestamp) {
  1722. //
  1723. // TC was flushed while we were becomming a reader again.
  1724. // nativedest and nativenext are invalid, but stack optimization
  1725. // code was flushed.
  1726. //
  1727. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1728. }
  1729. } else { // NativeNext == NULL, TC locked for Read
  1730. CTRL_CallfFrag(Cpu, pIntelDest, IntelNext, 0);
  1731. if (TCTimestamp != TranslationCacheTimestamp) {
  1732. //
  1733. // Cache was flushed by another thread. NativeDest is invalid.
  1734. //
  1735. return (ULONG)(ULONGLONG) &EndTranslatedCode;
  1736. }
  1737. }
  1738. return NativeDest;
  1739. }
  1740. DWORD
  1741. PatchCallIndirectExceptionFilter(
  1742. PTHREADSTATE cpu
  1743. )
  1744. /*++
  1745. Routine Description:
  1746. Called if CTRL_CallFrag() throws an exception from within
  1747. PatchCallIndirect(). If this happens, the Translation Cache Write lock
  1748. is being held. This must be released before the exception can be
  1749. allowed to continue.
  1750. Arguments:
  1751. cpu
  1752. Return Value:
  1753. None.
  1754. --*/
  1755. {
  1756. //
  1757. // Release the TC write lock.
  1758. //
  1759. MrswWriterExit(&MrswTC);
  1760. //
  1761. // Indicate the TC read lock is not held, either
  1762. //
  1763. cpu->fTCUnlocked = TRUE;
  1764. //
  1765. // Continue unwinding the stack
  1766. //
  1767. return EXCEPTION_CONTINUE_SEARCH;
  1768. }
  1769. VOID
  1770. PatchCallIndirect(
  1771. IN PTHREADSTATE Cpu,
  1772. IN ULONG IntelDest,
  1773. IN ULONG IntelNext,
  1774. IN PULONG PatchAddr
  1775. )
  1776. /*++
  1777. Routine Description:
  1778. This routine patches a CALLINDIRECT to a CALLINDIRECT2. It is called when
  1779. the native destination address of the instruction after the call is not yet
  1780. known. It patches the fragment to place the native address of the
  1781. instruction after the call on the optimized callstack.
  1782. Arguments:
  1783. Cpu -- per-thread info
  1784. IntelDest -- intel address of the destination of the call
  1785. IntelNext -- intel address of the instruction following the call
  1786. PatchAddr -- address of the CALLDIRECT2 in the Translation Cache
  1787. Return Value:
  1788. None. cpu->Eip updated to be IntelDest.
  1789. --*/
  1790. {
  1791. DWORD TCTimestamp;
  1792. ULONG NativeNext;
  1793. ULONG NativeSize;
  1794. TCTimestamp = TranslationCacheTimestamp;
  1795. MrswReaderExit(&MrswTC);
  1796. NativeNext = (ULONG)(ULONGLONG) NativeAddressFromEipNoCompile((PVOID)IntelNext);
  1797. if (NativeNext) {
  1798. PULONG CodeLocation;
  1799. //
  1800. // The code at the return address from the call has already been
  1801. // compiled. Replace CALLINDIRECT by CALLINDIRECT2. TC is locked
  1802. // for write.
  1803. //
  1804. if (TCTimestamp != TranslationCacheTimestamp) {
  1805. //
  1806. // The TC was flushed while switching from reader to writer.
  1807. // Become a TC reader again
  1808. //
  1809. MrswWriterExit(&MrswTC);
  1810. MrswReaderEnter(&MrswTC);
  1811. // The CALLINDIRECT code is now gone, so set up for the call
  1812. // without patching anything
  1813. //
  1814. CTRL_CallFrag(
  1815. Cpu,
  1816. IntelDest,
  1817. IntelNext,
  1818. 0 // nativenext is unknown
  1819. );
  1820. return;
  1821. }
  1822. //
  1823. // Else the TC was not flushed, and nativenext is now known. Patch
  1824. // CALLINDIRECT to be CALLINDIRECT2
  1825. //
  1826. CodeLocation = PatchAddr - CallIndirect_PATCHRA_OFFSET;
  1827. NativeSize = GenCallIndirect2(CodeLocation,
  1828. FALSE, // patching, not compiling
  1829. #if _ALPHA_
  1830. GetCurrentECU(CodeLocation),
  1831. #endif
  1832. NativeNext,
  1833. getUniqueIndex());
  1834. NtFlushInstructionCache(
  1835. NtCurrentProcess(),
  1836. CodeLocation,
  1837. NativeSize
  1838. );
  1839. //
  1840. // Push IntelNext on the stack and update the stack optimization code.
  1841. // This must be done while still in TC write mode. If it isn't, then
  1842. // the transition back to TC reader may allow a TC cache flush, invalidating
  1843. // nativedest before it is written into the stack optimization. (The
  1844. // stack optimization is blown away whenever the TC is flushed, so if
  1845. // it is written in BEFORE the flush, it will just get blown away.
  1846. //
  1847. _try {
  1848. CTRL_CallFrag(Cpu, IntelDest, IntelNext, NativeNext);
  1849. } _except(PatchCallIndirectExceptionFilter(Cpu)) {
  1850. // nothing to do - the exception filter does everything
  1851. }
  1852. //
  1853. // Switch back to being a TC reader. TC flushes during the switch
  1854. // are OK and require no extra work.
  1855. //
  1856. MrswWriterExit(&MrswTC);
  1857. MrswReaderEnter(&MrswTC);
  1858. } else { // NativeNext == NULL, TC locked for read.
  1859. CTRL_CallFrag(Cpu, IntelDest, IntelNext, 0);
  1860. }
  1861. return;
  1862. }
  1863. VOID
  1864. PatchCallfIndirect(
  1865. IN PTHREADSTATE Cpu,
  1866. IN PUSHORT pIntelDest,
  1867. IN ULONG IntelNext,
  1868. IN PULONG PatchAddr
  1869. )
  1870. /*++
  1871. Routine Description:
  1872. This routine patches a CALLFINDIRECT to a CALLFINDIRECT2. It is called when
  1873. the native destination address of the instruction after the call is not yet
  1874. known. It patches the fragment to place the native address of the
  1875. instruction after the call on the optimized callstack.
  1876. Arguments:
  1877. Cpu -- per-thread info
  1878. pIntelDest-- ptr to SEL:OFFSET intel address of the destination of the call
  1879. IntelNext -- intel address of the instruction following the call
  1880. PatchAddr -- address of the CALLDIRECT2 in the Translation Cache
  1881. Return Value:
  1882. None. cpu->eip updated to IntelDest
  1883. --*/
  1884. {
  1885. DWORD TCTimestamp;
  1886. ULONG NativeNext;
  1887. ULONG IntelDest;
  1888. ULONG NativeSize;
  1889. TCTimestamp = TranslationCacheTimestamp;
  1890. MrswReaderExit(&MrswTC);
  1891. IntelDest = *(UNALIGNED DWORD *)pIntelDest;
  1892. NativeNext = (ULONG)(ULONGLONG) NativeAddressFromEipNoCompile((PVOID)IntelNext);
  1893. if (NativeNext) {
  1894. PULONG CodeLocation;
  1895. //
  1896. // The code at the return address from the call has already been
  1897. // compiled. Replace CALLINDIRECT by CALLINDIRECT2. TC is locked
  1898. // for write.
  1899. //
  1900. if (TCTimestamp != TranslationCacheTimestamp) {
  1901. //
  1902. // The TC was flushed while switching from reader to writer.
  1903. // Become a TC reader again
  1904. //
  1905. MrswWriterExit(&MrswTC);
  1906. MrswReaderEnter(&MrswTC);
  1907. // The CALLFINDIRECT code is now gone, so set up for the call
  1908. // without patching anything
  1909. //
  1910. CTRL_CallfFrag(
  1911. Cpu,
  1912. pIntelDest,
  1913. IntelNext,
  1914. 0 // nativenext is unknown
  1915. );
  1916. return;
  1917. }
  1918. //
  1919. // Else the TC was not flushed, and nativenext is now known. Patch
  1920. // CALLFINDIRECT to be CALLFINDIRECT2
  1921. //
  1922. CodeLocation = PatchAddr - CallfIndirect_PATCHRA_OFFSET;
  1923. NativeSize = GenCallfIndirect2(CodeLocation,
  1924. FALSE, // patching, not compiling
  1925. #if _ALPHA_
  1926. GetCurrentECU(CodeLocation),
  1927. #endif
  1928. NativeNext,
  1929. getUniqueIndex());
  1930. NtFlushInstructionCache(
  1931. NtCurrentProcess(),
  1932. CodeLocation,
  1933. NativeSize
  1934. );
  1935. //
  1936. // Push IntelNext on the stack and update the stack optimization code.
  1937. // This must be done while still in TC write mode. If it isn't, then
  1938. // the transition back to TC reader may allow a TC cache flush, invalidating
  1939. // nativedest before it is written into the stack optimization. (The
  1940. // stack optimization is blown away whenever the TC is flushed, so if
  1941. // it is written in BEFORE the flush, it will just get blown away.
  1942. //
  1943. _try {
  1944. CTRL_CallfFrag(Cpu, pIntelDest, IntelNext, NativeNext);
  1945. } _except(PatchCallIndirectExceptionFilter(Cpu)) {
  1946. // nothing to do - the exception filter does everything
  1947. }
  1948. //
  1949. // Switch back to being a TC reader. TC flushes during the switch
  1950. // are OK and require no extra work.
  1951. //
  1952. MrswWriterExit(&MrswTC);
  1953. MrswReaderEnter(&MrswTC);
  1954. } else { // NativeNext == NULL, TC locked for read.
  1955. CTRL_CallfFrag(Cpu, pIntelDest, IntelNext, 0);
  1956. }
  1957. return;
  1958. }
  1959. //*********************************************************************************
  1960. // Below are functions for the Indirect Control Transfer Table
  1961. //*********************************************************************************
  1962. // This number must be below 0xffff, because we want to be able to load it with just
  1963. // one instruction (now we use ori). It should also be a factor of two to get good
  1964. // code generation for % (so that we won't have to use a division instruction).
  1965. #define MAX_TABLE_ENTRIES 0x1000
  1966. typedef struct _IndirControlTransferTable {
  1967. ULONG intelAddr;
  1968. ULONG nativeAddr;
  1969. } INDIRCONTROLTRANSFERTABLE, *PINDIRCONTROLTRANSFERTABLE;
  1970. INDIRCONTROLTRANSFERTABLE IndirControlTransferTable[MAX_TABLE_ENTRIES];
  1971. // The last used index in the table
  1972. ULONG lastTableIndex;
  1973. ULONG
  1974. getUniqueIndex(
  1975. VOID
  1976. )
  1977. /*++
  1978. Routine Description:
  1979. This function returns the next free index to the indirect control
  1980. transfer table. If it reaches the end of the table, it wraps around.
  1981. NOTE: we need not worry about synchronization here, because we have
  1982. an Entry Point write lock whenever we are called.
  1983. Arguments:
  1984. none
  1985. Return Value:
  1986. An index into the table
  1987. --*/
  1988. {
  1989. return (lastTableIndex = ((lastTableIndex + 1) % MAX_TABLE_ENTRIES));
  1990. }
  1991. VOID
  1992. FlushIndirControlTransferTable(
  1993. VOID
  1994. )
  1995. /*++
  1996. Routine Description:
  1997. This routine flushes the Indirect Control Transfer Table
  1998. NOTE: we need not worry about synchronizations here, because the routine
  1999. which calls us (FlushTranslationCache) has a Translation Cache write lock.
  2000. Arguments:
  2001. none
  2002. Return Value:
  2003. none
  2004. --*/
  2005. {
  2006. RtlZeroMemory (IndirControlTransferTable, sizeof(INDIRCONTROLTRANSFERTABLE)*MAX_TABLE_ENTRIES);
  2007. lastTableIndex = 0;
  2008. }
  2009. ULONG
  2010. IndirectControlTransfer(
  2011. IN ULONG tableEntry,
  2012. IN ULONG intelAddr,
  2013. IN PTHREADSTATE cpu
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. This routine is used by an indirect control transfer operation to try
  2018. and save a call to the Entry Point Manager.
  2019. Arguments:
  2020. tableEntry -- The index of the table entry where information might be
  2021. available about intelAddr
  2022. intelAddr -- The intel address we want to go to
  2023. cpu -- pointer to per-thread CPU data
  2024. Return Value:
  2025. The native address we want to go to
  2026. --*/
  2027. {
  2028. ULONG nativeAddr;
  2029. DWORD TCTimestamp;
  2030. //
  2031. // Detect apps which do the following:
  2032. // call foo
  2033. // where
  2034. // foo: mov eax, [esp]
  2035. // ...
  2036. // jmp eax ; this is really a 'ret' instruction
  2037. //
  2038. // This is the way _alloca() works - you call it with eax==number of bytes
  2039. // to allocate, and it jumps back to its caller with esp munged.
  2040. //
  2041. // What happens is the callstack cache gets out-of-sync. If the app
  2042. // is trying to do an indirect jump to the address already on the
  2043. // callstack cache, we will pop the callstack cache.
  2044. //
  2045. if (ISTOPOF_CALLSTACK(intelAddr)) {
  2046. POP_CALLSTACK(intelAddr, nativeAddr);
  2047. if (nativeAddr) {
  2048. return nativeAddr;
  2049. }
  2050. }
  2051. // First see if the table is filled in correctly already
  2052. MrswReaderEnter(&MrswIndirTable);
  2053. if (IndirControlTransferTable[tableEntry].intelAddr == intelAddr){
  2054. nativeAddr = IndirControlTransferTable[tableEntry].nativeAddr;
  2055. if (nativeAddr) {
  2056. MrswReaderExit(&MrswIndirTable);
  2057. return nativeAddr;
  2058. }
  2059. }
  2060. MrswReaderExit(&MrswIndirTable);
  2061. // Give up the translation cache reading lock so that we can call NativeAddressFromEip
  2062. TCTimestamp = TranslationCacheTimestamp;
  2063. MrswReaderExit(&MrswTC);
  2064. nativeAddr = (ULONG) (ULONGLONG)NativeAddressFromEip((PVOID)intelAddr, FALSE)->nativeStart;
  2065. // Note: we now have a TC read lock obtained by NativeAddressFromEip.
  2066. if (TCTimestamp == TranslationCacheTimestamp) {
  2067. // We haven't flushed the cache. Save the native address in the table.
  2068. MrswWriterEnter(&MrswIndirTable);
  2069. IndirControlTransferTable[tableEntry].intelAddr = intelAddr;
  2070. IndirControlTransferTable[tableEntry].nativeAddr = nativeAddr;
  2071. MrswWriterExit(&MrswIndirTable);
  2072. } else {
  2073. //
  2074. // Translation cache was flushed, possibly by another thread.
  2075. // Flush our callstack before resuming execution of RISC code
  2076. // in the Translation Cache.
  2077. //
  2078. FlushCallstack(cpu);
  2079. }
  2080. // Return the native address to IndirectControlTransferHelper which will go there.
  2081. return nativeAddr;
  2082. }
  2083. ULONG
  2084. IndirectControlTransferFar(
  2085. IN PTHREADSTATE cpu,
  2086. IN PUSHORT pintelAddr,
  2087. IN ULONG tableEntry
  2088. )
  2089. /*++
  2090. Routine Description:
  2091. This routine is used by a FAR indirect control transfer operation to try
  2092. and save a call to the Entry Point Manager.
  2093. Arguments:
  2094. tableEntry -- The index of the table entry where information might be
  2095. available about intelAddr
  2096. pintelAddr -- Pointer to SEL:OFFSET intel address we want to go to
  2097. Return Value:
  2098. The native address we want to go to
  2099. --*/
  2100. {
  2101. USHORT Sel;
  2102. ULONG Offset;
  2103. Offset = *(UNALIGNED PULONG)pintelAddr;
  2104. Sel = *(UNALIGNED PUSHORT)(pintelAddr+2);
  2105. CS = Sel;
  2106. eip = Offset;
  2107. return IndirectControlTransfer(tableEntry, Offset, cpu);
  2108. }
  2109. ULONG
  2110. PlaceNop(
  2111. IN PULONG CodeLocation,
  2112. #if _ALPHA_
  2113. IN ULONG CurrentECU,
  2114. #endif
  2115. IN PINSTRUCTION Instruction
  2116. )
  2117. {
  2118. return 0;
  2119. }
  2120. #if _ALPHA_
  2121. ULONG
  2122. GetCurrentECU(
  2123. PULONG CodeLocation
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. This routine returns the correct ECU. CurrentECU is the target for
  2128. branch instructions when a fragment wants to jump to EndTranslatedCode.
  2129. N.B. This routine cannot change the global CurrentECU. This is set in
  2130. Compile(), and is the only way to locate the ECU at the end of
  2131. the translation cache if the exception info hasn't been placed
  2132. yet.
  2133. Arguments:
  2134. CodeLocation -- The code location which will be patched.
  2135. Return Value:
  2136. None.
  2137. --*/
  2138. {
  2139. //
  2140. // Find an EndCompilationUnit fragment by searching the Translation Cache
  2141. // for the next EXCEPTIONDATA_SIGNATURE. The code immediately before it
  2142. // is an EndCompilationUnit fragment.
  2143. //
  2144. while (*CodeLocation != EXCEPTIONDATA_SIGNATURE) {
  2145. CodeLocation++;
  2146. }
  2147. return (ULONG)(ULONGLONG)(CodeLocation-EndCompilationUnit_SIZE);
  2148. }
  2149. #endif // _ALPHA_-only