Skip to content

Commit

Permalink
Support memory aliasing (#2954)
Browse files Browse the repository at this point in the history
* Back to the origins: Make memory manager take guest PA rather than host address once again

* Direct mapping with alias support on Windows

* Fixes and remove more of the emulated shared memory

* Linux support

* Make shared and transfer memory not depend on SharedMemoryStorage

* More efficient view mapping on Windows (no more restricted to 4KB pages at a time)

* Handle potential access violations caused by partial unmap

* Implement host mapping using shared memory on Linux

* Add new GetPhysicalAddressChecked method, used to ensure the virtual address is mapped before address translation

Also align GetRef behaviour with software memory manager

* We don't need a mirrorable memory block for software memory manager mode

* Disable memory aliasing tests while we don't have shared memory support on Mac

* Shared memory & SIGBUS handler for macOS

* Fix typo + nits + re-enable memory tests

* Set MAP_JIT_DARWIN on x86 Mac too

* Add back the address space mirror

* Only set MAP_JIT_DARWIN if we are mapping as executable

* Disable aliasing tests again (still fails on Mac)

* Fix UnmapView4KB (by not casting size to int)

* Use ref counting on memory blocks to delay closing the shared memory handle until all blocks using it are disposed

* Address PR feedback

* Make RO hold a reference to the guest process memory manager to avoid early disposal

Co-authored-by: nastys <[email protected]>
  • Loading branch information
gdkchan and nastys authored May 2, 2022
1 parent 4a892fb commit 95017b8
Show file tree
Hide file tree
Showing 41 changed files with 2,356 additions and 2,138 deletions.
2 changes: 1 addition & 1 deletion ARMeilleure/Signal/NativeSignalHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static void InitializeSignalHandler()
// Unix siginfo struct locations.
// NOTE: These are incredibly likely to be different between kernel version and architectures.

config.StructAddressOffset = 16; // si_addr
config.StructAddressOffset = OperatingSystem.IsMacOS() ? 24 : 16; // si_addr
config.StructWriteOffset = 8; // si_code

_signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
Expand Down
15 changes: 13 additions & 2 deletions ARMeilleure/Signal/UnixSignalHandlerRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct SigAction
static class UnixSignalHandlerRegistration
{
private const int SIGSEGV = 11;
private const int SIGBUS = 10;
private const int SA_SIGINFO = 0x00000004;

[DllImport("libc", SetLastError = true)]
Expand All @@ -43,15 +44,25 @@ public static SigAction RegisterExceptionHandler(IntPtr action)

if (result != 0)
{
throw new InvalidOperationException($"Could not register sigaction. Error: {result}");
throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}");
}

if (OperatingSystem.IsMacOS())
{
result = sigaction(SIGBUS, ref sig, out SigAction oldb);

if (result != 0)
{
throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}");
}
}

return old;
}

public static bool RestoreExceptionHandler(SigAction oldAction)
{
return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0;
return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0);
}
}
}
40 changes: 20 additions & 20 deletions ARMeilleure/Translation/IntervalTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace ARMeilleure.Translation
/// </summary>
/// <typeparam name="K">Key</typeparam>
/// <typeparam name="V">Value</typeparam>
public class IntervalTree<K, V> where K : IComparable<K>
class IntervalTree<K, V> where K : IComparable<K>
{
private const int ArrayGrowthSize = 32;

Expand Down Expand Up @@ -53,7 +53,7 @@ public bool TryGet(K key, out V value)
/// <returns>Number of intervals found</returns>
public int Get(K start, K end, ref K[] overlaps, int overlapCount = 0)
{
GetValues(_root, start, end, ref overlaps, ref overlapCount);
GetKeys(_root, start, end, ref overlaps, ref overlapCount);

return overlapCount;
}
Expand Down Expand Up @@ -180,20 +180,20 @@ private IntervalTreeNode<K, V> GetNode(K key)
}

/// <summary>
/// Retrieve all values that overlap the given start and end keys.
/// Retrieve all keys that overlap the given start and end keys.
/// </summary>
/// <param name="start">Start of the range</param>
/// <param name="end">End of the range</param>
/// <param name="overlaps">Overlaps array to place results in</param>
/// <param name="overlapCount">Overlaps count to update</param>
private void GetValues(IntervalTreeNode<K, V> node, K start, K end, ref K[] overlaps, ref int overlapCount)
private void GetKeys(IntervalTreeNode<K, V> node, K start, K end, ref K[] overlaps, ref int overlapCount)
{
if (node == null || start.CompareTo(node.Max) >= 0)
{
return;
}

GetValues(node.Left, start, end, ref overlaps, ref overlapCount);
GetKeys(node.Left, start, end, ref overlaps, ref overlapCount);

bool endsOnRight = end.CompareTo(node.Start) > 0;
if (endsOnRight)
Expand All @@ -208,7 +208,7 @@ private void GetValues(IntervalTreeNode<K, V> node, K start, K end, ref K[] over
overlaps[overlapCount++] = node.Start;
}

GetValues(node.Right, start, end, ref overlaps, ref overlapCount);
GetKeys(node.Right, start, end, ref overlaps, ref overlapCount);
}
}

