From 95017b8c66f70406e926b278ecdd6d4ec0a93110 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 2 May 2022 20:30:02 -0300 Subject: 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 --- Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs | 64 +++++++++++-------------- 1 file changed, 28 insertions(+), 36 deletions(-) (limited to 'Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs') diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs index fb3d669d..518a0f09 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs @@ -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 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 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 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 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 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(); + + GetPhysicalRegions(address, pagesCount * PageSize, currentPageList); - if (!currentRanges.SequenceEqual(ranges)) + if (!currentPageList.IsEqual(pageList)) { return KernelResult.InvalidMemRange; } @@ -2741,8 +2743,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// /// Virtual address of the range /// Size of the range - /// Array of physical regions - protected abstract IEnumerable GetPhysicalRegions(ulong va, ulong size); + /// Page list where the ranges will be added + protected abstract void GetPhysicalRegions(ulong va, ulong size, KPageList pageList); /// /// Gets a read-only span of data from CPU mapped memory. @@ -2803,16 +2805,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// Result of the mapping operation protected abstract KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0); - /// - /// Maps a region of memory into the specified host memory ranges. - /// - /// Destination virtual address that should be mapped - /// Ranges of host memory that should be mapped - /// Permission of the region to be mapped - /// Result of the mapping operation - /// The implementation does not support memory aliasing - protected abstract KernelResult MapPages(ulong address, IEnumerable ranges, KMemoryPermission permission); - /// /// Unmaps a region of memory that was previously mapped with one of the page mapping methods. /// -- cgit v1.2.3