diff options
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Memory')
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs | 2 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs | 56 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs | 70 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs | 13 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Memory/SharedMemoryStorage.cs | 2 |
5 files changed, 119 insertions, 24 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs index 5e6273b8..4596b15d 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryRegionManager.cs @@ -64,7 +64,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory if (address != 0) { IncrementPagesReferenceCount(address, pagesCount); - context.Memory.Commit(address - DramMemoryMap.DramBase, pagesCount * KPageTableBase.PageSize); + context.CommitMemory(address - DramMemoryMap.DramBase, pagesCount * KPageTableBase.PageSize); } return address; diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs index 9b7c99ba..28e9f90a 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs @@ -1,6 +1,8 @@ using Ryujinx.Horizon.Common; using Ryujinx.Memory; +using Ryujinx.Memory.Range; using System; +using System.Collections.Generic; using System.Diagnostics; namespace Ryujinx.HLE.HOS.Kernel.Memory @@ -9,12 +11,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { private readonly IVirtualMemoryManager _cpuMemory; + protected override bool Supports4KBPages => _cpuMemory.Supports4KBPages; + public KPageTable(KernelContext context, IVirtualMemoryManager cpuMemory) : base(context) { _cpuMemory = cpuMemory; } /// <inheritdoc/> + protected override IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size) + { + return _cpuMemory.GetHostRegions(va, size); + } + + /// <inheritdoc/> protected override void GetPhysicalRegions(ulong va, ulong size, KPageList pageList) { var ranges = _cpuMemory.GetPhysicalRegions(va, size); @@ -43,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return result; } - result = MapPages(dst, pageList, newDstPermission, false, 0); + result = MapPages(dst, pageList, newDstPermission, MemoryMapFlags.Private, false, 0); if (result != Result.Success) { @@ -81,7 +91,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory if (result != Result.Success) { - Result mapResult = MapPages(dst, dstPageList, oldDstPermission, false, 0); + Result mapResult = MapPages(dst, dstPageList, oldDstPermission, MemoryMapFlags.Private, false, 0); Debug.Assert(mapResult == Result.Success); } @@ -89,13 +99,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } /// <inheritdoc/> - protected override Result MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages, byte fillValue) + protected override Result MapPages( + ulong dstVa, + ulong pagesCount, + ulong srcPa, + KMemoryPermission permission, + MemoryMapFlags flags, + bool shouldFillPages, + byte fillValue) { ulong size = pagesCount * PageSize; - Context.Memory.Commit(srcPa - DramMemoryMap.DramBase, size); + Context.CommitMemory(srcPa - DramMemoryMap.DramBase, size); - _cpuMemory.Map(dstVa, srcPa - DramMemoryMap.DramBase, size); + _cpuMemory.Map(dstVa, srcPa - DramMemoryMap.DramBase, size, flags); if (DramMemoryMap.IsHeapPhysicalAddress(srcPa)) { @@ -111,7 +128,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } /// <inheritdoc/> - protected override Result MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages, byte fillValue) + protected override Result MapPages( + ulong address, + KPageList pageList, + KMemoryPermission permission, + MemoryMapFlags flags, + bool shouldFillPages, + byte fillValue) { using var scopedPageList = new KScopedPageList(Context.MemoryManager, pageList); @@ -122,9 +145,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong addr = pageNode.Address - DramMemoryMap.DramBase; ulong size = pageNode.PagesCount * PageSize; - Context.Memory.Commit(addr, size); + Context.CommitMemory(addr, size); - _cpuMemory.Map(currentVa, addr, size); + _cpuMemory.Map(currentVa, addr, size, flags); if (shouldFillPages) { @@ -140,6 +163,21 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } /// <inheritdoc/> + protected override Result MapForeign(IEnumerable<HostMemoryRange> regions, ulong va, ulong size) + { + ulong offset = 0; + + foreach (var region in regions) + { + _cpuMemory.MapForeign(va + offset, region.Address, region.Size); + + offset += region.Size; + } + + return Result.Success; + } + + /// <inheritdoc/> protected override Result Unmap(ulong address, ulong pagesCount) { KPageList pagesToClose = new KPageList(); @@ -188,4 +226,4 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory _cpuMemory.Write(va, data); } } -} +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs index e19e22c8..bd7d5725 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs @@ -1,6 +1,8 @@ using Ryujinx.Common; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.Memory; +using Ryujinx.Memory.Range; using Ryujinx.Horizon.Common; using System; using System.Collections.Generic; @@ -29,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory private const int MaxBlocksNeededForInsertion = 2; protected readonly KernelContext Context; + protected virtual bool Supports4KBPages => true; public ulong AddrSpaceStart { get; private set; } public ulong AddrSpaceEnd { get; private set; } @@ -366,7 +369,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.OutOfResource; } - Result result = MapPages(address, pageList, permission); + Result result = MapPages(address, pageList, permission, MemoryMapFlags.None); if (result == Result.Success) { @@ -502,7 +505,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory if (paIsValid) { - result = MapPages(address, pagesCount, srcPa, permission); + result = MapPages(address, pagesCount, srcPa, permission, MemoryMapFlags.Private); } else { @@ -565,7 +568,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory using var _ = new OnScopeExit(() => pageList.DecrementPagesReferenceCount(Context.MemoryManager)); - return MapPages(address, pageList, permission); + return MapPages(address, pageList, permission, MemoryMapFlags.Private); } public Result MapProcessCodeMemory(ulong dst, ulong src, ulong size) @@ -746,7 +749,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.InvalidMemState; } - result = MapPages(_currentHeapAddr, pageList, KMemoryPermission.ReadAndWrite, true, (byte)_heapFillValue); + result = MapPages(_currentHeapAddr, pageList, KMemoryPermission.ReadAndWrite, MemoryMapFlags.Private, true, (byte)_heapFillValue); if (result != Result.Success) { @@ -1334,7 +1337,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory ulong currentPagesCount = Math.Min(srcPaPages, dstVaPages); - MapPages(dstVa, currentPagesCount, srcPa, KMemoryPermission.ReadAndWrite); + MapPages(dstVa, currentPagesCount, srcPa, KMemoryPermission.ReadAndWrite, MemoryMapFlags.Private); dstVa += currentPagesCount * PageSize; srcPa += currentPagesCount * PageSize; @@ -1878,7 +1881,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory Context.Memory.Fill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter, (byte)_ipcFillValue); } - Result result = MapPages(currentVa, 1, dstFirstPagePa, permission); + Result result = MapPages(currentVa, 1, dstFirstPagePa, permission, MemoryMapFlags.Private); if (result != Result.Success) { @@ -1894,10 +1897,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { ulong alignedSize = endAddrTruncated - addressRounded; - KPageList pageList = new KPageList(); - srcPageTable.GetPhysicalRegions(addressRounded, alignedSize, pageList); + Result result; + + if (srcPageTable.Supports4KBPages) + { + KPageList pageList = new KPageList(); + srcPageTable.GetPhysicalRegions(addressRounded, alignedSize, pageList); - Result result = MapPages(currentVa, pageList, permission); + result = MapPages(currentVa, pageList, permission, MemoryMapFlags.None); + } + else + { + result = MapForeign(srcPageTable.GetHostRegions(addressRounded, alignedSize), currentVa, alignedSize); + } if (result != Result.Success) { @@ -1932,7 +1944,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory Context.Memory.Fill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter, (byte)_ipcFillValue); - Result result = MapPages(currentVa, 1, dstLastPagePa, permission); + Result result = MapPages(currentVa, 1, dstLastPagePa, permission, MemoryMapFlags.Private); if (result != Result.Success) { @@ -2885,6 +2897,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory } /// <summary> + /// Gets the host regions that make up the given virtual address region. + /// If any part of the virtual region is unmapped, null is returned. + /// </summary> + /// <param name="va">Virtual address of the range</param> + /// <param name="size">Size of the range</param> + /// <returns>The host regions</returns> + /// <exception cref="Ryujinx.Memory.InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception> + protected abstract IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size); + + /// <summary> /// Gets the physical regions that make up the given virtual address region. /// If any part of the virtual region is unmapped, null is returned. /// </summary> @@ -2936,10 +2958,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// <param name="pagesCount">Number of pages to map</param> /// <param name="srcPa">Physical address where the pages should be mapped. May be ignored if aliasing is not supported</param> /// <param name="permission">Permission of the region to be mapped</param> + /// <param name="flags">Flags controlling the memory map operation</param> /// <param name="shouldFillPages">Indicate if the pages should be filled with the <paramref name="fillValue"/> value</param> /// <param name="fillValue">The value used to fill pages when <paramref name="shouldFillPages"/> is set to true</param> /// <returns>Result of the mapping operation</returns> - protected abstract Result MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0); + protected abstract Result MapPages( + ulong dstVa, + ulong pagesCount, + ulong srcPa, + KMemoryPermission permission, + MemoryMapFlags flags, + bool shouldFillPages = false, + byte fillValue = 0); /// <summary> /// Maps a region of memory into the specified physical memory region. @@ -2947,10 +2977,26 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory /// <param name="address">Destination virtual address that should be mapped</param> /// <param name="pageList">List of physical memory pages where the pages should be mapped. May be ignored if aliasing is not supported</param> /// <param name="permission">Permission of the region to be mapped</param> + /// <param name="flags">Flags controlling the memory map operation</param> /// <param name="shouldFillPages">Indicate if the pages should be filled with the <paramref name="fillValue"/> value</param> /// <param name="fillValue">The value used to fill pages when <paramref name="shouldFillPages"/> is set to true</param> /// <returns>Result of the mapping operation</returns> - protected abstract Result MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0); + protected abstract Result MapPages( + ulong address, + KPageList pageList, + KMemoryPermission permission, + MemoryMapFlags flags, + bool shouldFillPages = false, + byte fillValue = 0); + + /// <summary> + /// Maps pages into an arbitrary host memory location. + /// </summary> + /// <param name="regions">Host regions to be mapped into the specified virtual memory region</param> + /// <param name="va">Destination virtual address of the range on this page table</param> + /// <param name="size">Size of the range</param> + /// <returns>Result of the mapping operation</returns> + protected abstract Result MapForeign(IEnumerable<HostMemoryRange> regions, ulong va, ulong size); /// <summary> /// Unmaps a region of memory that was previously mapped with one of the page mapping methods. diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs index 2dbaf3cd..5ec3cd72 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs @@ -2,6 +2,7 @@ using Ryujinx.Common; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.Horizon.Common; +using Ryujinx.Memory; namespace Ryujinx.HLE.HOS.Kernel.Memory { @@ -48,7 +49,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.InvalidPermission; } - return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission); + // On platforms with page size > 4 KB, this can fail due to the address not being page aligned, + // we can return an error to force the application to retry with a different address. + + try + { + return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission); + } + catch (InvalidMemoryRegionException) + { + return KernelResult.InvalidMemState; + } } public Result UnmapFromProcess(KPageTableBase memoryManager, ulong address, ulong size, KProcess process) diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/SharedMemoryStorage.cs b/Ryujinx.HLE/HOS/Kernel/Memory/SharedMemoryStorage.cs index 167e0aa9..c68b7369 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/SharedMemoryStorage.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/SharedMemoryStorage.cs @@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { ulong address = pageNode.Address - DramMemoryMap.DramBase; ulong size = pageNode.PagesCount * KPageTableBase.PageSize; - context.Memory.Commit(address, size); + context.CommitMemory(address, size); } } |