JitCacheInvalidation.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using ARMeilleure.Memory;
  2. using System.Runtime.InteropServices;
  3. namespace Ryujinx.Cpu.LightningJit.Cache
  4. {
  5. class JitCacheInvalidation
  6. {
  7. private static readonly int[] _invalidationCode =
  8. [
  9. unchecked((int)0xd53b0022), // mrs x2, ctr_el0
  10. unchecked((int)0xd3504c44), // ubfx x4, x2, #16, #4
  11. unchecked((int)0x52800083), // mov w3, #0x4
  12. unchecked((int)0x12000c45), // and w5, w2, #0xf
  13. unchecked((int)0x1ac42064), // lsl w4, w3, w4
  14. unchecked((int)0x51000482), // sub w2, w4, #0x1
  15. unchecked((int)0x8a220002), // bic x2, x0, x2
  16. unchecked((int)0x1ac52063), // lsl w3, w3, w5
  17. unchecked((int)0xeb01005f), // cmp x2, x1
  18. unchecked((int)0x93407c84), // sxtw x4, w4
  19. unchecked((int)0x540000a2), // b.cs 3c <do_ic_clear>
  20. unchecked((int)0xd50b7b22), // dc cvau, x2
  21. unchecked((int)0x8b040042), // add x2, x2, x4
  22. unchecked((int)0xeb02003f), // cmp x1, x2
  23. unchecked((int)0x54ffffa8), // b.hi 2c <dc_clear_loop>
  24. unchecked((int)0xd5033b9f), // dsb ish
  25. unchecked((int)0x51000462), // sub w2, w3, #0x1
  26. unchecked((int)0x93407c63), // sxtw x3, w3
  27. unchecked((int)0x8a220000), // bic x0, x0, x2
  28. unchecked((int)0xeb00003f), // cmp x1, x0
  29. unchecked((int)0x540000a9), // b.ls 64 <exit>
  30. unchecked((int)0xd50b7520), // ic ivau, x0
  31. unchecked((int)0x8b030000), // add x0, x0, x3
  32. unchecked((int)0xeb00003f), // cmp x1, x0
  33. unchecked((int)0x54ffffa8), // b.hi 54 <ic_clear_loop>
  34. unchecked((int)0xd5033b9f), // dsb ish
  35. unchecked((int)0xd5033fdf), // isb
  36. unchecked((int)0xd65f03c0) // ret
  37. ];
  38. private delegate void InvalidateCache(ulong start, ulong end);
  39. private readonly InvalidateCache _invalidateCache;
  40. private readonly ReservedRegion _invalidateCacheCodeRegion;
  41. private readonly bool _needsInvalidation;
  42. public JitCacheInvalidation(IJitMemoryAllocator allocator)
  43. {
  44. // On macOS and Windows, a different path is used to write to the JIT cache, which does the invalidation.
  45. if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
  46. {
  47. ulong size = (ulong)_invalidationCode.Length * sizeof(int);
  48. ulong mask = (ulong)ReservedRegion.DefaultGranularity - 1;
  49. size = (size + mask) & ~mask;
  50. _invalidateCacheCodeRegion = new ReservedRegion(allocator, size);
  51. _invalidateCacheCodeRegion.ExpandIfNeeded(size);
  52. Marshal.Copy(_invalidationCode, 0, _invalidateCacheCodeRegion.Pointer, _invalidationCode.Length);
  53. _invalidateCacheCodeRegion.Block.MapAsRx(0, size);
  54. _invalidateCache = Marshal.GetDelegateForFunctionPointer<InvalidateCache>(_invalidateCacheCodeRegion.Pointer);
  55. _needsInvalidation = true;
  56. }
  57. }
  58. public void Invalidate(nint basePointer, ulong size)
  59. {
  60. if (_needsInvalidation)
  61. {
  62. _invalidateCache((ulong)basePointer, (ulong)basePointer + size);
  63. }
  64. }
  65. }
  66. }