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