diff options
| author | jhorv <38920027+jhorv@users.noreply.github.com> | 2024-03-09 19:01:51 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-09 21:01:51 -0300 |
| commit | a3a63d43948b79450d1a0ee963ea4796cb3532a0 (patch) | |
| tree | b97c0c19bac9ce065fdf4acad7b0c170f7a6b1dc /src/Ryujinx.Memory | |
| parent | 3924bd1a4364455ab8a5747e3cb0b3000dbaa589 (diff) | |
Refactor memory managers to a common base class, consolidate Read() method logic (#6360)
* - add new abstract class `VirtualMemoryManagerBase`
- rename `MemoryManagerBase` to `VirtualMemoryManagerRefCountedBase` and derive from `VirtualMemoryManagerBase`
- change `AddressSpaceManager`, `HvMemoryManager`, `MemoryManager`, and `MemoryManagerHostMapped` to implement abstract members and use the inherited `void VirtualMemoryManagerBase.Read(TVirtual va, Span<byte> data)` implementation.
* move property `AddressSpaceSize` up by the other properties
Diffstat (limited to 'src/Ryujinx.Memory')
| -rw-r--r-- | src/Ryujinx.Memory/AddressSpaceManager.cs | 85 | ||||
| -rw-r--r-- | src/Ryujinx.Memory/VirtualMemoryManagerBase.cs | 91 |
2 files changed, 102 insertions, 74 deletions
diff --git a/src/Ryujinx.Memory/AddressSpaceManager.cs b/src/Ryujinx.Memory/AddressSpaceManager.cs index 021d3366..b953eb30 100644 --- a/src/Ryujinx.Memory/AddressSpaceManager.cs +++ b/src/Ryujinx.Memory/AddressSpaceManager.cs @@ -11,12 +11,8 @@ namespace Ryujinx.Memory /// Represents a address space manager. /// Supports virtual memory region mapping, address translation and read/write access to mapped regions. /// </summary> - public sealed class AddressSpaceManager : IVirtualMemoryManager, IWritableBlock + public sealed class AddressSpaceManager : VirtualMemoryManagerBase<ulong, nuint>, IVirtualMemoryManager, IWritableBlock { - public const int PageBits = PageTable<nuint>.PageBits; - public const int PageSize = PageTable<nuint>.PageSize; - public const int PageMask = PageTable<nuint>.PageMask; - /// <inheritdoc/> public bool Supports4KBPages => true; @@ -25,11 +21,11 @@ namespace Ryujinx.Memory /// </summary> public int AddressSpaceBits { get; } - private readonly ulong _addressSpaceSize; - private readonly MemoryBlock _backingMemory; private readonly PageTable<nuint> _pageTable; + protected override ulong AddressSpaceSize { get; } + /// <summary> /// Creates a new instance of the memory manager. /// </summary> @@ -47,7 +43,7 @@ namespace Ryujinx.Memory } AddressSpaceBits = asBits; - _addressSpaceSize = asSize; + AddressSpaceSize = asSize; _backingMemory = backingMemory; _pageTable = new PageTable<nuint>(); } @@ -103,12 +99,6 @@ namespace Ryujinx.Memory } /// <inheritdoc/> - public void Read(ulong va, Span<byte> data) - { - ReadImpl(va, data); - } - - /// <inheritdoc/> public void Write<T>(ulong va, T value) where T : unmanaged { Write(va, MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateSpan(ref value, 1))); @@ -174,7 +164,7 @@ namespace Ryujinx.Memory { Span<byte> data = new byte[size]; - ReadImpl(va, data); + Read(va, data); return data; } @@ -346,34 +336,6 @@ namespace Ryujinx.Memory return regions; } - private void ReadImpl(ulong va, Span<byte> data) - { - if (data.Length == 0) - { - return; - } - - AssertValidAddressAndSize(va, (ulong)data.Length); - - int offset = 0, size; - - if ((va & PageMask) != 0) - { - size = Math.Min(data.Length, PageSize - (int)(va & PageMask)); - - GetHostSpanContiguous(va, size).CopyTo(data[..size]); - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - size = Math.Min(data.Length - offset, PageSize); - - GetHostSpanContiguous(va + (ulong)offset, size).CopyTo(data.Slice(offset, size)); - } - } - /// <inheritdoc/> [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsMapped(ulong va) @@ -414,37 +376,6 @@ namespace Ryujinx.Memory return true; } - private bool ValidateAddress(ulong va) - { - return va < _addressSpaceSize; - } - - /// <summary> - /// Checks if the combination of virtual address and size is part of the addressable space. - /// </summary> - /// <param name="va">Virtual address of the range</param> - /// <param name="size">Size of the range in bytes</param> - /// <returns>True if the combination of virtual address and size is part of the addressable space</returns> - private bool ValidateAddressAndSize(ulong va, ulong size) - { - ulong endVa = va + size; - return endVa >= va && endVa >= size && endVa <= _addressSpaceSize; - } - - /// <summary> - /// Ensures the combination of virtual address and size is part of the addressable space. - /// </summary> - /// <param name="va">Virtual address of the range</param> - /// <param name="size">Size of the range in bytes</param> - /// <exception cref="InvalidMemoryRegionException">Throw when the memory region specified outside the addressable space</exception> - private void AssertValidAddressAndSize(ulong va, ulong size) - { - if (!ValidateAddressAndSize(va, size)) - { - throw new InvalidMemoryRegionException($"va=0x{va:X16}, size=0x{size:X16}"); - } - } - private unsafe Span<byte> GetHostSpanContiguous(ulong va, int size) { return new Span<byte>((void*)GetHostAddress(va), size); @@ -471,5 +402,11 @@ namespace Ryujinx.Memory { // Only the ARM Memory Manager has tracking for now. } + + protected override unsafe Span<byte> GetPhysicalAddressSpan(nuint pa, int size) + => new((void*)pa, size); + + protected override nuint TranslateVirtualAddressForRead(ulong va) + => GetHostAddress(va); } } diff --git a/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs b/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs new file mode 100644 index 00000000..cbec88cc --- /dev/null +++ b/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs @@ -0,0 +1,91 @@ +using System; +using System.Numerics; + +namespace Ryujinx.Memory +{ + public abstract class VirtualMemoryManagerBase<TVirtual, TPhysical> + where TVirtual : IBinaryInteger<TVirtual> + where TPhysical : IBinaryInteger<TPhysical> + { + public const int PageBits = 12; + public const int PageSize = 1 << PageBits; + public const int PageMask = PageSize - 1; + + protected abstract TVirtual AddressSpaceSize { get; } + + public virtual void Read(TVirtual va, Span<byte> data) + { + if (data.Length == 0) + { + return; + } + + AssertValidAddressAndSize(va, TVirtual.CreateChecked(data.Length)); + + int offset = 0, size; + + if ((int.CreateTruncating(va) & PageMask) != 0) + { + TPhysical pa = TranslateVirtualAddressForRead(va); + + size = Math.Min(data.Length, PageSize - ((int.CreateTruncating(va) & PageMask))); + + GetPhysicalAddressSpan(pa, size).CopyTo(data[..size]); + + offset += size; + } + + for (; offset < data.Length; offset += size) + { + TPhysical pa = TranslateVirtualAddressForRead(va + TVirtual.CreateChecked(offset)); + + size = Math.Min(data.Length - offset, PageSize); + + GetPhysicalAddressSpan(pa, size).CopyTo(data.Slice(offset, size)); + } + } + + /// <summary> + /// Ensures the combination of virtual address and size is part of the addressable space. + /// </summary> + /// <param name="va">Virtual address of the range</param> + /// <param name="size">Size of the range in bytes</param> + /// <exception cref="InvalidMemoryRegionException">Throw when the memory region specified outside the addressable space</exception> + protected void AssertValidAddressAndSize(TVirtual va, TVirtual size) + { + if (!ValidateAddressAndSize(va, size)) + { + throw new InvalidMemoryRegionException($"va=0x{va:X16}, size=0x{size:X16}"); + } + } + + protected abstract Span<byte> GetPhysicalAddressSpan(TPhysical pa, int size); + + protected abstract TPhysical TranslateVirtualAddressForRead(TVirtual va); + + /// <summary> + /// Checks if the virtual address is part of the addressable space. + /// </summary> + /// <param name="va">Virtual address</param> + /// <returns>True if the virtual address is part of the addressable space</returns> + protected bool ValidateAddress(TVirtual va) + { + return va < AddressSpaceSize; + } + + /// <summary> + /// Checks if the combination of virtual address and size is part of the addressable space. + /// </summary> + /// <param name="va">Virtual address of the range</param> + /// <param name="size">Size of the range in bytes</param> + /// <returns>True if the combination of virtual address and size is part of the addressable space</returns> + protected bool ValidateAddressAndSize(TVirtual va, TVirtual size) + { + TVirtual endVa = va + size; + return endVa >= va && endVa >= size && endVa <= AddressSpaceSize; + } + + protected static void ThrowInvalidMemoryRegionException(string message) + => throw new InvalidMemoryRegionException(message); + } +} |
