diff --git a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs index decb0e4e3..dd5547274 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs @@ -151,6 +151,11 @@ namespace Ryujinx.Cpu.AppleHv } } + public override bool TryReadUnsafe(ulong va, int length, out Span data) + { + throw new NotImplementedException(); + } + public override void Write(ulong va, ReadOnlySpan data) { try diff --git a/src/Ryujinx.Cpu/Jit/MemoryManager.cs b/src/Ryujinx.Cpu/Jit/MemoryManager.cs index 9e5d29cca..8cc786a83 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManager.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -174,6 +174,11 @@ namespace Ryujinx.Cpu.Jit } } } + + public override bool TryReadUnsafe(ulong va, int length, out Span data) + { + throw new NotImplementedException(); + } public override void Write(ulong va, ReadOnlySpan data) { diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs index e27a2e173..e2d8f5efb 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs @@ -151,6 +151,11 @@ namespace Ryujinx.Cpu.Jit return default; } } + + public override bool TryReadUnsafe(ulong va, int length, out Span data) + { + throw new NotImplementedException(); + } public override T ReadTracked(ulong va) { diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs index 9ae4ca5a9..0ad96c6ae 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs @@ -227,6 +227,11 @@ namespace Ryujinx.Cpu.Jit } } } + + public override bool TryReadUnsafe(ulong va, int length, out Span data) + { + throw new NotImplementedException(); + } public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data) { diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index fea09ef47..99acd06bb 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -123,15 +123,15 @@ namespace Ryujinx.HLE.HOS.Services.Nv return NvResult.InvalidSize; } - byte[] outputData = new byte[outputDataSize]; - - byte[] temp = new byte[inputDataSize]; - - context.Memory.Read(inputDataPosition, temp); - - Buffer.BlockCopy(temp, 0, outputData, 0, temp.Length); - - arguments = new Span(outputData); + if (!context.Memory.TryReadUnsafe(inputDataPosition, (int)inputDataSize, out arguments)) + { + arguments = new byte[inputDataSize]; + context.Memory.Read(inputDataPosition, arguments); + } + else + { + arguments = arguments.ToArray(); + } } else if (isWrite) { @@ -470,12 +470,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv (ulong inlineInBufferPosition, ulong inlineInBufferSize) = context.Request.GetBufferType0x21(1); errorCode = GetIoctlArgument(context, ioctlCommand, out Span arguments); - - byte[] temp = new byte[inlineInBufferSize]; - - context.Memory.Read(inlineInBufferPosition, temp); - - Span inlineInBuffer = new(temp); + + if (!context.Memory.TryReadUnsafe(inlineInBufferPosition, (int)inlineInBufferSize, out Span inlineInBuffer)) + { + inlineInBuffer = new byte[inlineInBufferSize]; + context.Memory.Read(inlineInBufferPosition, inlineInBuffer); + } if (errorCode == NvResult.Success) { diff --git a/src/Ryujinx.Memory/IVirtualMemoryManager.cs b/src/Ryujinx.Memory/IVirtualMemoryManager.cs index 1f8ca37aa..a417ede8c 100644 --- a/src/Ryujinx.Memory/IVirtualMemoryManager.cs +++ b/src/Ryujinx.Memory/IVirtualMemoryManager.cs @@ -60,6 +60,15 @@ namespace Ryujinx.Memory /// Span to store the data being read into /// Throw for unhandled invalid or unmapped memory accesses void Read(ulong va, Span data); + + /// + /// Gets a span of CPU mapped memory. + /// + /// Virtual address of the data in memory + /// Length of the data in memory + /// Span that references the data being read + /// Throw for unhandled invalid or unmapped memory accesses + bool TryReadUnsafe(ulong va, int length, out Span data); /// /// Writes data to CPU mapped memory. diff --git a/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs b/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs index 9c49286b9..cd50b4152 100644 --- a/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs +++ b/src/Ryujinx.Memory/VirtualMemoryManagerBase.cs @@ -159,6 +159,13 @@ namespace Ryujinx.Memory AssertValidAddressAndSize(va, data.Length); + if (IsContiguousAndMapped(va, data.Length)) + { + nuint pa = TranslateVirtualAddressChecked(va); + + GetPhysicalAddressSpan(pa, data.Length).CopyTo(data); + } + int offset = 0, size; if ((va & PageMask) != 0) @@ -182,6 +189,28 @@ namespace Ryujinx.Memory } } + public virtual bool TryReadUnsafe(ulong va, int length, out Span data) + { + if (!IsContiguousAndMapped(va, length)) + { + data = default; + return false; + } + + if (length == 0) + { + data = Span.Empty; + return true; + } + + AssertValidAddressAndSize(va, length); + + nuint pa = TranslateVirtualAddressChecked(va); + + data = GetPhysicalAddressSpan(pa, length); + return true; + } + public virtual T ReadTracked(ulong va) where T : unmanaged { SignalMemoryTracking(va, (ulong)Unsafe.SizeOf(), false); diff --git a/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs b/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs index a01521c8f..9b1a8c995 100644 --- a/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs +++ b/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs @@ -42,6 +42,11 @@ namespace Ryujinx.Tests.Memory { throw new NotImplementedException(); } + + public bool TryReadUnsafe(ulong va, int lenfth, out Span data) + { + throw new NotImplementedException(); + } public void Write(ulong va, T value) where T : unmanaged {