diff --git a/Ryujinx.Cpu/MemoryManagerHostMapped.cs b/Ryujinx.Cpu/MemoryManagerHostMapped.cs index 8bd3092e2..91fcec327 100644 --- a/Ryujinx.Cpu/MemoryManagerHostMapped.cs +++ b/Ryujinx.Cpu/MemoryManagerHostMapped.cs @@ -324,16 +324,16 @@ namespace Ryujinx.Cpu /// public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false) { - if (tracked) - { - SignalMemoryTracking(va, (ulong)size, true); - } - if (size == 0) { return new WritableRegion(null, va, Memory.Empty); } + if (tracked) + { + SignalMemoryTracking(va, (ulong)size, true); + } + if (IsContiguousAndMapped(va, size)) { return new WritableRegion(null, va, _backingMemory.GetMemory(GetPhysicalAddressInternal(va), size)); @@ -342,7 +342,7 @@ namespace Ryujinx.Cpu { Memory memory = new byte[size]; - GetSpan(va, size).CopyTo(memory.Span); + ReadImpl(va, memory.Span); return new WritableRegion(this, va, memory); } @@ -849,17 +849,6 @@ namespace Ryujinx.Cpu } } - private ulong GetPhysicalAddress(ulong va) - { - // We return -1L if the virtual address is invalid or unmapped. - if (!ValidateAddress(va) || !IsMapped(va)) - { - return ulong.MaxValue; - } - - return GetPhysicalAddressInternal(va); - } - private ulong GetPhysicalAddressInternal(ulong va) { return _pageTable.Read(va) + (va & PageMask); @@ -874,6 +863,6 @@ namespace Ryujinx.Cpu _memoryEh.Dispose(); } - private void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message); + private static void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message); } } diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs index 8ceed5ea6..bb79c5bf4 100644 --- a/Ryujinx.HLE/HOS/ApplicationLoader.cs +++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs @@ -17,6 +17,7 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.Loaders.Executables; +using Ryujinx.Memory; using System; using System.Collections.Generic; using System.Globalization; @@ -555,7 +556,14 @@ namespace Ryujinx.HLE.HOS Graphics.Gpu.GraphicsConfig.TitleId = TitleIdText; _device.Gpu.HostInitalized.Set(); - Ptc.Initialize(TitleIdText, DisplayVersion, usePtc, _device.Configuration.MemoryManagerMode); + MemoryManagerMode memoryManagerMode = _device.Configuration.MemoryManagerMode; + + if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible)) + { + memoryManagerMode = MemoryManagerMode.SoftwarePageTable; + } + + Ptc.Initialize(TitleIdText, DisplayVersion, usePtc, memoryManagerMode); metaData.GetNpdm(out Npdm npdm).ThrowIfFailure(); ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, new ProgramInfo(in npdm), executables: programs); diff --git a/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs index a951b3a82..2cd905a75 100644 --- a/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs +++ b/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs @@ -21,6 +21,11 @@ namespace Ryujinx.HLE.HOS { MemoryManagerMode mode = context.Device.Configuration.MemoryManagerMode; + if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible)) + { + mode = MemoryManagerMode.SoftwarePageTable; + } + switch (mode) { case MemoryManagerMode.SoftwarePageTable: diff --git a/Ryujinx.Memory/MemoryBlock.cs b/Ryujinx.Memory/MemoryBlock.cs index fdc84068d..63719c8c7 100644 --- a/Ryujinx.Memory/MemoryBlock.cs +++ b/Ryujinx.Memory/MemoryBlock.cs @@ -11,6 +11,7 @@ namespace Ryujinx.Memory { private readonly bool _usesSharedMemory; private readonly bool _isMirror; + private readonly bool _viewCompatible; private IntPtr _sharedMemory; private IntPtr _pointer; @@ -41,7 +42,8 @@ namespace Ryujinx.Memory } else if (flags.HasFlag(MemoryAllocationFlags.Reserve)) { - _pointer = MemoryManagement.Reserve(size, flags.HasFlag(MemoryAllocationFlags.ViewCompatible)); + _viewCompatible = flags.HasFlag(MemoryAllocationFlags.ViewCompatible); + _pointer = MemoryManagement.Reserve(size, _viewCompatible); } else { @@ -154,7 +156,7 @@ namespace Ryujinx.Memory /// Throw when is invalid public void Reprotect(ulong offset, ulong size, MemoryPermission permission, bool throwOnFail = true) { - MemoryManagement.Reprotect(GetPointerInternal(offset, size), size, permission, throwOnFail); + MemoryManagement.Reprotect(GetPointerInternal(offset, size), size, permission, _viewCompatible, throwOnFail); } /// @@ -412,7 +414,27 @@ namespace Ryujinx.Memory } } - private void ThrowObjectDisposed() => throw new ObjectDisposedException(nameof(MemoryBlock)); - private void ThrowInvalidMemoryRegionException() => throw new InvalidMemoryRegionException(); + /// + /// Checks if the specified memory allocation flags are supported on the current platform. + /// + /// Flags to be checked + /// True if the platform supports all the flags, false otherwise + public static bool SupportsFlags(MemoryAllocationFlags flags) + { + if (flags.HasFlag(MemoryAllocationFlags.ViewCompatible)) + { + if (OperatingSystem.IsWindows()) + { + return OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134); + } + + return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS(); + } + + return true; + } + + private static void ThrowObjectDisposed() => throw new ObjectDisposedException(nameof(MemoryBlock)); + private static void ThrowInvalidMemoryRegionException() => throw new InvalidMemoryRegionException(); } } diff --git a/Ryujinx.Memory/MemoryManagement.cs b/Ryujinx.Memory/MemoryManagement.cs index a325532f2..fa21f9d31 100644 --- a/Ryujinx.Memory/MemoryManagement.cs +++ b/Ryujinx.Memory/MemoryManagement.cs @@ -108,7 +108,7 @@ namespace Ryujinx.Memory } } - public static void Reprotect(IntPtr address, ulong size, MemoryPermission permission, bool throwOnFail) + public static void Reprotect(IntPtr address, ulong size, MemoryPermission permission, bool forView, bool throwOnFail) { bool result; @@ -116,7 +116,7 @@ namespace Ryujinx.Memory { IntPtr sizeNint = new IntPtr((long)size); - result = MemoryManagementWindows.Reprotect(address, sizeNint, permission); + result = MemoryManagementWindows.Reprotect(address, sizeNint, permission, forView); } else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) diff --git a/Ryujinx.Memory/MemoryManagementWindows.cs b/Ryujinx.Memory/MemoryManagementWindows.cs index d0700518e..32effbc8e 100644 --- a/Ryujinx.Memory/MemoryManagementWindows.cs +++ b/Ryujinx.Memory/MemoryManagementWindows.cs @@ -1,6 +1,5 @@ using Ryujinx.Memory.WindowsShared; using System; -using System.Collections.Generic; using System.Runtime.InteropServices; using System.Runtime.Versioning; @@ -13,11 +12,6 @@ namespace Ryujinx.Memory private static readonly IntPtr InvalidHandleValue = new IntPtr(-1); private static readonly IntPtr CurrentProcessHandle = new IntPtr(-1); - private static bool UseWin10Placeholders; - - private static object _emulatedHandleLock = new object(); - private static EmulatedSharedMemoryWindows[] _emulatedShared = new EmulatedSharedMemoryWindows[64]; - private static List _emulatedSharedList = new List(); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr VirtualAlloc( @@ -87,11 +81,6 @@ namespace Ryujinx.Memory [DllImport("kernel32.dll")] private static extern uint GetLastError(); - static MemoryManagementWindows() - { - UseWin10Placeholders = OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134); - } - public static IntPtr Allocate(IntPtr size) { return AllocateInternal(size, AllocationType.Reserve | AllocationType.Commit); @@ -186,24 +175,21 @@ namespace Ryujinx.Memory } } - public static bool Reprotect(IntPtr address, IntPtr size, MemoryPermission permission) + public static bool Reprotect(IntPtr address, IntPtr size, MemoryPermission permission, bool forView) { - if (UseWin10Placeholders) + if (forView) { ulong uaddress = (ulong)address; ulong usize = (ulong)size; while (usize > 0) { - ulong nextGranular = (uaddress & ~EmulatedSharedMemoryWindows.MappingMask) + EmulatedSharedMemoryWindows.MappingGranularity; - ulong mapSize = Math.Min(usize, nextGranular - uaddress); - - if (!VirtualProtect((IntPtr)uaddress, (IntPtr)mapSize, GetProtection(permission), out _)) + if (!VirtualProtect((IntPtr)uaddress, (IntPtr)PageSize, GetProtection(permission), out _)) { return false; } - uaddress = nextGranular; - usize -= mapSize; + uaddress += PageSize; + usize -= PageSize; } return true; @@ -233,27 +219,6 @@ namespace Ryujinx.Memory return VirtualFree(address, IntPtr.Zero, AllocationType.Release); } - private static int GetEmulatedHandle() - { - // Assumes we have the handle lock. - - for (int i = 0; i < _emulatedShared.Length; i++) - { - if (_emulatedShared[i] == null) - { - return i + 1; - } - } - - throw new InvalidProgramException("Too many shared memory handles were created."); - } - - public static bool EmulatedHandleValid(ref int handle) - { - handle--; - return handle >= 0 && handle < _emulatedShared.Length && _emulatedShared[handle] != null; - } - public static IntPtr CreateSharedMemory(IntPtr size, bool reserve) { var prot = reserve ? FileMapProtection.SectionReserve : FileMapProtection.SectionCommit;