From c94d47cc408910af8342d47886937dd9feb32f4d Mon Sep 17 00:00:00 2001
From: Mary <me@thog.eu>
Date: Sun, 24 Oct 2021 01:24:49 +0200
Subject: 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
---
 Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs | 46 +++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

(limited to 'Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs')

diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
index e1ab0b93..965e03d9 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
@@ -799,6 +799,52 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             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()
         {
             lock (_blockManager)
-- 
cgit v1.2.3-70-g09d2