Expand Down Expand Up @@ -717,40 +717,40 @@ public void Clear()
/// </summary>
/// <typeparam name="K">Key type of the node</typeparam>
/// <typeparam name="V">Value type of the node</typeparam>
internal class IntervalTreeNode<K, V>
class IntervalTreeNode<K, V>
{
internal bool Color = true;
internal IntervalTreeNode<K, V> Left = null;
internal IntervalTreeNode<K, V> Right = null;
internal IntervalTreeNode<K, V> Parent = null;
public bool Color = true;
public IntervalTreeNode<K, V> Left = null;
public IntervalTreeNode<K, V> Right = null;
public IntervalTreeNode<K, V> Parent = null;

/// <summary>
/// The start of the range.
/// </summary>
internal K Start;
public K Start;

/// <summary>
/// The end of the range.
/// </summary>
internal K End;
public K End;

/// <summary>
/// The maximum end value of this node and all its children.
/// </summary>
internal K Max;
public K Max;

/// <summary>
/// Value stored on this node.
/// </summary>
internal V Value;
public V Value;

public IntervalTreeNode(K start, K end, V value, IntervalTreeNode<K, V> parent)
{
this.Start = start;
this.End = end;
this.Max = end;
this.Value = value;
this.Parent = parent;
Start = start;
End = end;
Max = end;
Value = value;
Parent = parent;
}
}
}
36 changes: 17 additions & 19 deletions Ryujinx.Common/Collections/IntervalTree.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

namespace Ryujinx.Common.Collections
Expand Down Expand Up @@ -212,7 +210,7 @@ private IntervalTreeNode<K, V> GetNode(K key)
/// <param name="overlaps">Overlaps array to place results in</param>
/// <param name="overlapCount">Overlaps count to update</param>
private void GetValues(IntervalTreeNode<K, V> node, K start, K end, ref V[] overlaps, ref int overlapCount)
{
{
if (node == null || start.CompareTo(node.Max) >= 0)
{
return;
Expand Down Expand Up @@ -624,7 +622,7 @@ private void RotateLeft(IntervalTreeNode<K, V> node)
node.Right = LeftOf(right);
if (node.Right != null)
{
node.Right.Parent = node;
node.Right.Parent = node;
}
IntervalTreeNode<K, V> nodeParent = ParentOf(node);
right.Parent = nodeParent;
Expand All @@ -638,7 +636,7 @@ private void RotateLeft(IntervalTreeNode<K, V> node)
}
else
{
nodeParent.Right = right;
nodeParent.Right = right;
}
right.Left = node;
node.Parent = right;
Expand Down Expand Up @@ -779,37 +777,37 @@ public RangeNode(K start, K end, V value)
/// </summary>
/// <typeparam name="K">Key type of the node</typeparam>
/// <typeparam name="V">Value type of the node</typeparam>
internal class IntervalTreeNode<K, V>
class IntervalTreeNode<K, V>
{
internal bool Color = true;
internal IntervalTreeNode<K, V> Left = null;
internal IntervalTreeNode<K, V> Right = null;
internal IntervalTreeNode<K, V> Parent = null;
public bool Color = true;
public IntervalTreeNode<K, V> Left = null;
public IntervalTreeNode<K, V> Right = null;
public IntervalTreeNode<K, V> Parent = null;

/// <summary>
/// The start of the range.
/// </summary>
internal K Start;
public K Start;

/// <summary>
/// The end of the range - maximum of all in the Values list.
/// </summary>
internal K End;
public K End;

/// <summary>
/// The maximum end value of this node and all its children.
/// </summary>
internal K Max;
public K Max;

internal List<RangeNode<K, V>> Values;
public List<RangeNode<K, V>> Values;

public IntervalTreeNode(K start, K end, V value, IntervalTreeNode<K, V> parent)
{
this.Start = start;
this.End = end;
this.Max = end;
this.Values = new List<RangeNode<K, V>> { new RangeNode<K, V>(start, end, value) };
this.Parent = parent;
Start = start;
End = end;
Max = end;
Values = new List<RangeNode<K, V>> { new RangeNode<K, V>(start, end, value) };
Parent = parent;
}
}
}
26 changes: 13 additions & 13 deletions Ryujinx.Common/Collections/TreeDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -921,10 +921,10 @@ IEnumerator IEnumerable.GetEnumerator()

public bool IsReadOnly => false;

public V this[K key]
{
public V this[K key]
{
get => Get(key);
set => Add(key, value);
set => Add(key, value);
}

#endregion
Expand Down Expand Up @@ -967,20 +967,20 @@ private SortedList<K, V> GetKeyValues()
/// </summary>
/// <typeparam name="K">Key of the node</typeparam>
/// <typeparam name="V">Value of the node</typeparam>
internal class Node<K, V>
class Node<K, V>
{
internal bool Color = true;
internal Node<K, V> Left = null;
internal Node<K, V> Right = null;
internal Node<K, V> Parent = null;
internal K Key;
internal V Value;
public bool Color = true;
public Node<K, V> Left = null;
public Node<K, V> Right = null;
public Node<K, V> Parent = null;
public K Key;
public V Value;

public Node(K key, V value, Node<K, V> parent)
{
this.Key = key;
this.Value = value;
this.Parent = parent;
Key = key;
Value = value;
Parent = parent;
}
}
}
2 changes: 1 addition & 1 deletion Ryujinx.Cpu/MemoryEhMeilleure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public MemoryEhMeilleure(MemoryBlock addressSpace, MemoryTracking tracking)
_baseAddress = (ulong)_addressSpace.Pointer;
ulong endAddress = _baseAddress + addressSpace.Size;

_trackingEvent = new TrackingEventDelegate(tracking.VirtualMemoryEvent);
_trackingEvent = new TrackingEventDelegate(tracking.VirtualMemoryEventEh);
bool added = NativeSignalHandler.AddTrackedRegion((nuint)_baseAddress, (nuint)endAddress, Marshal.GetFunctionPointerForDelegate(_trackingEvent));

if (!added)
Expand Down
Loading

0 comments on commit 95017b8

Please sign in to comment.