/ src / Ryujinx.Cpu / MemoryEhMeilleure.cs
MemoryEhMeilleure.cs
 1  using Ryujinx.Common;
 2  using Ryujinx.Cpu.Signal;
 3  using Ryujinx.Memory;
 4  using Ryujinx.Memory.Tracking;
 5  using System;
 6  using System.Runtime.InteropServices;
 7  
 8  namespace Ryujinx.Cpu
 9  {
10      public class MemoryEhMeilleure : IDisposable
11      {
12          public delegate ulong TrackingEventDelegate(ulong address, ulong size, bool write);
13  
14          private readonly MemoryTracking _tracking;
15          private readonly TrackingEventDelegate _trackingEvent;
16  
17          private readonly ulong _pageSize;
18  
19          private readonly ulong _baseAddress;
20          private readonly ulong _mirrorAddress;
21  
22          public MemoryEhMeilleure(MemoryBlock addressSpace, MemoryBlock addressSpaceMirror, MemoryTracking tracking, TrackingEventDelegate trackingEvent = null)
23          {
24              _baseAddress = (ulong)addressSpace.Pointer;
25  
26              ulong endAddress = _baseAddress + addressSpace.Size;
27  
28              _tracking = tracking;
29              _trackingEvent = trackingEvent ?? VirtualMemoryEvent;
30  
31              _pageSize = MemoryBlock.GetPageSize();
32  
33              bool added = NativeSignalHandler.AddTrackedRegion((nuint)_baseAddress, (nuint)endAddress, Marshal.GetFunctionPointerForDelegate(_trackingEvent));
34  
35              if (!added)
36              {
37                  throw new InvalidOperationException("Number of allowed tracked regions exceeded.");
38              }
39  
40              if (OperatingSystem.IsWindows() && addressSpaceMirror != null)
41              {
42                  // Add a tracking event with no signal handler for the mirror on Windows.
43                  // The native handler has its own code to check for the partial overlap race when regions are protected by accident,
44                  // and when there is no signal handler present.
45  
46                  _mirrorAddress = (ulong)addressSpaceMirror.Pointer;
47                  ulong endAddressMirror = _mirrorAddress + addressSpace.Size;
48  
49                  bool addedMirror = NativeSignalHandler.AddTrackedRegion((nuint)_mirrorAddress, (nuint)endAddressMirror, IntPtr.Zero);
50  
51                  if (!addedMirror)
52                  {
53                      throw new InvalidOperationException("Number of allowed tracked regions exceeded.");
54                  }
55              }
56          }
57  
58          private ulong VirtualMemoryEvent(ulong address, ulong size, bool write)
59          {
60              ulong pageSize = _pageSize;
61              ulong addressAligned = BitUtils.AlignDown(address, pageSize);
62              ulong endAddressAligned = BitUtils.AlignUp(address + size, pageSize);
63              ulong sizeAligned = endAddressAligned - addressAligned;
64  
65              if (_tracking.VirtualMemoryEvent(addressAligned, sizeAligned, write))
66              {
67                  return _baseAddress + address;
68              }
69  
70              return 0;
71          }
72  
73          public void Dispose()
74          {
75              GC.SuppressFinalize(this);
76  
77              NativeSignalHandler.RemoveTrackedRegion((nuint)_baseAddress);
78  
79              if (_mirrorAddress != 0)
80              {
81                  NativeSignalHandler.RemoveTrackedRegion((nuint)_mirrorAddress);
82              }
83          }
84      }
85  }