HvExecutionContextVcpu.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. using ARMeilleure.State;
  2. using Ryujinx.Memory;
  3. using System;
  4. using System.Runtime.InteropServices;
  5. using System.Runtime.Versioning;
  6. namespace Ryujinx.Cpu.AppleHv
  7. {
  8. [SupportedOSPlatform("macos")]
  9. class HvExecutionContextVcpu : IHvExecutionContext
  10. {
  11. private static readonly MemoryBlock _setSimdFpRegFuncMem;
  12. private delegate HvResult SetSimdFpReg(ulong vcpu, HvSimdFPReg reg, in V128 value, nint funcPtr);
  13. private static readonly SetSimdFpReg _setSimdFpReg;
  14. private static readonly nint _setSimdFpRegNativePtr;
  15. static HvExecutionContextVcpu()
  16. {
  17. // .NET does not support passing vectors by value, so we need to pass a pointer and use a native
  18. // function to load the value into a vector register.
  19. _setSimdFpRegFuncMem = new MemoryBlock(MemoryBlock.GetPageSize());
  20. _setSimdFpRegFuncMem.Write(0, 0x3DC00040u); // LDR Q0, [X2]
  21. _setSimdFpRegFuncMem.Write(4, 0xD61F0060u); // BR X3
  22. _setSimdFpRegFuncMem.Reprotect(0, _setSimdFpRegFuncMem.Size, MemoryPermission.ReadAndExecute);
  23. _setSimdFpReg = Marshal.GetDelegateForFunctionPointer<SetSimdFpReg>(_setSimdFpRegFuncMem.Pointer);
  24. if (NativeLibrary.TryLoad(HvApi.LibraryName, out nint hvLibHandle))
  25. {
  26. _setSimdFpRegNativePtr = NativeLibrary.GetExport(hvLibHandle, nameof(HvApi.hv_vcpu_set_simd_fp_reg));
  27. }
  28. }
  29. public ulong Pc
  30. {
  31. get
  32. {
  33. HvApi.hv_vcpu_get_reg(_vcpu, HvReg.PC, out ulong pc).ThrowOnError();
  34. return pc;
  35. }
  36. set
  37. {
  38. HvApi.hv_vcpu_set_reg(_vcpu, HvReg.PC, value).ThrowOnError();
  39. }
  40. }
  41. public ulong ElrEl1
  42. {
  43. get
  44. {
  45. HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.ELR_EL1, out ulong elr).ThrowOnError();
  46. return elr;
  47. }
  48. set
  49. {
  50. HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.ELR_EL1, value).ThrowOnError();
  51. }
  52. }
  53. public ulong EsrEl1
  54. {
  55. get
  56. {
  57. HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.ESR_EL1, out ulong esr).ThrowOnError();
  58. return esr;
  59. }
  60. set
  61. {
  62. HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.ESR_EL1, value).ThrowOnError();
  63. }
  64. }
  65. public long TpidrEl0
  66. {
  67. get
  68. {
  69. HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.TPIDR_EL0, out ulong tpidrEl0).ThrowOnError();
  70. return (long)tpidrEl0;
  71. }
  72. set
  73. {
  74. HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.TPIDR_EL0, (ulong)value).ThrowOnError();
  75. }
  76. }
  77. public long TpidrroEl0
  78. {
  79. get
  80. {
  81. HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.TPIDRRO_EL0, out ulong tpidrroEl0).ThrowOnError();
  82. return (long)tpidrroEl0;
  83. }
  84. set
  85. {
  86. HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.TPIDRRO_EL0, (ulong)value).ThrowOnError();
  87. }
  88. }
  89. public uint Pstate
  90. {
  91. get
  92. {
  93. HvApi.hv_vcpu_get_reg(_vcpu, HvReg.CPSR, out ulong cpsr).ThrowOnError();
  94. return (uint)cpsr;
  95. }
  96. set
  97. {
  98. HvApi.hv_vcpu_set_reg(_vcpu, HvReg.CPSR, (ulong)value).ThrowOnError();
  99. }
  100. }
  101. public uint Fpcr
  102. {
  103. get
  104. {
  105. HvApi.hv_vcpu_get_reg(_vcpu, HvReg.FPCR, out ulong fpcr).ThrowOnError();
  106. return (uint)fpcr;
  107. }
  108. set
  109. {
  110. HvApi.hv_vcpu_set_reg(_vcpu, HvReg.FPCR, (ulong)value).ThrowOnError();
  111. }
  112. }
  113. public uint Fpsr
  114. {
  115. get
  116. {
  117. HvApi.hv_vcpu_get_reg(_vcpu, HvReg.FPSR, out ulong fpsr).ThrowOnError();
  118. return (uint)fpsr;
  119. }
  120. set
  121. {
  122. HvApi.hv_vcpu_set_reg(_vcpu, HvReg.FPSR, (ulong)value).ThrowOnError();
  123. }
  124. }
  125. private readonly ulong _vcpu;
  126. public HvExecutionContextVcpu(ulong vcpu)
  127. {
  128. _vcpu = vcpu;
  129. }
  130. public ulong GetX(int index)
  131. {
  132. if (index == 31)
  133. {
  134. HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.SP_EL0, out ulong value).ThrowOnError();
  135. return value;
  136. }
  137. else
  138. {
  139. HvApi.hv_vcpu_get_reg(_vcpu, HvReg.X0 + (uint)index, out ulong value).ThrowOnError();
  140. return value;
  141. }
  142. }
  143. public void SetX(int index, ulong value)
  144. {
  145. if (index == 31)
  146. {
  147. HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.SP_EL0, value).ThrowOnError();
  148. }
  149. else
  150. {
  151. HvApi.hv_vcpu_set_reg(_vcpu, HvReg.X0 + (uint)index, value).ThrowOnError();
  152. }
  153. }
  154. public V128 GetV(int index)
  155. {
  156. HvApi.hv_vcpu_get_simd_fp_reg(_vcpu, HvSimdFPReg.Q0 + (uint)index, out HvSimdFPUchar16 value).ThrowOnError();
  157. return new V128(value.Low, value.High);
  158. }
  159. public void SetV(int index, V128 value)
  160. {
  161. _setSimdFpReg(_vcpu, HvSimdFPReg.Q0 + (uint)index, value, _setSimdFpRegNativePtr).ThrowOnError();
  162. }
  163. public void RequestInterrupt()
  164. {
  165. ulong vcpu = _vcpu;
  166. HvApi.hv_vcpus_exit(ref vcpu, 1);
  167. }
  168. }
  169. }