diff options
Diffstat (limited to 'ARMeilleure')
| -rw-r--r-- | ARMeilleure/Instructions/InstEmitMemoryHelper.cs | 70 | ||||
| -rw-r--r-- | ARMeilleure/Memory/IMemoryManager.cs | 52 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryManagerType.cs | 41 | ||||
| -rw-r--r-- | ARMeilleure/Signal/NativeSignalHandler.cs | 327 | ||||
| -rw-r--r-- | ARMeilleure/Signal/UnixSignalHandlerRegistration.cs | 57 | ||||
| -rw-r--r-- | ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs | 24 | ||||
| -rw-r--r-- | ARMeilleure/Translation/PTC/Ptc.cs | 23 | ||||
| -rw-r--r-- | ARMeilleure/Translation/Translator.cs | 6 |
8 files changed, 581 insertions, 19 deletions
diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs index 2d7b6799..2de12304 100644 --- a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs +++ b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs @@ -1,5 +1,6 @@ using ARMeilleure.Decoders; using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Memory; using ARMeilleure.Translation; using ARMeilleure.Translation.PTC; using System; @@ -141,13 +142,16 @@ namespace ARMeilleure.Instructions SetInt(context, rt, value); - context.Branch(lblEnd); + if (!context.Memory.Type.IsHostMapped()) + { + context.Branch(lblEnd); - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); + context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - EmitReadIntFallback(context, address, rt, size); + EmitReadIntFallback(context, address, rt, size); - context.MarkLabel(lblEnd); + context.MarkLabel(lblEnd); + } } public static Operand EmitReadIntAligned(ArmEmitterContext context, Operand address, int size) @@ -195,13 +199,16 @@ namespace ARMeilleure.Instructions context.Copy(GetVec(rt), value); - context.Branch(lblEnd); + if (!context.Memory.Type.IsHostMapped()) + { + context.Branch(lblEnd); - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); + context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - EmitReadVectorFallback(context, address, vector, rt, elem, size); + EmitReadVectorFallback(context, address, vector, rt, elem, size); - context.MarkLabel(lblEnd); + context.MarkLabel(lblEnd); + } } private static Operand VectorCreate(ArmEmitterContext context, Operand value) @@ -231,13 +238,16 @@ namespace ARMeilleure.Instructions case 3: context.Store (physAddr, value); break; } - context.Branch(lblEnd); + if (!context.Memory.Type.IsHostMapped()) + { + context.Branch(lblEnd); - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); + context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - EmitWriteIntFallback(context, address, rt, size); + EmitWriteIntFallback(context, address, rt, size); - context.MarkLabel(lblEnd); + context.MarkLabel(lblEnd); + } } public static void EmitWriteIntAligned(ArmEmitterContext context, Operand address, Operand value, int size) @@ -291,17 +301,25 @@ namespace ARMeilleure.Instructions case 4: context.Store (physAddr, value); break; } - context.Branch(lblEnd); + if (!context.Memory.Type.IsHostMapped()) + { + context.Branch(lblEnd); - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); + context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - EmitWriteVectorFallback(context, address, rt, elem, size); + EmitWriteVectorFallback(context, address, rt, elem, size); - context.MarkLabel(lblEnd); + context.MarkLabel(lblEnd); + } } public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write, int size) { + if (context.Memory.Type.IsHostMapped()) + { + return EmitHostMappedPointer(context, address); + } + int ptLevelBits = context.Memory.AddressSpaceBits - PageBits; int ptLevelSize = 1 << ptLevelBits; int ptLevelMask = ptLevelSize - 1; @@ -380,6 +398,26 @@ namespace ARMeilleure.Instructions return context.Add(pte, pageOffset); } + public static Operand EmitHostMappedPointer(ArmEmitterContext context, Operand address) + { + if (address.Type == OperandType.I32) + { + address = context.ZeroExtend32(OperandType.I64, address); + } + + if (context.Memory.Type == MemoryManagerType.HostMapped) + { + Operand mask = Const(ulong.MaxValue >> (64 - context.Memory.AddressSpaceBits)); + address = context.BitwiseAnd(address, mask); + } + + Operand baseAddr = Ptc.State == PtcState.Disabled + ? Const(context.Memory.PageTablePointer.ToInt64()) + : Const(context.Memory.PageTablePointer.ToInt64(), true, Ptc.PageTablePointerIndex); + + return context.Add(baseAddr, address); + } + private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size) { MethodInfo info = null; diff --git a/ARMeilleure/Memory/IMemoryManager.cs b/ARMeilleure/Memory/IMemoryManager.cs index cacfc4ac..0a25eb97 100644 --- a/ARMeilleure/Memory/IMemoryManager.cs +++ b/ARMeilleure/Memory/IMemoryManager.cs @@ -8,16 +8,68 @@ namespace ARMeilleure.Memory IntPtr PageTablePointer { get; } + MemoryManagerType Type { get; } + + event Action<ulong, ulong> UnmapEvent; + + /// <summary> + /// Reads data from CPU mapped memory. + /// </summary> + /// <typeparam name="T">Type of the data being read</typeparam> + /// <param name="va">Virtual address of the data in memory</param> + /// <returns>The data</returns> T Read<T>(ulong va) where T : unmanaged; + + /// <summary> + /// Reads data from CPU mapped memory, with read tracking + /// </summary> + /// <typeparam name="T">Type of the data being read</typeparam> + /// <param name="va">Virtual address of the data in memory</param> + /// <returns>The data</returns> T ReadTracked<T>(ulong va) where T : unmanaged; + + /// <summary> + /// Writes data to CPU mapped memory. + /// </summary> + /// <typeparam name="T">Type of the data being written</typeparam> + /// <param name="va">Virtual address to write the data into</param> + /// <param name="value">Data to be written</param> void Write<T>(ulong va, T value) where T : unmanaged; + /// <summary> + /// Gets a read-only span of data from CPU mapped memory. + /// </summary> + /// <param name="va">Virtual address of the data</param> + /// <param name="size">Size of the data</param> + /// <param name="tracked">True if read tracking is triggered on the span</param> + /// <returns>A read-only span of the data</returns> ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false); + /// <summary> + /// Gets a reference for the given type at the specified virtual memory address. + /// </summary> + /// <remarks> + /// The data must be located at a contiguous memory region. + /// </remarks> + /// <typeparam name="T">Type of the data to get the reference</typeparam> + /// <param name="va">Virtual address of the data</param> + /// <returns>A reference to the data in memory</returns> ref T GetRef<T>(ulong va) where T : unmanaged; + /// <summary> + /// Checks if the page at a given CPU virtual address is mapped. + /// </summary> + /// <param name="va">Virtual address to check</param> + /// <returns>True if the address is mapped, false otherwise</returns> bool IsMapped(ulong va); + /// <summary> + /// Alerts the memory tracking that a given region has been read from or written to. + /// This should be called before read/write is performed. + /// </summary> + /// <param name="va">Virtual address of the region</param> + /// <param name="size">Size of the region</param> + /// <param name="write">True if the region was written, false if read</param> void SignalMemoryTracking(ulong va, ulong size, bool write); } }
\ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManagerType.cs b/ARMeilleure/Memory/MemoryManagerType.cs new file mode 100644 index 00000000..ce84ccaf --- /dev/null +++ b/ARMeilleure/Memory/MemoryManagerType.cs @@ -0,0 +1,41 @@ +namespace ARMeilleure.Memory +{ + /// <summary> + /// Indicates the type of a memory manager and the method it uses for memory mapping + /// and address translation. This controls the code generated for memory accesses on the JIT. + /// </summary> + public enum MemoryManagerType + { + /// <summary> + /// Complete software MMU implementation, the read/write methods are always called, + /// without any attempt to perform faster memory access. + /// </summary> + SoftwareMmu, + + /// <summary> + /// High level implementation using a software flat page table for address translation, + /// used to speed up address translation if possible without calling the read/write methods. + /// </summary> + SoftwarePageTable, + + /// <summary> + /// High level implementation with mappings managed by the host OS, effectively using hardware + /// page tables. No address translation is performed in software and the memory is just accessed directly. + /// </summary> + HostMapped, + + /// <summary> + /// Same as the host mapped memory manager type, but without masking the address within the address space. + /// Allows invalid access from JIT code to the rest of the program, but is faster. + /// </summary> + HostMappedUnsafe + } + + static class MemoryManagerTypeExtensions + { + public static bool IsHostMapped(this MemoryManagerType type) + { + return type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe; + } + } +} diff --git a/ARMeilleure/Signal/NativeSignalHandler.cs b/ARMeilleure/Signal/NativeSignalHandler.cs new file mode 100644 index 00000000..e5387ca6 --- /dev/null +++ b/ARMeilleure/Signal/NativeSignalHandler.cs @@ -0,0 +1,327 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Signal +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SignalHandlerRange + { + public int IsActive; + public nuint RangeAddress; + public nuint RangeEndAddress; + public IntPtr ActionPointer; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SignalHandlerConfig + { + /// <summary> + /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct. + /// </summary> + public int StructAddressOffset; + + /// <summary> + /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct. + /// </summary> + public int StructWriteOffset; + + /// <summary> + /// The sigaction handler that was registered before this one. (unix only) + /// </summary> + public nuint UnixOldSigaction; + + /// <summary> + /// The type of the previous sigaction. True for the 3 argument variant. (unix only) + /// </summary> + 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; + + private const int StructAddressOffset = 0; + private const int StructWriteOffset = 4; + private const int UnixOldSigaction = 8; + private const int UnixOldSigaction3Arg = 16; + private const int RangeOffset = 20; + + private const int EXCEPTION_CONTINUE_SEARCH = 0; + private const int EXCEPTION_CONTINUE_EXECUTION = -1; + + private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005; + + private const ulong PageSize = 0x1000; + private const ulong PageMask = PageSize - 1; + + private static IntPtr _handlerConfig; + private static IntPtr _signalHandlerPtr; + private static IntPtr _signalHandlerHandle; + + private static readonly object _lock = new object(); + private static bool _initialized; + + static NativeSignalHandler() + { + _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf<SignalHandlerConfig>()); + ref SignalHandlerConfig config = ref GetConfigRef(); + + config = new SignalHandlerConfig(); + } + + public static void InitializeSignalHandler() + { + if (_initialized) return; + + lock (_lock) + { + if (_initialized) return; + + Translator.PreparePool(); + + bool unix = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + ref SignalHandlerConfig config = ref GetConfigRef(); + + if (unix) + { + // Unix siginfo struct locations. + // NOTE: These are incredibly likely to be different between kernel version and architectures. + + config.StructAddressOffset = 16; // si_addr + config.StructWriteOffset = 8; // si_code + + _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig)); + + SigAction 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)); + + _signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); + } + + Translator.ResetPool(); + + Translator.DisposePools(); + + _initialized = true; + } + } + + private static unsafe ref SignalHandlerConfig GetConfigRef() + { + return ref Unsafe.AsRef<SignalHandlerConfig>((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)); + + Operand endLabel = Label(); + + for (int i = 0; i < MaxTrackedRanges; i++) + { + ulong rangeBaseOffset = (ulong)(RangeOffset + i * Unsafe.SizeOf<SignalHandlerRange>()); + + Operand nextLabel = Label(); + + Operand isActive = context.Load(OperandType.I32, Const((ulong)signalStructPtr + rangeBaseOffset)); + + context.BranchIfFalse(nextLabel, isActive); + + Operand rangeAddress = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 4)); + Operand rangeEndAddress = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 12)); + + // Is the fault address within this tracked region? + Operand inRange = context.BitwiseAnd( + context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI), + context.ICompare(faultAddress, rangeEndAddress, Comparison.Less) + ); + + // Only call tracking if in range. + context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold); + + context.Copy(inRegionLocal, Const(1)); + 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)); + context.Call(trackingActionPtr, OperandType.I32, offset, Const(PageSize), isWrite); + + context.Branch(endLabel); + + context.MarkLabel(nextLabel); + } + + context.MarkLabel(endLabel); + + return context.Copy(inRegionLocal); + } + + private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr) + { + EmitterContext context = new EmitterContext(); + + // (int sig, SigInfo* sigInfo, void* ucontext) + Operand sigInfoPtr = context.LoadArgument(OperandType.I64, 1); + + Operand structAddressOffset = context.Load(OperandType.I64, Const((ulong)signalStructPtr + StructAddressOffset)); + Operand structWriteOffset = context.Load(OperandType.I64, Const((ulong)signalStructPtr + StructWriteOffset)); + + Operand faultAddress = context.Load(OperandType.I64, context.Add(sigInfoPtr, context.ZeroExtend32(OperandType.I64, structAddressOffset))); + Operand writeFlag = context.Load(OperandType.I64, context.Add(sigInfoPtr, context.ZeroExtend32(OperandType.I64, structWriteOffset))); + + Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. + + Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite); + + Operand endLabel = Label(); + + context.BranchIfTrue(endLabel, isInRegion); + + Operand unixOldSigaction = context.Load(OperandType.I64, Const((ulong)signalStructPtr + UnixOldSigaction)); + Operand unixOldSigaction3Arg = context.Load(OperandType.I64, Const((ulong)signalStructPtr + UnixOldSigaction3Arg)); + Operand threeArgLabel = Label(); + + context.BranchIfTrue(threeArgLabel, unixOldSigaction3Arg); + + context.Call(unixOldSigaction, OperandType.None, context.LoadArgument(OperandType.I32, 0)); + context.Branch(endLabel); + + context.MarkLabel(threeArgLabel); + + context.Call(unixOldSigaction, + OperandType.None, + context.LoadArgument(OperandType.I32, 0), + sigInfoPtr, + context.LoadArgument(OperandType.I64, 2) + ); + + context.MarkLabel(endLabel); + + context.Return(); + + ControlFlowGraph cfg = context.GetControlFlowGraph(); + + OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 }; + + return Compiler.Compile<UnixExceptionHandler>(cfg, argTypes, OperandType.None, CompilerOptions.HighCq); + } + + private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr) + { + EmitterContext context = new EmitterContext(); + + // (ExceptionPointers* exceptionInfo) + Operand exceptionInfoPtr = context.LoadArgument(OperandType.I64, 0); + Operand exceptionRecordPtr = context.Load(OperandType.I64, exceptionInfoPtr); + + // First thing's first - this catches a number of exceptions, but we only want access violations. + Operand validExceptionLabel = Label(); + + Operand exceptionCode = context.Load(OperandType.I32, exceptionRecordPtr); + + context.BranchIf(validExceptionLabel, exceptionCode, Const(EXCEPTION_ACCESS_VIOLATION), Comparison.Equal); + + context.Return(Const(EXCEPTION_CONTINUE_SEARCH)); // Don't handle this one. + + context.MarkLabel(validExceptionLabel); + + // Next, read the address of the invalid access, and whether it is a write or not. + + Operand structAddressOffset = context.Load(OperandType.I32, Const((ulong)signalStructPtr + StructAddressOffset)); + Operand structWriteOffset = context.Load(OperandType.I32, Const((ulong)signalStructPtr + StructWriteOffset)); + + Operand faultAddress = context.Load(OperandType.I64, context.Add(exceptionRecordPtr, context.ZeroExtend32(OperandType.I64, structAddressOffset))); + Operand writeFlag = context.Load(OperandType.I64, context.Add(exceptionRecordPtr, context.ZeroExtend32(OperandType.I64, structWriteOffset))); + + Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. + + Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite); + + Operand endLabel = Label(); + + // If the region check result is false, then run the next vectored exception handler. + + context.BranchIfTrue(endLabel, isInRegion); + + context.Return(Const(EXCEPTION_CONTINUE_SEARCH)); + + context.MarkLabel(endLabel); + + // Otherwise, return to execution. + + context.Return(Const(EXCEPTION_CONTINUE_EXECUTION)); + + // Compile and return the function. + + ControlFlowGraph cfg = context.GetControlFlowGraph(); + + OperandType[] argTypes = new OperandType[] { OperandType.I64 }; + + return Compiler.Compile<VectoredExceptionHandler>(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq); + } + } +} diff --git a/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs b/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs new file mode 100644 index 00000000..9e87749e --- /dev/null +++ b/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs @@ -0,0 +1,57 @@ +using Mono.Unix.Native; +using System; +using System.Runtime.InteropServices; + +namespace ARMeilleure.Signal +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + unsafe struct SigSet + { + fixed long sa_mask[16]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SigAction + { + public IntPtr sa_handler; + public SigSet sa_mask; + public int sa_flags; + public IntPtr sa_restorer; + } + + static class UnixSignalHandlerRegistration + { + 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 sigemptyset(ref SigSet set); + + public static SigAction RegisterExceptionHandler(IntPtr action) + { + SigAction sig = new SigAction + { + sa_handler = action, + sa_flags = SA_SIGINFO + }; + + sigemptyset(ref sig.sa_mask); + + int result = sigaction((int)Signum.SIGSEGV, ref sig, out SigAction old); + + if (result != 0) + { + throw new InvalidOperationException($"Could not register sigaction. Error: {result}"); + } + + return old; + } + + public static bool RestoreExceptionHandler(SigAction oldAction) + { + return sigaction((int)Signum.SIGSEGV, ref oldAction, out SigAction _) == 0; + } + } +} diff --git a/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs b/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs new file mode 100644 index 00000000..959d1c47 --- /dev/null +++ b/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.InteropServices; + +namespace ARMeilleure.Signal +{ + class WindowsSignalHandlerRegistration + { + [DllImport("kernel32.dll")] + private static extern IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler); + + [DllImport("kernel32.dll")] + private static extern ulong RemoveVectoredExceptionHandler(IntPtr handle); + + public static IntPtr RegisterExceptionHandler(IntPtr action) + { + return AddVectoredExceptionHandler(1, action); + } + + public static bool RemoveExceptionHandler(IntPtr handle) + { + return RemoveVectoredExceptionHandler(handle) != 0; + } + } +} diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index f6494c23..ed4a003d 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -28,7 +28,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0"; - private const uint InternalVersion = 2305; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 2289; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1"; @@ -64,6 +64,8 @@ namespace ARMeilleure.Translation.PTC internal static string TitleIdText { get; private set; } internal static string DisplayVersion { get; private set; } + private static MemoryManagerMode _memoryMode; + internal static string CachePathActual { get; private set; } internal static string CachePathBackup { get; private set; } @@ -98,7 +100,7 @@ namespace ARMeilleure.Translation.PTC Disable(); } - public static void Initialize(string titleIdText, string displayVersion, bool enabled) + public static void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerMode memoryMode) { Wait(); @@ -122,6 +124,7 @@ namespace ARMeilleure.Translation.PTC TitleIdText = titleIdText; DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault; + _memoryMode = memoryMode; string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir); string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir); @@ -244,6 +247,13 @@ namespace ARMeilleure.Translation.PTC return false; } + if (outerHeader.MemoryManagerMode != GetMemoryManagerMode()) + { + InvalidateCompressedStream(compressedStream); + + return false; + } + if (outerHeader.OSPlatform != GetOSPlatform()) { InvalidateCompressedStream(compressedStream); @@ -441,6 +451,7 @@ namespace ARMeilleure.Translation.PTC outerHeader.CacheFileVersion = InternalVersion; outerHeader.Endianness = GetEndianness(); outerHeader.FeatureInfo = GetFeatureInfo(); + outerHeader.MemoryManagerMode = GetMemoryManagerMode(); outerHeader.OSPlatform = GetOSPlatform(); outerHeader.UncompressedStreamSize = @@ -954,6 +965,11 @@ namespace ARMeilleure.Translation.PTC return (ulong)HardwareCapabilities.FeatureInfoEdx << 32 | (uint)HardwareCapabilities.FeatureInfoEcx; } + private static byte GetMemoryManagerMode() + { + return (byte)_memoryMode; + } + private static uint GetOSPlatform() { uint osPlatform = 0u; @@ -966,7 +982,7 @@ namespace ARMeilleure.Translation.PTC return osPlatform; } - [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 49*/)] + [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 50*/)] private struct OuterHeader { public ulong Magic; @@ -975,6 +991,7 @@ namespace ARMeilleure.Translation.PTC public bool Endianness; public ulong FeatureInfo; + public byte MemoryManagerMode; public uint OSPlatform; public long UncompressedStreamSize; diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs index f8b074c9..eeeb517f 100644 --- a/ARMeilleure/Translation/Translator.cs +++ b/ARMeilleure/Translation/Translator.cs @@ -4,6 +4,7 @@ using ARMeilleure.Diagnostics; using ARMeilleure.Instructions; using ARMeilleure.IntermediateRepresentation; using ARMeilleure.Memory; +using ARMeilleure.Signal; using ARMeilleure.State; using ARMeilleure.Translation.Cache; using ARMeilleure.Translation.PTC; @@ -63,6 +64,11 @@ namespace ARMeilleure.Translation JitCache.Initialize(allocator); DirectCallStubs.InitializeStubs(); + + if (memory.Type.IsHostMapped()) + { + NativeSignalHandler.InitializeSignalHandler(); + } } private void TranslateStackedSubs() |
