Support memory aliasing (#2954)

* 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 <nastys@users.noreply.github.com>
This commit is contained in:
gdkchan 2022-05-02 20:30:02 -03:00 committed by GitHub
parent 4a892fbdc9
commit 95017b8c66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 2373 additions and 2155 deletions

View file

@ -1,11 +1,9 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.Memory.Range;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
@ -73,8 +71,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private MersenneTwister _randomNumberGenerator;
public abstract bool SupportsMemoryAliasing { get; }
private MemoryFillValue _heapFillValue;
private MemoryFillValue _ipcFillValue;
@ -305,7 +301,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
TlsIoRegionStart = tlsIoRegion.Start;
TlsIoRegionEnd = tlsIoRegion.End;
// TODO: Check kernel configuration via secure monitor call when implemented to set memory fill values.
// TODO: Check kernel configuration via secure monitor call when implemented to set memory fill values.
_currentHeapAddr = HeapRegionStart;
_heapCapacity = 0;
@ -380,8 +376,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
public KernelResult UnmapPages(ulong address, ulong pagesCount, IEnumerable<HostMemoryRange> ranges, MemoryState stateExpected)
public KernelResult UnmapPages(ulong address, KPageList pageList, MemoryState stateExpected)
{
ulong pagesCount = pageList.GetPagesCount();
ulong size = pagesCount * PageSize;
ulong endAddr = address + size;
@ -405,9 +402,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
lock (_blockManager)
{
var currentRanges = GetPhysicalRegions(address, size);
KPageList currentPageList = new KPageList();
if (!currentRanges.SequenceEqual(ranges))
GetPhysicalRegions(address, size, currentPageList);
if (!currentPageList.IsEqual(pageList))
{
return KernelResult.InvalidMemRange;
}
@ -1690,11 +1689,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
bool send,
out ulong dst)
{
if (!SupportsMemoryAliasing)
{
throw new NotSupportedException("Memory aliasing not supported, can't map IPC buffers.");
}
dst = 0;
if (!_slabManager.CanAllocate(MaxBlocksNeededForInsertion))
@ -1828,7 +1822,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
ulong alignedSize = endAddrTruncated - addressRounded;
KernelResult result = MapPages(currentVa, srcPageTable.GetPhysicalRegions(addressRounded, alignedSize), permission);
KPageList pageList = new KPageList();
srcPageTable.GetPhysicalRegions(addressRounded, alignedSize, pageList);
KernelResult result = MapPages(currentVa, pageList, permission);
if (result != KernelResult.Success)
{
@ -2041,7 +2038,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute.Borrowed);
}
public KernelResult BorrowTransferMemory(List<HostMemoryRange> ranges, ulong address, ulong size, KMemoryPermission permission)
public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
{
return SetAttributesAndChangePermission(
address,
@ -2054,7 +2051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute.None,
permission,
MemoryAttribute.Borrowed,
ranges);
pageList);
}
private KernelResult SetAttributesAndChangePermission(
@ -2068,7 +2065,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute attributeExpected,
KMemoryPermission newPermission,
MemoryAttribute attributeSetMask,
List<HostMemoryRange> ranges = null)
KPageList pageList = null)
{
if (address + size <= address || !InsideAddrSpace(address, size))
{
@ -2093,7 +2090,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
ulong pagesCount = size / PageSize;
ranges?.AddRange(GetPhysicalRegions(address, size));
if (pageList != null)
{
GetPhysicalRegions(address, pagesCount * PageSize, pageList);
}
if (!_slabManager.CanAllocate(MaxBlocksNeededForInsertion))
{
@ -2143,7 +2143,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute.Borrowed);
}
public KernelResult UnborrowTransferMemory(ulong address, ulong size, List<HostMemoryRange> ranges)
public KernelResult UnborrowTransferMemory(ulong address, ulong size, KPageList pageList)
{
return ClearAttributesAndChangePermission(
address,
@ -2156,7 +2156,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute.Borrowed,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.Borrowed,
ranges);
pageList);
}
private KernelResult ClearAttributesAndChangePermission(
@ -2170,7 +2170,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryAttribute attributeExpected,
KMemoryPermission newPermission,
MemoryAttribute attributeClearMask,
List<HostMemoryRange> ranges = null)
KPageList pageList = null)
{
if (address + size <= address || !InsideAddrSpace(address, size))
{
@ -2195,11 +2195,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
ulong pagesCount = size / PageSize;
if (ranges != null)
if (pageList != null)
{
var currentRanges = GetPhysicalRegions(address, size);
KPageList currentPageList = new KPageList();
if (!currentRanges.SequenceEqual(ranges))
GetPhysicalRegions(address, pagesCount * PageSize, currentPageList);
if (!currentPageList.IsEqual(pageList))
{
return KernelResult.InvalidMemRange;
}
@ -2741,8 +2743,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// </summary>
/// <param name="va">Virtual address of the range</param>
/// <param name="size">Size of the range</param>
/// <returns>Array of physical regions</returns>
protected abstract IEnumerable<HostMemoryRange> GetPhysicalRegions(ulong va, ulong size);
/// <param name="pageList">Page list where the ranges will be added</param>
protected abstract void GetPhysicalRegions(ulong va, ulong size, KPageList pageList);
/// <summary>
/// Gets a read-only span of data from CPU mapped memory.
@ -2803,16 +2805,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
/// <returns>Result of the mapping operation</returns>
protected abstract KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
/// <summary>
/// Maps a region of memory into the specified host memory ranges.
/// </summary>
/// <param name="address">Destination virtual address that should be mapped</param>
/// <param name="ranges">Ranges of host memory that should be mapped</param>
/// <param name="permission">Permission of the region to be mapped</param>
/// <returns>Result of the mapping operation</returns>
/// <exception cref="NotSupportedException">The implementation does not support memory aliasing</exception>
protected abstract KernelResult MapPages(ulong address, IEnumerable<HostMemoryRange> ranges, KMemoryPermission permission);
/// <summary>
/// Unmaps a region of memory that was previously mapped with one of the page mapping methods.
/// </summary>