From 86fd0643c26433362a25acceb4fa1fcee07dd0b2 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 17 Jan 2023 01:13:24 -0300 Subject: Implement support for page sizes > 4KB (#4252) * Implement support for page sizes > 4KB * Check and work around more alignment issues * Was not meant to change this * Use MemoryBlock.GetPageSize() value for signal handler code * Do not take the path for private allocations if host supports 4KB pages * Add Flags attribute on MemoryMapFlags * Fix dirty region size with 16kb pages Would accidentally report a size that was too high (generally 16k instead of 4k, uploading 4x as much data) Co-authored-by: riperiperi --- Ryujinx.Cpu/Jit/JitMemoryAllocator.cs | 2 + Ryujinx.Cpu/Jit/MemoryManager.cs | 43 +++++++++++++++++++- Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs | 63 +++++++++++++++++------------- 3 files changed, 80 insertions(+), 28 deletions(-) (limited to 'Ryujinx.Cpu/Jit') diff --git a/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs b/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs index 0cf35c17..4aa78d06 100644 --- a/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs +++ b/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs @@ -7,5 +7,7 @@ namespace Ryujinx.Cpu.Jit { public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None); public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.Jit); + + public ulong GetPageSize() => MemoryBlock.GetPageSize(); } } diff --git a/Ryujinx.Cpu/Jit/MemoryManager.cs b/Ryujinx.Cpu/Jit/MemoryManager.cs index 21c50d51..014d843b 100644 --- a/Ryujinx.Cpu/Jit/MemoryManager.cs +++ b/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -28,6 +28,9 @@ namespace Ryujinx.Cpu.Jit private readonly MemoryBlock _backingMemory; private readonly InvalidAccessHandler _invalidAccessHandler; + /// + public bool Supports4KBPages => true; + /// /// Address space width in bits. /// @@ -76,7 +79,7 @@ namespace Ryujinx.Cpu.Jit } /// - public void Map(ulong va, ulong pa, ulong size) + public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags) { AssertValidAddressAndSize(va, size); @@ -91,9 +94,16 @@ namespace Ryujinx.Cpu.Jit pa += PageSize; remainingSize -= PageSize; } + Tracking.Map(oVa, size); } + /// + public void MapForeign(ulong va, nuint hostPointer, ulong size) + { + throw new NotSupportedException(); + } + /// public void Unmap(ulong va, ulong size) { @@ -378,6 +388,32 @@ namespace Ryujinx.Cpu.Jit return true; } + /// + public IEnumerable GetHostRegions(ulong va, ulong size) + { + if (size == 0) + { + return Enumerable.Empty(); + } + + var guestRegions = GetPhysicalRegionsImpl(va, size); + if (guestRegions == null) + { + return null; + } + + var regions = new HostMemoryRange[guestRegions.Count]; + + for (int i = 0; i < regions.Length; i++) + { + var guestRegion = guestRegions[i]; + IntPtr pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size); + regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size); + } + + return regions; + } + /// public IEnumerable GetPhysicalRegions(ulong va, ulong size) { @@ -386,6 +422,11 @@ namespace Ryujinx.Cpu.Jit return Enumerable.Empty(); } + return GetPhysicalRegionsImpl(va, size); + } + + private List GetPhysicalRegionsImpl(ulong va, ulong size) + { if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size)) { return null; diff --git a/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs b/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs index c4e59db9..856b6b9b 100644 --- a/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs +++ b/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs @@ -5,6 +5,7 @@ using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; using System.Threading; @@ -37,20 +38,21 @@ namespace Ryujinx.Cpu.Jit private readonly InvalidAccessHandler _invalidAccessHandler; private readonly bool _unsafeMode; - private readonly MemoryBlock _addressSpace; - private readonly MemoryBlock _addressSpaceMirror; + private readonly AddressSpace _addressSpace; private readonly ulong _addressSpaceSize; - private readonly MemoryBlock _backingMemory; private readonly PageTable _pageTable; private readonly MemoryEhMeilleure _memoryEh; private readonly ulong[] _pageBitmap; + /// + public bool Supports4KBPages => MemoryBlock.GetPageSize() == PageSize; + public int AddressSpaceBits { get; } - public IntPtr PageTablePointer => _addressSpace.Pointer; + public IntPtr PageTablePointer => _addressSpace.Base.Pointer; public MemoryManagerType Type => _unsafeMode ? MemoryManagerType.HostMappedUnsafe : MemoryManagerType.HostMapped; @@ -67,7 +69,6 @@ namespace Ryujinx.Cpu.Jit /// Optional function to handle invalid memory accesses public MemoryManagerHostMapped(MemoryBlock backingMemory, ulong addressSpaceSize, bool unsafeMode, InvalidAccessHandler invalidAccessHandler = null) { - _backingMemory = backingMemory; _pageTable = new PageTable(); _invalidAccessHandler = invalidAccessHandler; _unsafeMode = unsafeMode; @@ -86,13 +87,10 @@ namespace Ryujinx.Cpu.Jit _pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))]; - MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible; + _addressSpace = new AddressSpace(backingMemory, asSize, Supports4KBPages); - _addressSpace = new MemoryBlock(asSize, asFlags); - _addressSpaceMirror = new MemoryBlock(asSize, asFlags); - - Tracking = new MemoryTracking(this, PageSize, invalidAccessHandler); - _memoryEh = new MemoryEhMeilleure(_addressSpace, _addressSpaceMirror, Tracking); + Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler); + _memoryEh = new MemoryEhMeilleure(_addressSpace.Base, _addressSpace.Mirror, Tracking); } /// @@ -145,18 +143,23 @@ namespace Ryujinx.Cpu.Jit } /// - public void Map(ulong va, ulong pa, ulong size) + public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags) { AssertValidAddressAndSize(va, size); - _addressSpace.MapView(_backingMemory, pa, va, size); - _addressSpaceMirror.MapView(_backingMemory, pa, va, size); + _addressSpace.Map(va, pa, size, flags); AddMapping(va, size); PtMap(va, pa, size); Tracking.Map(va, size); } + /// + public void MapForeign(ulong va, nuint hostPointer, ulong size) + { + throw new NotSupportedException(); + } + /// public void Unmap(ulong va, ulong size) { @@ -167,8 +170,7 @@ namespace Ryujinx.Cpu.Jit RemoveMapping(va, size); PtUnmap(va, size); - _addressSpace.UnmapView(_backingMemory, va, size); - _addressSpaceMirror.UnmapView(_backingMemory, va, size); + _addressSpace.Unmap(va, size); } private void PtMap(ulong va, ulong pa, ulong size) @@ -201,7 +203,7 @@ namespace Ryujinx.Cpu.Jit { AssertMapped(va, (ulong)Unsafe.SizeOf()); - return _addressSpaceMirror.Read(va); + return _addressSpace.Mirror.Read(va); } catch (InvalidMemoryRegionException) { @@ -241,7 +243,7 @@ namespace Ryujinx.Cpu.Jit { AssertMapped(va, (ulong)data.Length); - _addressSpaceMirror.Read(va, data); + _addressSpace.Mirror.Read(va, data); } catch (InvalidMemoryRegionException) { @@ -260,7 +262,7 @@ namespace Ryujinx.Cpu.Jit { SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), write: true); - _addressSpaceMirror.Write(va, value); + _addressSpace.Mirror.Write(va, value); } catch (InvalidMemoryRegionException) { @@ -278,7 +280,7 @@ namespace Ryujinx.Cpu.Jit { SignalMemoryTracking(va, (ulong)data.Length, write: true); - _addressSpaceMirror.Write(va, data); + _addressSpace.Mirror.Write(va, data); } catch (InvalidMemoryRegionException) { @@ -296,7 +298,7 @@ namespace Ryujinx.Cpu.Jit { AssertMapped(va, (ulong)data.Length); - _addressSpaceMirror.Write(va, data); + _addressSpace.Mirror.Write(va, data); } catch (InvalidMemoryRegionException) { @@ -314,7 +316,7 @@ namespace Ryujinx.Cpu.Jit { SignalMemoryTracking(va, (ulong)data.Length, false); - Span target = _addressSpaceMirror.GetSpan(va, data.Length); + Span target = _addressSpace.Mirror.GetSpan(va, data.Length); bool changed = !data.SequenceEqual(target); if (changed) @@ -347,7 +349,7 @@ namespace Ryujinx.Cpu.Jit AssertMapped(va, (ulong)size); } - return _addressSpaceMirror.GetSpan(va, size); + return _addressSpace.Mirror.GetSpan(va, size); } /// @@ -362,7 +364,7 @@ namespace Ryujinx.Cpu.Jit AssertMapped(va, (ulong)size); } - return _addressSpaceMirror.GetWritableRegion(va, size); + return _addressSpace.Mirror.GetWritableRegion(va, size); } /// @@ -370,7 +372,7 @@ namespace Ryujinx.Cpu.Jit { SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), true); - return ref _addressSpaceMirror.GetRef(va); + return ref _addressSpace.Mirror.GetRef(va); } /// @@ -454,6 +456,14 @@ namespace Ryujinx.Cpu.Jit return true; } + /// + public IEnumerable GetHostRegions(ulong va, ulong size) + { + AssertValidAddressAndSize(va, size); + + return Enumerable.Repeat(new HostMemoryRange((nuint)(ulong)_addressSpace.Mirror.GetPointer(va, size), size), 1); + } + /// public IEnumerable GetPhysicalRegions(ulong va, ulong size) { @@ -692,7 +702,7 @@ namespace Ryujinx.Cpu.Jit _ => MemoryPermission.None }; - _addressSpace.Reprotect(va, size, protection, false); + _addressSpace.Base.Reprotect(va, size, protection, false); } /// @@ -799,7 +809,6 @@ namespace Ryujinx.Cpu.Jit protected override void Destroy() { _addressSpace.Dispose(); - _addressSpaceMirror.Dispose(); _memoryEh.Dispose(); } -- cgit v1.2.3