diff --git a/src/ARMeilleure/Memory/IJitMemoryAllocator.cs b/src/ARMeilleure/Memory/IJitMemoryAllocator.cs
index 171bfd2f1..ff64bf13e 100644
--- a/src/ARMeilleure/Memory/IJitMemoryAllocator.cs
+++ b/src/ARMeilleure/Memory/IJitMemoryAllocator.cs
@@ -4,7 +4,5 @@ namespace ARMeilleure.Memory
{
IJitMemoryBlock Allocate(ulong size);
IJitMemoryBlock Reserve(ulong size);
-
- ulong GetPageSize();
}
}
diff --git a/src/ARMeilleure/Memory/MemoryManagerType.cs b/src/ARMeilleure/Memory/MemoryManagerType.cs
index 1e656ba27..b1cdbb069 100644
--- a/src/ARMeilleure/Memory/MemoryManagerType.cs
+++ b/src/ARMeilleure/Memory/MemoryManagerType.cs
@@ -31,7 +31,7 @@ namespace ARMeilleure.Memory
HostMappedUnsafe,
}
- static class MemoryManagerTypeExtensions
+ public static class MemoryManagerTypeExtensions
{
public static bool IsHostMapped(this MemoryManagerType type)
{
diff --git a/src/ARMeilleure/Signal/NativeSignalHandler.cs b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
similarity index 62%
rename from src/ARMeilleure/Signal/NativeSignalHandler.cs
rename to src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
index 31ec16cb1..c5e708e16 100644
--- a/src/ARMeilleure/Signal/NativeSignalHandler.cs
+++ b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
@@ -1,63 +1,14 @@
using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.Memory;
using ARMeilleure.Translation;
-using ARMeilleure.Translation.Cache;
using System;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Signal
{
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- struct SignalHandlerRange
+ public static class NativeSignalHandlerGenerator
{
- public int IsActive;
- public nuint RangeAddress;
- public nuint RangeEndAddress;
- public IntPtr ActionPointer;
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- struct SignalHandlerConfig
- {
- ///
- /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct.
- ///
- public int StructAddressOffset;
-
- ///
- /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct.
- ///
- public int StructWriteOffset;
-
- ///
- /// The sigaction handler that was registered before this one. (unix only)
- ///
- public nuint UnixOldSigaction;
-
- ///
- /// The type of the previous sigaction. True for the 3 argument variant. (unix only)
- ///
- public int UnixOldSigaction3Arg;
-
- public SignalHandlerRange Range0;
- public SignalHandlerRange Range1;
- public SignalHandlerRange Range2;
- public SignalHandlerRange Range3;
- public SignalHandlerRange Range4;
- public SignalHandlerRange Range5;
- public SignalHandlerRange Range6;
- public SignalHandlerRange Range7;
- }
-
- public static class NativeSignalHandler
- {
- private delegate void UnixExceptionHandler(int sig, IntPtr info, IntPtr ucontext);
- [UnmanagedFunctionPointer(CallingConvention.Winapi)]
- private delegate int VectoredExceptionHandler(IntPtr exceptionInfo);
-
- private const int MaxTrackedRanges = 8;
+ public const int MaxTrackedRanges = 8;
private const int StructAddressOffset = 0;
private const int StructWriteOffset = 4;
@@ -70,125 +21,10 @@ namespace ARMeilleure.Signal
private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
- private static ulong _pageSize;
- private static ulong _pageMask;
-
- private static readonly IntPtr _handlerConfig;
- private static IntPtr _signalHandlerPtr;
- private static IntPtr _signalHandlerHandle;
-
- private static readonly object _lock = new();
- private static bool _initialized;
-
- static NativeSignalHandler()
+ private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize, ulong pageSize)
{
- _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf());
- ref SignalHandlerConfig config = ref GetConfigRef();
+ ulong pageMask = pageSize - 1;
- config = new SignalHandlerConfig();
- }
-
- public static void Initialize(IJitMemoryAllocator allocator)
- {
- JitCache.Initialize(allocator);
- }
-
- public static void InitializeSignalHandler(ulong pageSize, Func customSignalHandlerFactory = null)
- {
- if (_initialized)
- {
- return;
- }
-
- lock (_lock)
- {
- if (_initialized)
- {
- return;
- }
-
- _pageSize = pageSize;
- _pageMask = pageSize - 1;
-
- ref SignalHandlerConfig config = ref GetConfigRef();
-
- if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
- {
- _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
-
- if (customSignalHandlerFactory != null)
- {
- _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
- }
-
- var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
-
- config.UnixOldSigaction = (nuint)(ulong)old.sa_handler;
- config.UnixOldSigaction3Arg = old.sa_flags & 4;
- }
- else
- {
- config.StructAddressOffset = 40; // ExceptionInformation1
- config.StructWriteOffset = 32; // ExceptionInformation0
-
- _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateWindowsSignalHandler(_handlerConfig));
-
- if (customSignalHandlerFactory != null)
- {
- _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr);
- }
-
- _signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
- }
-
- _initialized = true;
- }
- }
-
- private static unsafe ref SignalHandlerConfig GetConfigRef()
- {
- return ref Unsafe.AsRef((void*)_handlerConfig);
- }
-
- public static unsafe bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action)
- {
- var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0;
-
- for (int i = 0; i < MaxTrackedRanges; i++)
- {
- if (ranges[i].IsActive == 0)
- {
- ranges[i].RangeAddress = address;
- ranges[i].RangeEndAddress = endAddress;
- ranges[i].ActionPointer = action;
- ranges[i].IsActive = 1;
-
- return true;
- }
- }
-
- return false;
- }
-
- public static unsafe bool RemoveTrackedRegion(nuint address)
- {
- var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0;
-
- for (int i = 0; i < MaxTrackedRanges; i++)
- {
- if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address)
- {
- ranges[i].IsActive = 0;
-
- return true;
- }
- }
-
- return false;
- }
-
- private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite)
- {
Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
context.Copy(inRegionLocal, Const(0));
@@ -196,7 +32,7 @@ namespace ARMeilleure.Signal
for (int i = 0; i < MaxTrackedRanges; i++)
{
- ulong rangeBaseOffset = (ulong)(RangeOffset + i * Unsafe.SizeOf());
+ ulong rangeBaseOffset = (ulong)(RangeOffset + i * rangeStructSize);
Operand nextLabel = Label();
@@ -210,13 +46,12 @@ namespace ARMeilleure.Signal
// Is the fault address within this tracked region?
Operand inRange = context.BitwiseAnd(
context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI),
- context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI)
- );
+ context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI));
// Only call tracking if in range.
context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold);
- Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~_pageMask));
+ Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~pageMask));
// Call the tracking action, with the pointer's relative offset to the base address.
Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20));
@@ -227,7 +62,7 @@ namespace ARMeilleure.Signal
// Tracking action should be non-null to call it, otherwise assume false return.
context.BranchIfFalse(skipActionLabel, trackingActionPtr);
- Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite);
+ Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(pageSize), isWrite);
context.Copy(inRegionLocal, result);
context.MarkLabel(skipActionLabel);
@@ -269,8 +104,7 @@ namespace ARMeilleure.Signal
Operand esr = context.Load(OperandType.I64, context.Add(ctxPtr, Const(EsrOffset)));
return context.BitwiseAnd(esr, Const(0x40ul));
}
-
- if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
+ else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
{
const ulong ErrOffset = 4; // __es.__err
Operand err = context.Load(OperandType.I64, context.Add(ctxPtr, Const(ErrOffset)));
@@ -310,8 +144,7 @@ namespace ARMeilleure.Signal
Operand esr = context.Load(OperandType.I64, context.Add(auxPtr, Const(8ul)));
return context.BitwiseAnd(esr, Const(0x40ul));
}
-
- if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
+ else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
{
const int ErrOffset = 192; // uc_mcontext.gregs[REG_ERR]
Operand err = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(ErrOffset)));
@@ -322,7 +155,7 @@ namespace ARMeilleure.Signal
throw new PlatformNotSupportedException();
}
- private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr)
+ public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
{
EmitterContext context = new();
@@ -335,7 +168,7 @@ namespace ARMeilleure.Signal
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
- Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite);
+ Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
Operand endLabel = Label();
@@ -367,10 +200,10 @@ namespace ARMeilleure.Signal
OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 };
- return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map();
+ return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
}
- private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr)
+ public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
{
EmitterContext context = new();
@@ -399,7 +232,7 @@ namespace ARMeilleure.Signal
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
- Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite);
+ Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
Operand endLabel = Label();
@@ -421,7 +254,7 @@ namespace ARMeilleure.Signal
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
- return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map();
+ return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
}
}
}
diff --git a/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs b/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs
index 27a9ea83c..3bf6a4498 100644
--- a/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs
+++ b/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs
@@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using Ryujinx.Common.Memory.PartialUnmaps;
using System;
-
+using System.Runtime.InteropServices;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Signal
@@ -10,8 +10,28 @@ namespace ARMeilleure.Signal
///
/// Methods to handle signals caused by partial unmaps. See the structs for C# implementations of the methods.
///
- internal static class WindowsPartialUnmapHandler
+ internal static partial class WindowsPartialUnmapHandler
{
+ [LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
+ private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
+
+ [LibraryImport("kernel32.dll", SetLastError = true)]
+ private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
+
+ private static IntPtr _getCurrentThreadIdPtr;
+
+ public static IntPtr GetCurrentThreadIdFunc()
+ {
+ if (_getCurrentThreadIdPtr == IntPtr.Zero)
+ {
+ IntPtr handle = LoadLibrary("kernel32.dll");
+
+ _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
+ }
+
+ return _getCurrentThreadIdPtr;
+ }
+
public static Operand EmitRetryFromAccessViolation(EmitterContext context)
{
IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState;
@@ -20,7 +40,7 @@ namespace ARMeilleure.Signal
// Get the lock first.
EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
- IntPtr getCurrentThreadId = WindowsSignalHandlerRegistration.GetCurrentThreadIdFunc();
+ IntPtr getCurrentThreadId = GetCurrentThreadIdFunc();
Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32);
Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0));
@@ -137,17 +157,6 @@ namespace ARMeilleure.Signal
return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset));
}
-#pragma warning disable IDE0051 // Remove unused private member
- private static void EmitThreadLocalMapIntRelease(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand index)
- {
- Operand offset = context.Multiply(index, Const(sizeof(int)));
- Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap.ThreadIdsOffset));
- Operand idPtr = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset));
-
- context.CompareAndSwap(idPtr, threadId, Const(0));
- }
-#pragma warning restore IDE0051
-
private static void EmitAtomicAddI32(EmitterContext context, Operand ptr, Operand additive)
{
Operand loop = Label();
diff --git a/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs b/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs
deleted file mode 100644
index 5444da0ca..000000000
--- a/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Signal
-{
- unsafe partial class WindowsSignalHandlerRegistration
- {
- [LibraryImport("kernel32.dll")]
- private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
-
- [LibraryImport("kernel32.dll")]
- private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle);
-
- [LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
- private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
-
- [LibraryImport("kernel32.dll", SetLastError = true)]
- private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
-
- private static IntPtr _getCurrentThreadIdPtr;
-
- public static IntPtr RegisterExceptionHandler(IntPtr action)
- {
- return AddVectoredExceptionHandler(1, action);
- }
-
- public static bool RemoveExceptionHandler(IntPtr handle)
- {
- return RemoveVectoredExceptionHandler(handle) != 0;
- }
-
- public static IntPtr GetCurrentThreadIdFunc()
- {
- if (_getCurrentThreadIdPtr == IntPtr.Zero)
- {
- IntPtr handle = LoadLibrary("kernel32.dll");
-
- _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
- }
-
- return _getCurrentThreadIdPtr;
- }
- }
-}
diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs
index dc18038ba..7f6a25b07 100644
--- a/src/ARMeilleure/Translation/Translator.cs
+++ b/src/ARMeilleure/Translation/Translator.cs
@@ -79,11 +79,6 @@ namespace ARMeilleure.Translation
Stubs = new TranslatorStubs(this);
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
-
- if (memory.Type.IsHostMapped())
- {
- NativeSignalHandler.InitializeSignalHandler(allocator.GetPageSize());
- }
}
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
diff --git a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
index 24bc1e595..5876346a0 100644
--- a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
+++ b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
@@ -1,5 +1,7 @@
using ARMeilleure.Memory;
using ARMeilleure.Translation;
+using Ryujinx.Cpu.Signal;
+using Ryujinx.Memory;
namespace Ryujinx.Cpu.Jit
{
@@ -12,6 +14,12 @@ namespace Ryujinx.Cpu.Jit
{
_tickSource = tickSource;
_translator = new Translator(new JitMemoryAllocator(), memory, for64Bit);
+
+ if (memory.Type.IsHostMapped())
+ {
+ NativeSignalHandler.InitializeSignalHandler(MemoryBlock.GetPageSize());
+ }
+
memory.UnmapEvent += UnmapHandler;
}
diff --git a/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs b/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs
index 529a1a808..eb665c2df 100644
--- a/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs
+++ b/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs
@@ -7,7 +7,5 @@ namespace Ryujinx.Cpu.Jit
{
public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None);
public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.Jit);
-
- public ulong GetPageSize() => MemoryBlock.GetPageSize();
}
}
diff --git a/src/Ryujinx.Cpu/MemoryEhMeilleure.cs b/src/Ryujinx.Cpu/MemoryEhMeilleure.cs
index 54e232d9c..f3a5b056b 100644
--- a/src/Ryujinx.Cpu/MemoryEhMeilleure.cs
+++ b/src/Ryujinx.Cpu/MemoryEhMeilleure.cs
@@ -1,4 +1,4 @@
-using ARMeilleure.Signal;
+using Ryujinx.Cpu.Signal;
using Ryujinx.Memory;
using Ryujinx.Memory.Tracking;
using System;
diff --git a/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs
new file mode 100644
index 000000000..5a9d92cc4
--- /dev/null
+++ b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs
@@ -0,0 +1,179 @@
+using ARMeilleure.Signal;
+using Ryujinx.Common;
+using Ryujinx.Memory;
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Cpu.Signal
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct SignalHandlerRange
+ {
+ public int IsActive;
+ public nuint RangeAddress;
+ public nuint RangeEndAddress;
+ public IntPtr ActionPointer;
+ }
+
+ [InlineArray(NativeSignalHandlerGenerator.MaxTrackedRanges)]
+ struct SignalHandlerRangeArray
+ {
+ public SignalHandlerRange Range0;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct SignalHandlerConfig
+ {
+ ///
+ /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct.
+ ///
+ public int StructAddressOffset;
+
+ ///
+ /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct.
+ ///
+ public int StructWriteOffset;
+
+ ///
+ /// The sigaction handler that was registered before this one. (unix only)
+ ///
+ public nuint UnixOldSigaction;
+
+ ///
+ /// The type of the previous sigaction. True for the 3 argument variant. (unix only)
+ ///
+ public int UnixOldSigaction3Arg;
+
+ ///
+ /// Fixed size array of tracked ranges.
+ ///
+ public SignalHandlerRangeArray Ranges;
+ }
+
+ static class NativeSignalHandler
+ {
+ private static readonly IntPtr _handlerConfig;
+ private static IntPtr _signalHandlerPtr;
+
+ private static MemoryBlock _codeBlock;
+
+ private static readonly object _lock = new();
+ private static bool _initialized;
+
+ static NativeSignalHandler()
+ {
+ _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf());
+ ref SignalHandlerConfig config = ref GetConfigRef();
+
+ config = new SignalHandlerConfig();
+ }
+
+ public static void InitializeSignalHandler(ulong pageSize, Func customSignalHandlerFactory = null)
+ {
+ if (_initialized)
+ {
+ return;
+ }
+
+ lock (_lock)
+ {
+ if (_initialized)
+ {
+ return;
+ }
+
+ int rangeStructSize = Unsafe.SizeOf();
+
+ ref SignalHandlerConfig config = ref GetConfigRef();
+
+ if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+ {
+ _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateUnixSignalHandler(_handlerConfig, rangeStructSize, pageSize));
+
+ if (customSignalHandlerFactory != null)
+ {
+ _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
+ }
+
+ var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
+
+ config.UnixOldSigaction = (nuint)(ulong)old.sa_handler;
+ config.UnixOldSigaction3Arg = old.sa_flags & 4;
+ }
+ else
+ {
+ config.StructAddressOffset = 40; // ExceptionInformation1
+ config.StructWriteOffset = 32; // ExceptionInformation0
+
+ _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateWindowsSignalHandler(_handlerConfig, rangeStructSize, pageSize));
+
+ if (customSignalHandlerFactory != null)
+ {
+ _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr);
+ }
+
+ WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
+ }
+
+ _initialized = true;
+ }
+ }
+
+ private static IntPtr MapCode(ReadOnlySpan code)
+ {
+ Debug.Assert(_codeBlock == null);
+
+ ulong codeSizeAligned = BitUtils.AlignUp((ulong)code.Length, MemoryBlock.GetPageSize());
+
+ _codeBlock = new MemoryBlock(codeSizeAligned);
+ _codeBlock.Write(0, code);
+ _codeBlock.Reprotect(0, codeSizeAligned, MemoryPermission.ReadAndExecute);
+
+ return _codeBlock.Pointer;
+ }
+
+ private static unsafe ref SignalHandlerConfig GetConfigRef()
+ {
+ return ref Unsafe.AsRef((void*)_handlerConfig);
+ }
+
+ public static bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action)
+ {
+ Span ranges = GetConfigRef().Ranges;
+
+ for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++)
+ {
+ if (ranges[i].IsActive == 0)
+ {
+ ranges[i].RangeAddress = address;
+ ranges[i].RangeEndAddress = endAddress;
+ ranges[i].ActionPointer = action;
+ ranges[i].IsActive = 1;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static bool RemoveTrackedRegion(nuint address)
+ {
+ Span ranges = GetConfigRef().Ranges;
+
+ for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++)
+ {
+ if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address)
+ {
+ ranges[i].IsActive = 0;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs
similarity index 98%
rename from src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs
rename to src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs
index 70e9f2204..e88a6c0f6 100644
--- a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs
+++ b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs
@@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
-namespace ARMeilleure.Signal
+namespace Ryujinx.Cpu.Signal
{
static partial class UnixSignalHandlerRegistration
{
diff --git a/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs
new file mode 100644
index 000000000..1fbce0f72
--- /dev/null
+++ b/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Cpu.Signal
+{
+ static partial class WindowsSignalHandlerRegistration
+ {
+ [LibraryImport("kernel32.dll")]
+ private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
+
+ [LibraryImport("kernel32.dll")]
+ private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle);
+
+ public static IntPtr RegisterExceptionHandler(IntPtr action)
+ {
+ return AddVectoredExceptionHandler(1, action);
+ }
+
+ public static bool RemoveExceptionHandler(IntPtr handle)
+ {
+ return RemoveVectoredExceptionHandler(handle) != 0;
+ }
+ }
+}