aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs')
-rw-r--r--Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs196
1 files changed, 196 insertions, 0 deletions
diff --git a/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs b/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
new file mode 100644
index 00000000..4f6ebefa
--- /dev/null
+++ b/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
@@ -0,0 +1,196 @@
+using ARMeilleure.State;
+using Ryujinx.Memory;
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace Ryujinx.Cpu.AppleHv
+{
+ class HvExecutionContextVcpu : IHvExecutionContext
+ {
+ private static MemoryBlock _setSimdFpRegFuncMem;
+ private delegate hv_result_t SetSimdFpReg(ulong vcpu, hv_simd_fp_reg_t reg, in V128 value, IntPtr funcPtr);
+ private static SetSimdFpReg _setSimdFpReg;
+ private static IntPtr _setSimdFpRegNativePtr;
+
+ static HvExecutionContextVcpu()
+ {
+ // .NET does not support passing vectors by value, so we need to pass a pointer and use a native
+ // function to load the value into a vector register.
+ _setSimdFpRegFuncMem = new MemoryBlock(MemoryBlock.GetPageSize());
+ _setSimdFpRegFuncMem.Write(0, 0x3DC00040u); // LDR Q0, [X2]
+ _setSimdFpRegFuncMem.Write(4, 0xD61F0060u); // BR X3
+ _setSimdFpRegFuncMem.Reprotect(0, _setSimdFpRegFuncMem.Size, MemoryPermission.ReadAndExecute);
+
+ _setSimdFpReg = Marshal.GetDelegateForFunctionPointer<SetSimdFpReg>(_setSimdFpRegFuncMem.Pointer);
+
+ if (NativeLibrary.TryLoad(HvApi.LibraryName, out IntPtr hvLibHandle))
+ {
+ _setSimdFpRegNativePtr = NativeLibrary.GetExport(hvLibHandle, nameof(HvApi.hv_vcpu_set_simd_fp_reg));
+ }
+ }
+
+ public ulong Pc
+ {
+ get
+ {
+ HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_PC, out ulong pc).ThrowOnError();
+ return pc;
+ }
+ set
+ {
+ HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_PC, value).ThrowOnError();
+ }
+ }
+
+ public ulong ElrEl1
+ {
+ get
+ {
+ HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_ELR_EL1, out ulong elr).ThrowOnError();
+ return elr;
+ }
+ set
+ {
+ HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_ELR_EL1, value).ThrowOnError();
+ }
+ }
+
+ public ulong EsrEl1
+ {
+ get
+ {
+ HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_ESR_EL1, out ulong esr).ThrowOnError();
+ return esr;
+ }
+ set
+ {
+ HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_ESR_EL1, value).ThrowOnError();
+ }
+ }
+
+ public long TpidrEl0
+ {
+ get
+ {
+ HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_TPIDR_EL0, out ulong tpidrEl0).ThrowOnError();
+ return (long)tpidrEl0;
+ }
+ set
+ {
+ HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_TPIDR_EL0, (ulong)value).ThrowOnError();
+ }
+ }
+
+ public long TpidrroEl0
+ {
+ get
+ {
+ HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_TPIDRRO_EL0, out ulong tpidrroEl0).ThrowOnError();
+ return (long)tpidrroEl0;
+ }
+ set
+ {
+ HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_TPIDRRO_EL0, (ulong)value).ThrowOnError();
+ }
+ }
+
+ public uint Pstate
+ {
+ get
+ {
+ HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_CPSR, out ulong cpsr).ThrowOnError();
+ return (uint)cpsr;
+ }
+ set
+ {
+ HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_CPSR, (ulong)value).ThrowOnError();
+ }
+ }
+
+ public uint Fpcr
+ {
+ get
+ {
+ HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_FPCR, out ulong fpcr).ThrowOnError();
+ return (uint)fpcr;
+ }
+ set
+ {
+ HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_FPCR, (ulong)value).ThrowOnError();
+ }
+ }
+
+ public uint Fpsr
+ {
+ get
+ {
+ HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_FPSR, out ulong fpsr).ThrowOnError();
+ return (uint)fpsr;
+ }
+ set
+ {
+ HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_FPSR, (ulong)value).ThrowOnError();
+ }
+ }
+
+ private ulong _vcpu;
+ private int _interruptRequested;
+
+ public HvExecutionContextVcpu(ulong vcpu)
+ {
+ _vcpu = vcpu;
+ }
+
+ public ulong GetX(int index)
+ {
+ if (index == 31)
+ {
+ HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_SP_EL0, out ulong value).ThrowOnError();
+ return value;
+ }
+ else
+ {
+ HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_X0 + (uint)index, out ulong value).ThrowOnError();
+ return value;
+ }
+ }
+
+ public void SetX(int index, ulong value)
+ {
+ if (index == 31)
+ {
+ HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_SP_EL0, value).ThrowOnError();
+ }
+ else
+ {
+ HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_X0 + (uint)index, value).ThrowOnError();
+ }
+ }
+
+ public V128 GetV(int index)
+ {
+ HvApi.hv_vcpu_get_simd_fp_reg(_vcpu, hv_simd_fp_reg_t.HV_SIMD_FP_REG_Q0 + (uint)index, out hv_simd_fp_uchar16_t value).ThrowOnError();
+ return new V128(value.Low, value.High);
+ }
+
+ public void SetV(int index, V128 value)
+ {
+ _setSimdFpReg(_vcpu, hv_simd_fp_reg_t.HV_SIMD_FP_REG_Q0 + (uint)index, value, _setSimdFpRegNativePtr).ThrowOnError();
+ }
+
+ public void RequestInterrupt()
+ {
+ if (Interlocked.Exchange(ref _interruptRequested, 1) == 0)
+ {
+ ulong vcpu = _vcpu;
+ HvApi.hv_vcpus_exit(ref vcpu, 1);
+ }
+ }
+
+ public bool GetAndClearInterruptRequested()
+ {
+ return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
+ }
+ }
+} \ No newline at end of file