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 }