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:
parent
4a892fbdc9
commit
95017b8c66
41 changed files with 2373 additions and 2155 deletions
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue