diff options
Diffstat (limited to 'src/Ryujinx.Cpu')
-rw-r--r-- | src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs | 245 | ||||
-rw-r--r-- | src/Ryujinx.Cpu/Jit/MemoryManager.cs | 254 | ||||
-rw-r--r-- | src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs | 89 | ||||
-rw-r--r-- | src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs | 193 | ||||
-rw-r--r-- | src/Ryujinx.Cpu/VirtualMemoryManagerRefCountedBase.cs | 5 |
5 files changed, 176 insertions, 610 deletions
diff --git a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs index 80f7c8a1..0c2e5f33 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs @@ -3,10 +3,10 @@ using Ryujinx.Memory; using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Runtime.Versioning; namespace Ryujinx.Cpu.AppleHv @@ -15,7 +15,7 @@ namespace Ryujinx.Cpu.AppleHv /// Represents a CPU memory manager which maps guest virtual memory directly onto the Hypervisor page table. /// </summary> [SupportedOSPlatform("macos")] - public class HvMemoryManager : VirtualMemoryManagerRefCountedBase<ulong, ulong>, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock + public sealed class HvMemoryManager : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked { private readonly InvalidAccessHandler _invalidAccessHandler; @@ -97,12 +97,6 @@ namespace Ryujinx.Cpu.AppleHv } /// <inheritdoc/> - public void MapForeign(ulong va, nuint hostPointer, ulong size) - { - throw new NotSupportedException(); - } - - /// <inheritdoc/> public void Unmap(ulong va, ulong size) { AssertValidAddressAndSize(va, size); @@ -126,20 +120,11 @@ namespace Ryujinx.Cpu.AppleHv } } - /// <inheritdoc/> - public T Read<T>(ulong va) where T : unmanaged - { - return MemoryMarshal.Cast<byte, T>(GetSpan(va, Unsafe.SizeOf<T>()))[0]; - } - - /// <inheritdoc/> - public T ReadTracked<T>(ulong va) where T : unmanaged + public override T ReadTracked<T>(ulong va) { try { - SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), false); - - return Read<T>(va); + return base.ReadTracked<T>(va); } catch (InvalidMemoryRegionException) { @@ -152,7 +137,6 @@ namespace Ryujinx.Cpu.AppleHv } } - /// <inheritdoc/> public override void Read(ulong va, Span<byte> data) { try @@ -168,101 +152,26 @@ namespace Ryujinx.Cpu.AppleHv } } - /// <inheritdoc/> - public void Write<T>(ulong va, T value) where T : unmanaged - { - Write(va, MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateSpan(ref value, 1))); - } - - /// <inheritdoc/> - public void Write(ulong va, ReadOnlySpan<byte> data) - { - if (data.Length == 0) - { - return; - } - - SignalMemoryTracking(va, (ulong)data.Length, true); - - WriteImpl(va, data); - } - - /// <inheritdoc/> - public void WriteUntracked(ulong va, ReadOnlySpan<byte> data) - { - if (data.Length == 0) - { - return; - } - - WriteImpl(va, data); - } - - /// <inheritdoc/> - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data) + public override void Write(ulong va, ReadOnlySpan<byte> data) { - if (data.Length == 0) + try { - return false; + base.Write(va, data); } - - SignalMemoryTracking(va, (ulong)data.Length, false); - - if (IsContiguousAndMapped(va, data.Length)) + catch (InvalidMemoryRegionException) { - var target = _backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length); - - bool changed = !data.SequenceEqual(target); - - if (changed) + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) { - data.CopyTo(target); + throw; } - - return changed; - } - else - { - WriteImpl(va, data); - - return true; } } - private void WriteImpl(ulong va, ReadOnlySpan<byte> data) + public override void WriteUntracked(ulong va, ReadOnlySpan<byte> data) { try { - AssertValidAddressAndSize(va, (ulong)data.Length); - - if (IsContiguousAndMapped(va, data.Length)) - { - data.CopyTo(_backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length)); - } - else - { - int offset = 0, size; - - if ((va & PageMask) != 0) - { - ulong pa = GetPhysicalAddressChecked(va); - - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - data[..size].CopyTo(_backingMemory.GetSpan(pa, size)); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - ulong pa = GetPhysicalAddressChecked(va + (ulong)offset); - - size = Math.Min(data.Length - offset, PageSize); - - data.Slice(offset, size).CopyTo(_backingMemory.GetSpan(pa, size)); - } - } + base.WriteUntracked(va, data); } catch (InvalidMemoryRegionException) { @@ -273,61 +182,23 @@ namespace Ryujinx.Cpu.AppleHv } } - /// <inheritdoc/> - public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false) + public override ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false) { - if (size == 0) - { - return ReadOnlySpan<byte>.Empty; - } - - if (tracked) - { - SignalMemoryTracking(va, (ulong)size, false); - } - - if (IsContiguousAndMapped(va, size)) - { - return _backingMemory.GetSpan(GetPhysicalAddressInternal(va), size); - } - else - { - Span<byte> data = new byte[size]; - - base.Read(va, data); - - return data; - } - } - - /// <inheritdoc/> - public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) - { - if (size == 0) - { - return new WritableRegion(null, va, Memory<byte>.Empty); - } - - if (tracked) - { - SignalMemoryTracking(va, (ulong)size, true); - } - - if (IsContiguousAndMapped(va, size)) + try { - return new WritableRegion(null, va, _backingMemory.GetMemory(GetPhysicalAddressInternal(va), size)); + return base.GetReadOnlySequence(va, size, tracked); } - else + catch (InvalidMemoryRegionException) { - Memory<byte> memory = new byte[size]; - - base.Read(va, memory.Span); + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } - return new WritableRegion(this, va, memory); + return ReadOnlySequence<byte>.Empty; } } - /// <inheritdoc/> public ref T GetRef<T>(ulong va) where T : unmanaged { if (!IsContiguous(va, Unsafe.SizeOf<T>())) @@ -340,9 +211,8 @@ namespace Ryujinx.Cpu.AppleHv return ref _backingMemory.GetRef<T>(GetPhysicalAddressChecked(va)); } - /// <inheritdoc/> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { return ValidateAddress(va) && _pages.IsMapped(va); } @@ -355,39 +225,6 @@ namespace Ryujinx.Cpu.AppleHv return _pages.IsRangeMapped(va, size); } - private static void ThrowMemoryNotContiguous() => throw new MemoryNotContiguousException(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguousAndMapped(ulong va, int size) => IsContiguous(va, size) && IsMapped(va); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguous(ulong va, int size) - { - if (!ValidateAddress(va) || !ValidateAddressAndSize(va, (ulong)size)) - { - return false; - } - - int pages = GetPagesCount(va, (uint)size, out va); - - for (int page = 0; page < pages - 1; page++) - { - if (!ValidateAddress(va + PageSize)) - { - return false; - } - - if (GetPhysicalAddressInternal(va) + PageSize != GetPhysicalAddressInternal(va + PageSize)) - { - return false; - } - - va += PageSize; - } - - return true; - } - /// <inheritdoc/> public IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size) { @@ -464,11 +301,10 @@ namespace Ryujinx.Cpu.AppleHv return regions; } - /// <inheritdoc/> /// <remarks> /// This function also validates that the given range is both valid and mapped, and will throw if it is not. /// </remarks> - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) { AssertValidAddressAndSize(va, size); @@ -481,24 +317,6 @@ namespace Ryujinx.Cpu.AppleHv _pages.SignalMemoryTracking(Tracking, va, size, write, exemptId); } - /// <summary> - /// Computes the number of pages in a virtual address range. - /// </summary> - /// <param name="va">Virtual address of the range</param> - /// <param name="size">Size of the range</param> - /// <param name="startVa">The virtual address of the beginning of the first page</param> - /// <remarks>This function does not differentiate between allocated and unallocated pages.</remarks> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetPagesCount(ulong va, ulong size, out ulong startVa) - { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); - } - - /// <inheritdoc/> public void Reprotect(ulong va, ulong size, MemoryPermission protection) { // TODO @@ -535,7 +353,7 @@ namespace Ryujinx.Cpu.AppleHv return Tracking.BeginSmartGranularTracking(address, size, granularity, id); } - private ulong GetPhysicalAddressChecked(ulong va) + private nuint GetPhysicalAddressChecked(ulong va) { if (!IsMapped(va)) { @@ -545,9 +363,9 @@ namespace Ryujinx.Cpu.AppleHv return GetPhysicalAddressInternal(va); } - private ulong GetPhysicalAddressInternal(ulong va) + private nuint GetPhysicalAddressInternal(ulong va) { - return _pageTable.Read(va) + (va & PageMask); + return (nuint)(_pageTable.Read(va) + (va & PageMask)); } /// <summary> @@ -558,10 +376,17 @@ namespace Ryujinx.Cpu.AppleHv _addressSpace.Dispose(); } - protected override Span<byte> GetPhysicalAddressSpan(ulong pa, int size) + protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size) + => _backingMemory.GetMemory(pa, size); + + protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size) => _backingMemory.GetSpan(pa, size); - protected override ulong TranslateVirtualAddressForRead(ulong va) + protected override nuint TranslateVirtualAddressChecked(ulong va) => GetPhysicalAddressChecked(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) + => GetPhysicalAddressInternal(va); + } } diff --git a/src/Ryujinx.Cpu/Jit/MemoryManager.cs b/src/Ryujinx.Cpu/Jit/MemoryManager.cs index c87c8b8c..dfa5b935 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManager.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -3,6 +3,7 @@ using Ryujinx.Memory; using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; @@ -14,7 +15,7 @@ namespace Ryujinx.Cpu.Jit /// <summary> /// Represents a CPU memory manager. /// </summary> - public sealed class MemoryManager : VirtualMemoryManagerRefCountedBase<ulong, ulong>, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock + public sealed class MemoryManager : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked { private const int PteSize = 8; @@ -98,12 +99,6 @@ namespace Ryujinx.Cpu.Jit } /// <inheritdoc/> - public void MapForeign(ulong va, nuint hostPointer, ulong size) - { - throw new NotSupportedException(); - } - - /// <inheritdoc/> public void Unmap(ulong va, ulong size) { // If size is 0, there's nothing to unmap, just exit early. @@ -128,20 +123,11 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public T Read<T>(ulong va) where T : unmanaged - { - return MemoryMarshal.Cast<byte, T>(GetSpan(va, Unsafe.SizeOf<T>()))[0]; - } - - /// <inheritdoc/> - public T ReadTracked<T>(ulong va) where T : unmanaged + public override T ReadTracked<T>(ulong va) { try { - SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), false); - - return Read<T>(va); + return base.ReadTracked<T>(va); } catch (InvalidMemoryRegionException) { @@ -190,23 +176,19 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public void Write<T>(ulong va, T value) where T : unmanaged + public override void Write(ulong va, ReadOnlySpan<byte> data) { - Write(va, MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateSpan(ref value, 1))); - } - - /// <inheritdoc/> - public void Write(ulong va, ReadOnlySpan<byte> data) - { - if (data.Length == 0) + try { - return; + base.Write(va, data); + } + catch (InvalidMemoryRegionException) + { + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } } - - SignalMemoryTracking(va, (ulong)data.Length, true); - - WriteImpl(va, data); } /// <inheritdoc/> @@ -216,91 +198,14 @@ namespace Ryujinx.Cpu.Jit SignalMemoryTrackingImpl(va, (ulong)data.Length, true, true); - WriteImpl(va, data); - } - - /// <inheritdoc/> - public void WriteUntracked(ulong va, ReadOnlySpan<byte> data) - { - if (data.Length == 0) - { - return; - } - - WriteImpl(va, data); - } - - /// <inheritdoc/> - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data) - { - if (data.Length == 0) - { - return false; - } - - SignalMemoryTracking(va, (ulong)data.Length, false); - - if (IsContiguousAndMapped(va, data.Length)) - { - var target = _backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length); - - bool changed = !data.SequenceEqual(target); - - if (changed) - { - data.CopyTo(target); - } - - return changed; - } - else - { - WriteImpl(va, data); - - return true; - } + Write(va, data); } - /// <summary> - /// Writes data to CPU mapped memory. - /// </summary> - /// <param name="va">Virtual address to write the data into</param> - /// <param name="data">Data to be written</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WriteImpl(ulong va, ReadOnlySpan<byte> data) + public override void WriteUntracked(ulong va, ReadOnlySpan<byte> data) { try { - AssertValidAddressAndSize(va, (ulong)data.Length); - - if (IsContiguousAndMapped(va, data.Length)) - { - data.CopyTo(_backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length)); - } - else - { - int offset = 0, size; - - if ((va & PageMask) != 0) - { - ulong pa = GetPhysicalAddressInternal(va); - - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - data[..size].CopyTo(_backingMemory.GetSpan(pa, size)); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - ulong pa = GetPhysicalAddressInternal(va + (ulong)offset); - - size = Math.Min(data.Length - offset, PageSize); - - data.Slice(offset, size).CopyTo(_backingMemory.GetSpan(pa, size)); - } - } + base.WriteUntracked(va, data); } catch (InvalidMemoryRegionException) { @@ -311,61 +216,23 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false) + public override ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false) { - if (size == 0) - { - return ReadOnlySpan<byte>.Empty; - } - - if (tracked) - { - SignalMemoryTracking(va, (ulong)size, false); - } - - if (IsContiguousAndMapped(va, size)) - { - return _backingMemory.GetSpan(GetPhysicalAddressInternal(va), size); - } - else - { - Span<byte> data = new byte[size]; - - base.Read(va, data); - - return data; - } - } - - /// <inheritdoc/> - public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) - { - if (size == 0) + try { - return new WritableRegion(null, va, Memory<byte>.Empty); + return base.GetReadOnlySequence(va, size, tracked); } - - if (IsContiguousAndMapped(va, size)) + catch (InvalidMemoryRegionException) { - if (tracked) + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) { - SignalMemoryTracking(va, (ulong)size, true); + throw; } - return new WritableRegion(null, va, _backingMemory.GetMemory(GetPhysicalAddressInternal(va), size)); - } - else - { - Memory<byte> memory = new byte[size]; - - GetSpan(va, size).CopyTo(memory.Span); - - return new WritableRegion(this, va, memory, tracked); + return ReadOnlySequence<byte>.Empty; } } - /// <inheritdoc/> public ref T GetRef<T>(ulong va) where T : unmanaged { if (!IsContiguous(va, Unsafe.SizeOf<T>())) @@ -378,56 +245,6 @@ namespace Ryujinx.Cpu.Jit return ref _backingMemory.GetRef<T>(GetPhysicalAddressInternal(va)); } - /// <summary> - /// Computes the number of pages in a virtual address range. - /// </summary> - /// <param name="va">Virtual address of the range</param> - /// <param name="size">Size of the range</param> - /// <param name="startVa">The virtual address of the beginning of the first page</param> - /// <remarks>This function does not differentiate between allocated and unallocated pages.</remarks> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetPagesCount(ulong va, uint size, out ulong startVa) - { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); - } - - private static void ThrowMemoryNotContiguous() => throw new MemoryNotContiguousException(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguousAndMapped(ulong va, int size) => IsContiguous(va, size) && IsMapped(va); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguous(ulong va, int size) - { - if (!ValidateAddress(va) || !ValidateAddressAndSize(va, (ulong)size)) - { - return false; - } - - int pages = GetPagesCount(va, (uint)size, out va); - - for (int page = 0; page < pages - 1; page++) - { - if (!ValidateAddress(va + PageSize)) - { - return false; - } - - if (GetPhysicalAddressInternal(va) + PageSize != GetPhysicalAddressInternal(va + PageSize)) - { - return false; - } - - va += PageSize; - } - - return true; - } - /// <inheritdoc/> public IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size) { @@ -532,9 +349,8 @@ namespace Ryujinx.Cpu.Jit return true; } - /// <inheritdoc/> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { if (!ValidateAddress(va)) { @@ -544,9 +360,9 @@ namespace Ryujinx.Cpu.Jit return _pageTable.Read<ulong>((va / PageSize) * PteSize) != 0; } - private ulong GetPhysicalAddressInternal(ulong va) + private nuint GetPhysicalAddressInternal(ulong va) { - return PteToPa(_pageTable.Read<ulong>((va / PageSize) * PteSize) & ~(0xffffUL << 48)) + (va & PageMask); + return (nuint)(PteToPa(_pageTable.Read<ulong>((va / PageSize) * PteSize) & ~(0xffffUL << 48)) + (va & PageMask)); } /// <inheritdoc/> @@ -643,9 +459,7 @@ namespace Ryujinx.Cpu.Jit { ref long pageRef = ref _pageTable.GetRef<long>(pageStart * PteSize); - long pte; - - pte = Volatile.Read(ref pageRef); + long pte = Volatile.Read(ref pageRef); if ((pte & tag) != 0) { @@ -663,7 +477,7 @@ namespace Ryujinx.Cpu.Jit } /// <inheritdoc/> - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) { SignalMemoryTrackingImpl(va, size, write, false, precise, exemptId); } @@ -683,10 +497,16 @@ namespace Ryujinx.Cpu.Jit /// </summary> protected override void Destroy() => _pageTable.Dispose(); - protected override Span<byte> GetPhysicalAddressSpan(ulong pa, int size) + protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size) + => _backingMemory.GetMemory(pa, size); + + protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size) => _backingMemory.GetSpan(pa, size); - protected override ulong TranslateVirtualAddressForRead(ulong va) + protected override nuint TranslateVirtualAddressChecked(ulong va) + => GetPhysicalAddressInternal(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) => GetPhysicalAddressInternal(va); } } diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs index f410d02e..c60ab6b2 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs @@ -3,6 +3,7 @@ using Ryujinx.Memory; using Ryujinx.Memory.Range; using Ryujinx.Memory.Tracking; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; @@ -12,7 +13,7 @@ namespace Ryujinx.Cpu.Jit /// <summary> /// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region. /// </summary> - public sealed class MemoryManagerHostMapped : VirtualMemoryManagerRefCountedBase<ulong, ulong>, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock + public sealed class MemoryManagerHostMapped : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked { private readonly InvalidAccessHandler _invalidAccessHandler; private readonly bool _unsafeMode; @@ -97,12 +98,6 @@ namespace Ryujinx.Cpu.Jit } /// <inheritdoc/> - public void MapForeign(ulong va, nuint hostPointer, ulong size) - { - throw new NotSupportedException(); - } - - /// <inheritdoc/> public void Unmap(ulong va, ulong size) { AssertValidAddressAndSize(va, size); @@ -138,8 +133,7 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public T Read<T>(ulong va) where T : unmanaged + public override T Read<T>(ulong va) { try { @@ -158,14 +152,11 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public T ReadTracked<T>(ulong va) where T : unmanaged + public override T ReadTracked<T>(ulong va) { try { - SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), false); - - return Read<T>(va); + return base.ReadTracked<T>(va); } catch (InvalidMemoryRegionException) { @@ -178,7 +169,6 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> public override void Read(ulong va, Span<byte> data) { try @@ -196,9 +186,7 @@ namespace Ryujinx.Cpu.Jit } } - - /// <inheritdoc/> - public void Write<T>(ulong va, T value) where T : unmanaged + public override void Write<T>(ulong va, T value) { try { @@ -215,8 +203,7 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public void Write(ulong va, ReadOnlySpan<byte> data) + public override void Write(ulong va, ReadOnlySpan<byte> data) { try { @@ -233,8 +220,7 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public void WriteUntracked(ulong va, ReadOnlySpan<byte> data) + public override void WriteUntracked(ulong va, ReadOnlySpan<byte> data) { try { @@ -251,8 +237,7 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data) + public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data) { try { @@ -279,8 +264,21 @@ namespace Ryujinx.Cpu.Jit } } - /// <inheritdoc/> - public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false) + public override ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false) + { + if (tracked) + { + SignalMemoryTracking(va, (ulong)size, write: false); + } + else + { + AssertMapped(va, (ulong)size); + } + + return new ReadOnlySequence<byte>(_addressSpace.Mirror.GetMemory(va, size)); + } + + public override ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false) { if (tracked) { @@ -294,8 +292,7 @@ namespace Ryujinx.Cpu.Jit return _addressSpace.Mirror.GetSpan(va, size); } - /// <inheritdoc/> - public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) + public override WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) { if (tracked) { @@ -309,7 +306,6 @@ namespace Ryujinx.Cpu.Jit return _addressSpace.Mirror.GetWritableRegion(va, size); } - /// <inheritdoc/> public ref T GetRef<T>(ulong va) where T : unmanaged { SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), true); @@ -317,9 +313,8 @@ namespace Ryujinx.Cpu.Jit return ref _addressSpace.Mirror.GetRef<T>(va); } - /// <inheritdoc/> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { return ValidateAddress(va) && _pages.IsMapped(va); } @@ -390,11 +385,10 @@ namespace Ryujinx.Cpu.Jit return _pageTable.Read(va) + (va & PageMask); } - /// <inheritdoc/> /// <remarks> /// This function also validates that the given range is both valid and mapped, and will throw if it is not. /// </remarks> - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) { AssertValidAddressAndSize(va, size); @@ -407,23 +401,6 @@ namespace Ryujinx.Cpu.Jit _pages.SignalMemoryTracking(Tracking, va, size, write, exemptId); } - /// <summary> - /// Computes the number of pages in a virtual address range. - /// </summary> - /// <param name="va">Virtual address of the range</param> - /// <param name="size">Size of the range</param> - /// <param name="startVa">The virtual address of the beginning of the first page</param> - /// <remarks>This function does not differentiate between allocated and unallocated pages.</remarks> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetPagesCount(ulong va, ulong size, out ulong startVa) - { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); - } - /// <inheritdoc/> public void Reprotect(ulong va, ulong size, MemoryPermission protection) { @@ -470,10 +447,16 @@ namespace Ryujinx.Cpu.Jit _memoryEh.Dispose(); } - protected override Span<byte> GetPhysicalAddressSpan(ulong pa, int size) + protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size) + => _addressSpace.Mirror.GetMemory(pa, size); + + protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size) => _addressSpace.Mirror.GetSpan(pa, size); - protected override ulong TranslateVirtualAddressForRead(ulong va) - => va; + protected override nuint TranslateVirtualAddressChecked(ulong va) + => (nuint)GetPhysicalAddressChecked(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) + => (nuint)GetPhysicalAddressInternal(va); } } diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs index 18404bcc..b2964cd2 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs @@ -8,14 +8,13 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace Ryujinx.Cpu.Jit { /// <summary> /// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region. /// </summary> - public sealed class MemoryManagerHostTracked : VirtualMemoryManagerRefCountedBase<ulong, ulong>, IWritableBlock, IMemoryManager, IVirtualMemoryManagerTracked + public sealed class MemoryManagerHostTracked : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked { private readonly InvalidAccessHandler _invalidAccessHandler; private readonly bool _unsafeMode; @@ -101,12 +100,6 @@ namespace Ryujinx.Cpu.Jit } /// <inheritdoc/> - public void MapForeign(ulong va, nuint hostPointer, ulong size) - { - throw new NotSupportedException(); - } - - /// <inheritdoc/> public void Unmap(ulong va, ulong size) { AssertValidAddressAndSize(va, size); @@ -120,18 +113,11 @@ namespace Ryujinx.Cpu.Jit _nativePageTable.Unmap(va, size); } - public T Read<T>(ulong va) where T : unmanaged - { - return MemoryMarshal.Cast<byte, T>(GetSpan(va, Unsafe.SizeOf<T>()))[0]; - } - - public T ReadTracked<T>(ulong va) where T : unmanaged + public override T ReadTracked<T>(ulong va) { try { - SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), false); - - return Read<T>(va); + return base.ReadTracked<T>(va); } catch (InvalidMemoryRegionException) { @@ -146,37 +132,38 @@ namespace Ryujinx.Cpu.Jit public override void Read(ulong va, Span<byte> data) { - ReadImpl(va, data); - } - - public void Write<T>(ulong va, T value) where T : unmanaged - { - Write(va, MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateSpan(ref value, 1))); - } - - public void Write(ulong va, ReadOnlySpan<byte> data) - { if (data.Length == 0) { return; } - SignalMemoryTracking(va, (ulong)data.Length, true); + try + { + AssertValidAddressAndSize(va, (ulong)data.Length); + + ulong endVa = va + (ulong)data.Length; + int offset = 0; - WriteImpl(va, data); - } + while (va < endVa) + { + (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(data.Length - offset)); - public void WriteUntracked(ulong va, ReadOnlySpan<byte> data) - { - if (data.Length == 0) + memory.GetSpan(rangeOffset, (int)copySize).CopyTo(data.Slice(offset, (int)copySize)); + + va += copySize; + offset += (int)copySize; + } + } + catch (InvalidMemoryRegionException) { - return; + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } } - - WriteImpl(va, data); } - public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data) + public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data) { if (data.Length == 0) { @@ -206,35 +193,7 @@ namespace Ryujinx.Cpu.Jit } } - private void WriteImpl(ulong va, ReadOnlySpan<byte> data) - { - try - { - AssertValidAddressAndSize(va, (ulong)data.Length); - - ulong endVa = va + (ulong)data.Length; - int offset = 0; - - while (va < endVa) - { - (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(data.Length - offset)); - - data.Slice(offset, (int)copySize).CopyTo(memory.GetSpan(rangeOffset, (int)copySize)); - - va += copySize; - offset += (int)copySize; - } - } - catch (InvalidMemoryRegionException) - { - if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) - { - throw; - } - } - } - - public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false) + public override ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false) { if (size == 0) { @@ -254,13 +213,13 @@ namespace Ryujinx.Cpu.Jit { Span<byte> data = new byte[size]; - ReadImpl(va, data); + Read(va, data); return data; } } - public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) + public override WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) { if (size == 0) { @@ -280,7 +239,7 @@ namespace Ryujinx.Cpu.Jit { Memory<byte> memory = new byte[size]; - ReadImpl(va, memory.Span); + Read(va, memory.Span); return new WritableRegion(this, va, memory); } @@ -299,7 +258,7 @@ namespace Ryujinx.Cpu.Jit } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsMapped(ulong va) + public override bool IsMapped(ulong va) { return ValidateAddress(va) && _pages.IsMapped(va); } @@ -311,8 +270,6 @@ namespace Ryujinx.Cpu.Jit return _pages.IsRangeMapped(va, size); } - private static void ThrowMemoryNotContiguous() => throw new MemoryNotContiguousException(); - private bool TryGetVirtualContiguous(ulong va, int size, out MemoryBlock memory, out ulong offset) { if (_addressSpace.HasAnyPrivateAllocation(va, (ulong)size, out PrivateRange range)) @@ -491,44 +448,11 @@ namespace Ryujinx.Cpu.Jit return regions; } - private void ReadImpl(ulong va, Span<byte> data) - { - if (data.Length == 0) - { - return; - } - - try - { - AssertValidAddressAndSize(va, (ulong)data.Length); - - ulong endVa = va + (ulong)data.Length; - int offset = 0; - - while (va < endVa) - { - (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(data.Length - offset)); - - memory.GetSpan(rangeOffset, (int)copySize).CopyTo(data.Slice(offset, (int)copySize)); - - va += copySize; - offset += (int)copySize; - } - } - catch (InvalidMemoryRegionException) - { - if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) - { - throw; - } - } - } - /// <inheritdoc/> /// <remarks> /// This function also validates that the given range is both valid and mapped, and will throw if it is not. /// </remarks> - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) + public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) { AssertValidAddressAndSize(va, size); @@ -543,23 +467,6 @@ namespace Ryujinx.Cpu.Jit _pages.SignalMemoryTracking(Tracking, va, size, write, exemptId); } - /// <summary> - /// Computes the number of pages in a virtual address range. - /// </summary> - /// <param name="va">Virtual address of the range</param> - /// <param name="size">Size of the range</param> - /// <param name="startVa">The virtual address of the beginning of the first page</param> - /// <remarks>This function does not differentiate between allocated and unallocated pages.</remarks> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int GetPagesCount(ulong va, ulong size, out ulong startVa) - { - // WARNING: Always check if ulong does not overflow during the operations. - startVa = va & ~(ulong)PageMask; - ulong vaSpan = (va - startVa + size + PageMask) & ~(ulong)PageMask; - - return (int)(vaSpan / PageSize); - } - public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags = RegionFlags.None) { return Tracking.BeginTracking(address, size, id, flags); @@ -618,10 +525,44 @@ namespace Ryujinx.Cpu.Jit _nativePageTable.Dispose(); } - protected override Span<byte> GetPhysicalAddressSpan(ulong pa, int size) + protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size) + => _backingMemory.GetMemory(pa, size); + + protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size) => _backingMemory.GetSpan(pa, size); - protected override ulong TranslateVirtualAddressForRead(ulong va) - => GetPhysicalAddressInternal(va); + protected override void WriteImpl(ulong va, ReadOnlySpan<byte> data) + { + try + { + AssertValidAddressAndSize(va, (ulong)data.Length); + + ulong endVa = va + (ulong)data.Length; + int offset = 0; + + while (va < endVa) + { + (MemoryBlock memory, ulong rangeOffset, ulong copySize) = GetMemoryOffsetAndSize(va, (ulong)(data.Length - offset)); + + data.Slice(offset, (int)copySize).CopyTo(memory.GetSpan(rangeOffset, (int)copySize)); + + va += copySize; + offset += (int)copySize; + } + } + catch (InvalidMemoryRegionException) + { + if (_invalidAccessHandler == null || !_invalidAccessHandler(va)) + { + throw; + } + } + } + + protected override nuint TranslateVirtualAddressChecked(ulong va) + => (nuint)GetPhysicalAddressChecked(va); + + protected override nuint TranslateVirtualAddressUnchecked(ulong va) + => (nuint)GetPhysicalAddressInternal(va); } } diff --git a/src/Ryujinx.Cpu/VirtualMemoryManagerRefCountedBase.cs b/src/Ryujinx.Cpu/VirtualMemoryManagerRefCountedBase.cs index c2d8cfb1..3c7b3380 100644 --- a/src/Ryujinx.Cpu/VirtualMemoryManagerRefCountedBase.cs +++ b/src/Ryujinx.Cpu/VirtualMemoryManagerRefCountedBase.cs @@ -1,13 +1,10 @@ using Ryujinx.Memory; using System.Diagnostics; -using System.Numerics; using System.Threading; namespace Ryujinx.Cpu { - public abstract class VirtualMemoryManagerRefCountedBase<TVirtual, TPhysical> : VirtualMemoryManagerBase<TVirtual, TPhysical>, IRefCounted - where TVirtual : IBinaryInteger<TVirtual> - where TPhysical : IBinaryInteger<TPhysical> + public abstract class VirtualMemoryManagerRefCountedBase : VirtualMemoryManagerBase, IRefCounted { private int _referenceCount; |