From 9c510fec3e49b2744458b1449c40aa2964f2ebb2 Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Tue, 4 Jul 2023 09:20:14 +0000 Subject: [PATCH] add android bionic nce support --- src/Ryujinx.Cpu/Nce/NceThreadPal.cs | 12 +-- .../AndroidSignalHandlerRegistration.cs | 87 +++++++++++++++++++ src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs | 20 ++++- .../Signal/UnixSignalHandlerRegistration.cs | 22 ++--- 4 files changed, 120 insertions(+), 21 deletions(-) create mode 100644 src/Ryujinx.Cpu/Signal/AndroidSignalHandlerRegistration.cs diff --git a/src/Ryujinx.Cpu/Nce/NceThreadPal.cs b/src/Ryujinx.Cpu/Nce/NceThreadPal.cs index b59507995..77238b7fc 100644 --- a/src/Ryujinx.Cpu/Nce/NceThreadPal.cs +++ b/src/Ryujinx.Cpu/Nce/NceThreadPal.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Cpu.Nce public static IntPtr GetCurrentThreadHandle() { - if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid()) + if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || Ryujinx.Common.SystemInfo.SystemInfo.IsBionic) { return NceThreadPalUnix.GetCurrentThreadHandle(); } @@ -23,14 +23,14 @@ namespace Ryujinx.Cpu.Nce public static void SuspendThread(IntPtr handle) { - if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) - { - NceThreadPalUnix.SuspendThread(handle); - } - else if (OperatingSystem.IsAndroid()) + if (Ryujinx.Common.SystemInfo.SystemInfo.IsBionic) { NceThreadPalAndroid.SuspendThread(handle); } + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + { + NceThreadPalUnix.SuspendThread(handle); + } else { throw new PlatformNotSupportedException(); diff --git a/src/Ryujinx.Cpu/Signal/AndroidSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/AndroidSignalHandlerRegistration.cs new file mode 100644 index 000000000..a3f1ea740 --- /dev/null +++ b/src/Ryujinx.Cpu/Signal/AndroidSignalHandlerRegistration.cs @@ -0,0 +1,87 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.Signal +{ + static class AndroidSignalHandlerRegistration + { + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public unsafe struct SigSet + { + fixed long sa_mask[16]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct SigAction + { + public int sa_flags; + public IntPtr sa_handler; + public SigSet sa_mask; + public IntPtr sa_restorer; + } + + private const int SIGSEGV = 11; + private const int SA_SIGINFO = 0x00000004; + + [DllImport("libc", SetLastError = true)] + private static extern int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction); + + [DllImport("libc", SetLastError = true)] + private static extern int sigaction(int signum, IntPtr sigAction, out SigAction oldAction); + + [DllImport("libc", SetLastError = true)] + private static extern int sigemptyset(ref SigSet set); + + public static SigAction GetSegfaultExceptionHandler() + { + int result = sigaction(SIGSEGV, IntPtr.Zero, out SigAction old); + + if (result != 0) + { + throw new InvalidOperationException($"Could not get SIGSEGV sigaction. Error: {result}"); + } + + return old; + } + + public static SigAction RegisterExceptionHandler(IntPtr action, int userSignal = -1) + { + SigAction sig = new SigAction + { + sa_handler = action, + sa_flags = SA_SIGINFO + }; + + sigemptyset(ref sig.sa_mask); + + int result = sigaction(SIGSEGV, ref sig, out SigAction old); + + if (result != 0) + { + throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}"); + } + + if (userSignal != -1) + { + result = sigaction(userSignal, ref sig, out SigAction oldu); + + if (oldu.sa_handler != IntPtr.Zero) + { + throw new InvalidOperationException($"SIG{userSignal} is already in use."); + } + + if (result != 0) + { + throw new InvalidOperationException($"Could not register SIG{userSignal} sigaction. Error: {result}"); + } + } + + return old; + } + + public static bool RestoreExceptionHandler(SigAction oldAction) + { + return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0; + } + } +} diff --git a/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs index c37fd870e..bcd0fc1a7 100644 --- a/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs +++ b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs @@ -100,13 +100,25 @@ namespace Ryujinx.Cpu.Signal if (customSignalHandlerFactory != null) { - _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr); + _signalHandlerPtr = customSignalHandlerFactory(Ryujinx.Common.SystemInfo.SystemInfo.IsAndroid() ? + AndroidSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler : + UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr); } - var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr, userSignal); + if (Ryujinx.Common.SystemInfo.SystemInfo.IsAndroid()) + { + var old = AndroidSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr, userSignal); - config.UnixOldSigaction = (nuint)(ulong)old.sa_handler; - config.UnixOldSigaction3Arg = old.sa_flags & 4; + config.UnixOldSigaction = (nuint)(ulong)old.sa_handler; + config.UnixOldSigaction3Arg = old.sa_flags & 4; + } + else + { + var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr, userSignal); + + config.UnixOldSigaction = (nuint)(ulong)old.sa_handler; + config.UnixOldSigaction3Arg = old.sa_flags & 4; + } } else { diff --git a/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs index 80d280508..1d9f514eb 100644 --- a/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs +++ b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs @@ -148,20 +148,20 @@ namespace Ryujinx.Cpu.Signal throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}"); } } - } - if (userSignal != -1) - { - result = sigaction(userSignal, ref sig, out SigAction oldu); - - if (oldu.sa_handler != IntPtr.Zero) + if (userSignal != -1) { - throw new InvalidOperationException($"SIG{userSignal} is already in use."); - } + result = sigaction(userSignal, ref sig, out SigAction oldu); - if (result != 0) - { - throw new InvalidOperationException($"Could not register SIG{userSignal} sigaction. Error: {result}"); + if (oldu.sa_handler != IntPtr.Zero) + { + throw new InvalidOperationException($"SIG{userSignal} is already in use."); + } + + if (result != 0) + { + throw new InvalidOperationException($"Could not register SIG{userSignal} sigaction. Error: {result}"); + } } }