Selaa lähdekoodia

kernel: Implement SetMemoryPermission syscall (#2772)

* kernel: Implement SetMemoryPermission syscall

This commit implement the SetMemoryPermission syscall accurately.
This also fix KMemoryPermission not being an unsigned 32 bits type and
add the "DontCare" bit (used by shared memory, currently unused in
Ryujinx)

* Update MemoryPermission mask

* Address gdkchan's comments

* Fix a nit

* Address gdkchan's comment
Mary 4 vuotta sitten
vanhempi
sitoutus
c94d47cc40

+ 46 - 0
Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs

@@ -799,6 +799,52 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             return KernelResult.Success;
             return KernelResult.Success;
         }
         }
 
 
+        public KernelResult SetMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
+        {
+            lock (_blockManager)
+            {
+                if (CheckRange(
+                    address,
+                    size,
+                    MemoryState.PermissionChangeAllowed,
+                    MemoryState.PermissionChangeAllowed,
+                    KMemoryPermission.None,
+                    KMemoryPermission.None,
+                    MemoryAttribute.Mask,
+                    MemoryAttribute.None,
+                    MemoryAttribute.IpcAndDeviceMapped,
+                    out MemoryState oldState,
+                    out KMemoryPermission oldPermission,
+                    out _))
+                {
+                    if (permission != oldPermission)
+                    {
+                        if (!_slabManager.CanAllocate(MaxBlocksNeededForInsertion))
+                        {
+                            return KernelResult.OutOfResource;
+                        }
+
+                        ulong pagesCount = size / PageSize;
+
+                        KernelResult result = Reprotect(address, pagesCount, permission);
+
+                        if (result != KernelResult.Success)
+                        {
+                            return result;
+                        }
+
+                        _blockManager.InsertBlock(address, pagesCount, oldState, permission);
+                    }
+
+                    return KernelResult.Success;
+                }
+                else
+                {
+                    return KernelResult.InvalidMemState;
+                }
+            }
+        }
+
         public ulong GetTotalHeapSize()
         public ulong GetTotalHeapSize()
         {
         {
             lock (_blockManager)
             lock (_blockManager)

+ 6 - 5
Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs

@@ -3,14 +3,15 @@ using System;
 namespace Ryujinx.HLE.HOS.Kernel.Memory
 namespace Ryujinx.HLE.HOS.Kernel.Memory
 {
 {
     [Flags]
     [Flags]
-    enum KMemoryPermission : byte
+    enum KMemoryPermission : uint
     {
     {
         None = 0,
         None = 0,
-        Mask = 0xff,
+        Mask = uint.MaxValue,
 
 
-        Read    = 1 << 0,
-        Write   = 1 << 1,
-        Execute = 1 << 2,
+        Read     = 1 << 0,
+        Write    = 1 << 1,
+        Execute  = 1 << 2,
+        DontCare = 1 << 28,
 
 
         ReadAndWrite   = Read | Write,
         ReadAndWrite   = Read | Write,
         ReadAndExecute = Read | Execute
         ReadAndExecute = Read | Execute

+ 32 - 0
Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs

@@ -819,6 +819,38 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             return process.MemoryManager.SetHeapSize(size, out position);
             return process.MemoryManager.SetHeapSize(size, out position);
         }
         }
 
 
+        public KernelResult SetMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
+        {
+            if (!PageAligned(address))
+            {
+                return KernelResult.InvalidAddress;
+            }
+
+            if (!PageAligned(size) || size == 0)
+            {
+                return KernelResult.InvalidSize;
+            }
+
+            if (address + size <= address)
+            {
+                return KernelResult.InvalidMemState;
+            }
+
+            if (permission == KMemoryPermission.None || (permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
+            {
+                return KernelResult.InvalidPermission;
+            }
+
+            KProcess currentProcess = KernelStatic.GetCurrentProcess();
+
+            if (!currentProcess.MemoryManager.InsideAddrSpace(address, size))
+            {
+                return KernelResult.InvalidMemState;
+            }
+
+            return currentProcess.MemoryManager.SetMemoryPermission(address, size, permission);
+        }
+
         public KernelResult SetMemoryAttribute(
         public KernelResult SetMemoryAttribute(
             ulong position,
             ulong position,
             ulong size,
             ulong size,

+ 8 - 0
Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs

@@ -88,6 +88,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             return result;
             return result;
         }
         }
 
 
+        public KernelResult SetMemoryPermission32(
+            [R(0)] ulong position,
+            [R(1)] ulong size,
+            [R(2)] KMemoryPermission permission)
+        {
+            return _syscall.SetMemoryPermission(position, size, permission);
+        }
+
         public KernelResult SetMemoryAttribute32(
         public KernelResult SetMemoryAttribute32(
             [R(0)] uint position,
             [R(0)] uint position,
             [R(1)] uint size,
             [R(1)] uint size,

+ 8 - 0
Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs

@@ -109,6 +109,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             return _syscall.SetHeapSize(size, out position);
             return _syscall.SetHeapSize(size, out position);
         }
         }
 
 
+        public KernelResult SetMemoryPermission64(
+            [R(0)] ulong position,
+            [R(1)] ulong size,
+            [R(2)] KMemoryPermission permission)
+        {
+            return _syscall.SetMemoryPermission(position, size, permission);
+        }
+
         public KernelResult SetMemoryAttribute64(
         public KernelResult SetMemoryAttribute64(
             [R(0)] ulong position,
             [R(0)] ulong position,
             [R(1)] ulong size,
             [R(1)] ulong size,

+ 2 - 0
Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs

@@ -25,6 +25,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
             Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
             {
             {
                 { 0x01, nameof(Syscall64.SetHeapSize64)                    },
                 { 0x01, nameof(Syscall64.SetHeapSize64)                    },
+                { 0x02, nameof(Syscall64.SetMemoryPermission64)            },
                 { 0x03, nameof(Syscall64.SetMemoryAttribute64)             },
                 { 0x03, nameof(Syscall64.SetMemoryAttribute64)             },
                 { 0x04, nameof(Syscall64.MapMemory64)                      },
                 { 0x04, nameof(Syscall64.MapMemory64)                      },
                 { 0x05, nameof(Syscall64.UnmapMemory64)                    },
                 { 0x05, nameof(Syscall64.UnmapMemory64)                    },
@@ -94,6 +95,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             Dictionary<int, string> svcFuncs32 = new Dictionary<int, string>
             Dictionary<int, string> svcFuncs32 = new Dictionary<int, string>
             {
             {
                 { 0x01, nameof(Syscall32.SetHeapSize32)                   },
                 { 0x01, nameof(Syscall32.SetHeapSize32)                   },
+                { 0x02, nameof(Syscall32.SetMemoryPermission32)           },
                 { 0x03, nameof(Syscall32.SetMemoryAttribute32)            },
                 { 0x03, nameof(Syscall32.SetMemoryAttribute32)            },
                 { 0x04, nameof(Syscall32.MapMemory32)                     },
                 { 0x04, nameof(Syscall32.MapMemory32)                     },
                 { 0x05, nameof(Syscall32.UnmapMemory32)                   },
                 { 0x05, nameof(Syscall32.UnmapMemory32)                   },