diff --git a/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs index 2b6d4e4e95..b065e9c581 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs @@ -675,7 +675,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory KMemoryPermission.None, MemoryAttribute.Mask, MemoryAttribute.None, - MemoryAttribute.IpcAndDeviceMapped, + MemoryAttribute.IpcAndDeviceMapped | MemoryAttribute.PermissionLocked, out MemoryState state, out _, out _); @@ -687,7 +687,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory state, KMemoryPermission.None, KMemoryPermission.None, - MemoryAttribute.Mask, + MemoryAttribute.Mask & ~MemoryAttribute.PermissionLocked, MemoryAttribute.None); if (success) @@ -913,19 +913,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return Result.Success; } - public Result SetMemoryAttribute( - ulong address, - ulong size, - MemoryAttribute attributeMask, - MemoryAttribute attributeValue) + public Result SetMemoryAttribute(ulong address, ulong size, MemoryAttribute attributeMask, MemoryAttribute attributeValue) { lock (_blockManager) { + MemoryState stateCheckMask = 0; + + if (attributeMask.HasFlag(MemoryAttribute.Uncached)) + { + stateCheckMask = MemoryState.AttributeChangeAllowed; + } + + if (attributeMask.HasFlag(MemoryAttribute.PermissionLocked)) + { + stateCheckMask |= MemoryState.PermissionLockAllowed; + } + if (CheckRange( address, size, - MemoryState.AttributeChangeAllowed, - MemoryState.AttributeChangeAllowed, + stateCheckMask, + stateCheckMask, KMemoryPermission.None, KMemoryPermission.None, MemoryAttribute.BorrowedAndIpcMapped, diff --git a/src/Ryujinx.HLE/HOS/Kernel/Memory/MemoryAttribute.cs b/src/Ryujinx.HLE/HOS/Kernel/Memory/MemoryAttribute.cs index 36b1ec8c3a..e0fa60fab8 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Memory/MemoryAttribute.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Memory/MemoryAttribute.cs @@ -12,11 +12,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory IpcMapped = 1 << 1, DeviceMapped = 1 << 2, Uncached = 1 << 3, + PermissionLocked = 1 << 4, IpcAndDeviceMapped = IpcMapped | DeviceMapped, - BorrowedAndIpcMapped = Borrowed | IpcMapped, - DeviceMappedAndUncached = DeviceMapped | Uncached, } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Memory/MemoryState.cs b/src/Ryujinx.HLE/HOS/Kernel/Memory/MemoryState.cs index 273b58e5ec..da6fac6393 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Memory/MemoryState.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Memory/MemoryState.cs @@ -5,35 +5,155 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory [Flags] enum MemoryState : uint { - Unmapped = 0x00000000, - Io = 0x00002001, - Normal = 0x00042002, - CodeStatic = 0x00DC7E03, - CodeMutable = 0x03FEBD04, - Heap = 0x037EBD05, - SharedMemory = 0x00402006, - ModCodeStatic = 0x00DD7E08, - ModCodeMutable = 0x03FFBD09, - IpcBuffer0 = 0x005C3C0A, - Stack = 0x005C3C0B, - ThreadLocal = 0x0040200C, - TransferMemoryIsolated = 0x015C3C0D, - TransferMemory = 0x005C380E, - ProcessMemory = 0x0040380F, - Reserved = 0x00000010, - IpcBuffer1 = 0x005C3811, - IpcBuffer3 = 0x004C2812, - KernelStack = 0x00002013, - CodeReadOnly = 0x00402214, - CodeWritable = 0x00402015, - UserMask = 0xff, - Mask = 0xffffffff, + Unmapped = 0x0, + Io = Mapped | 0x1, + Normal = Mapped | QueryPhysicalAddressAllowed | 0x2, + CodeStatic = ForceReadWritableByDebugSyscalls | + IpcSendAllowedType0 | + IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + ProcessPermissionChangeAllowed | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IsPoolAllocated | + MapProcessAllowed | + LinearMapped | + 0x3, + CodeMutable = PermissionChangeAllowed | + IpcSendAllowedType0 | + IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + MapAllowed | + TransferMemoryAllowed | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IpcBufferAllowed | + IsPoolAllocated | + MapProcessAllowed | + AttributeChangeAllowed | + CodeMemoryAllowed | + LinearMapped | + PermissionLockAllowed | + 0x4, + Heap = PermissionChangeAllowed | + IpcSendAllowedType0 | + IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + MapAllowed | + TransferMemoryAllowed | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IpcBufferAllowed | + IsPoolAllocated | + AttributeChangeAllowed | + CodeMemoryAllowed | + LinearMapped | + 0x5, + SharedMemory = Mapped | IsPoolAllocated | LinearMapped | 0x6, + ModCodeStatic = ForceReadWritableByDebugSyscalls | + IpcSendAllowedType0 | + IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + ProcessPermissionChangeAllowed | + UnmapProcessCodeMemoryAllowed | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IsPoolAllocated | + MapProcessAllowed | + LinearMapped | + 0x8, + ModCodeMutable = PermissionChangeAllowed | + IpcSendAllowedType0 | + IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + MapAllowed | + UnmapProcessCodeMemoryAllowed | + TransferMemoryAllowed | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IpcBufferAllowed | + IsPoolAllocated | + MapProcessAllowed | + AttributeChangeAllowed | + CodeMemoryAllowed | + LinearMapped | + PermissionLockAllowed | + 0x9, + IpcBuffer0 = IpcSendAllowedType0 | + IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IsPoolAllocated | + LinearMapped | + 0xA, + Stack = IpcSendAllowedType0 | + IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IsPoolAllocated | + LinearMapped | + 0xB, + ThreadLocal = Mapped | IsPoolAllocated | LinearMapped | 0xC, + TransferMemoryIsolated = IpcSendAllowedType0 | + IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IsPoolAllocated | + AttributeChangeAllowed | + LinearMapped | + 0xD, + TransferMemory = IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IsPoolAllocated | + LinearMapped | + 0xE, + ProcessMemory = IpcSendAllowedType3 | IpcSendAllowedType1 | Mapped | IsPoolAllocated | LinearMapped | 0xF, + Reserved = 0x10, + IpcBuffer1 = IpcSendAllowedType3 | + IpcSendAllowedType1 | + Mapped | + QueryPhysicalAddressAllowed | + MapDeviceAllowed | + MapDeviceAlignedAllowed | + IsPoolAllocated | + LinearMapped | + 0x11, + IpcBuffer3 = IpcSendAllowedType3 | Mapped | QueryPhysicalAddressAllowed | MapDeviceAllowed | IsPoolAllocated | LinearMapped | 0x12, + KernelStack = Mapped | 0x13, + CodeReadOnly = ForceReadWritableByDebugSyscalls | Mapped | IsPoolAllocated | LinearMapped | 0x14, + CodeWritable = Mapped | IsPoolAllocated | LinearMapped | 0x15, + UserMask = 0xFF, + Mask = 0xFFFFFFFF, PermissionChangeAllowed = 1 << 8, ForceReadWritableByDebugSyscalls = 1 << 9, IpcSendAllowedType0 = 1 << 10, IpcSendAllowedType3 = 1 << 11, IpcSendAllowedType1 = 1 << 12, + Mapped = 1 << 13, ProcessPermissionChangeAllowed = 1 << 14, MapAllowed = 1 << 15, UnmapProcessCodeMemoryAllowed = 1 << 16, @@ -46,5 +166,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory MapProcessAllowed = 1 << 23, AttributeChangeAllowed = 1 << 24, CodeMemoryAllowed = 1 << 25, + LinearMapped = 1 << 26, + PermissionLockAllowed = 1 << 27, } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index e4f48da1b1..b07f5194e1 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -949,8 +949,16 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall MemoryAttribute attributes = attributeMask | attributeValue; + const MemoryAttribute SupportedAttributes = MemoryAttribute.Uncached | MemoryAttribute.PermissionLocked; + if (attributes != attributeMask || - (attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached) + (attributes | SupportedAttributes) != SupportedAttributes) + { + return KernelResult.InvalidCombination; + } + + // The permission locked attribute can't be unset. + if ((attributeMask & MemoryAttribute.PermissionLocked) != (attributeValue & MemoryAttribute.PermissionLocked)) { return KernelResult.InvalidCombination; }