From 1cbca5eecbb6b7bce94dca864b5cffda4db02d39 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Tue, 3 May 2022 08:16:31 -0300
Subject: Implement code memory syscalls (#2958)

* Implement code memory syscalls

* Remove owner process validation

* Add 32-bit code memory syscalls

* Remove unused field
---
 Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs | 146 ++++++++++++++++++++++++
 1 file changed, 146 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 518a0f09..94e8fb6a 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs
@@ -1095,6 +1095,77 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             }
         }
 
+        public KernelResult UnmapProcessMemory(ulong dst, ulong size, KPageTableBase srcPageTable, ulong src)
+        {
+            lock (_blockManager)
+            {
+                lock (srcPageTable._blockManager)
+                {
+                    bool success = CheckRange(
+                        dst,
+                        size,
+                        MemoryState.Mask,
+                        MemoryState.ProcessMemory,
+                        KMemoryPermission.ReadAndWrite,
+                        KMemoryPermission.ReadAndWrite,
+                        MemoryAttribute.Mask,
+                        MemoryAttribute.None,
+                        MemoryAttribute.IpcAndDeviceMapped,
+                        out _,
+                        out _,
+                        out _);
+
+                    success &= srcPageTable.CheckRange(
+                        src,
+                        size,
+                        MemoryState.MapProcessAllowed,
+                        MemoryState.MapProcessAllowed,
+                        KMemoryPermission.None,
+                        KMemoryPermission.None,
+                        MemoryAttribute.Mask,
+                        MemoryAttribute.None,
+                        MemoryAttribute.IpcAndDeviceMapped,
+                        out _,
+                        out _,
+                        out _);
+
+                    if (!success)
+                    {
+                        return KernelResult.InvalidMemState;
+                    }
+
+                    KPageList srcPageList = new KPageList();
+                    KPageList dstPageList = new KPageList();
+
+                    srcPageTable.GetPhysicalRegions(src, size, srcPageList);
+                    GetPhysicalRegions(dst, size, dstPageList);
+
+                    if (!dstPageList.IsEqual(srcPageList))
+                    {
+                        return KernelResult.InvalidMemRange;
+                    }
+                }
+
+                if (!_slabManager.CanAllocate(MaxBlocksNeededForInsertion))
+                {
+                    return KernelResult.OutOfResource;
+                }
+
+                ulong pagesCount = size / PageSize;
+
+                KernelResult result = Unmap(dst, pagesCount);
+
+                if (result != KernelResult.Success)
+                {
+                    return result;
+                }
+
+                _blockManager.InsertBlock(dst, pagesCount, MemoryState.Unmapped);
+
+                return KernelResult.Success;
+            }
+        }
+
         public KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
         {
             lock (_blockManager)
@@ -2023,6 +2094,49 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
             block.RestoreIpcMappingPermission();
         }
 
+        public KernelResult GetPagesIfStateEquals(
+            ulong address,
+            ulong size,
+            MemoryState stateMask,
+            MemoryState stateExpected,
+            KMemoryPermission permissionMask,
+            KMemoryPermission permissionExpected,
+            MemoryAttribute attributeMask,
+            MemoryAttribute attributeExpected,
+            KPageList pageList)
+        {
+            if (!InsideAddrSpace(address, size))
+            {
+                return KernelResult.InvalidMemState;
+            }
+
+            lock (_blockManager)
+            {
+                if (CheckRange(
+                    address,
+                    size,
+                    stateMask | MemoryState.IsPoolAllocated,
+                    stateExpected | MemoryState.IsPoolAllocated,
+                    permissionMask,
+                    permissionExpected,
+                    attributeMask,
+                    attributeExpected,
+                    MemoryAttribute.IpcAndDeviceMapped,
+                    out _,
+                    out _,
+                    out _))
+                {
+                    GetPhysicalRegions(address, size, pageList);
+
+                    return KernelResult.Success;
+                }
+                else
+                {
+                    return KernelResult.InvalidMemState;
+                }
+            }
+        }
+
         public KernelResult BorrowIpcBuffer(ulong address, ulong size)
         {
             return SetAttributesAndChangePermission(
@@ -2054,6 +2168,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 pageList);
         }
 
+        public KernelResult BorrowCodeMemory(KPageList pageList, ulong address, ulong size)
+        {
+            return SetAttributesAndChangePermission(
+                address,
+                size,
+                MemoryState.CodeMemoryAllowed,
+                MemoryState.CodeMemoryAllowed,
+                KMemoryPermission.Mask,
+                KMemoryPermission.ReadAndWrite,
+                MemoryAttribute.Mask,
+                MemoryAttribute.None,
+                KMemoryPermission.None,
+                MemoryAttribute.Borrowed,
+                pageList);
+        }
+
         private KernelResult SetAttributesAndChangePermission(
             ulong address,
             ulong size,
@@ -2159,6 +2289,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
                 pageList);
         }
 
+        public KernelResult UnborrowCodeMemory(ulong address, ulong size, KPageList pageList)
+        {
+            return ClearAttributesAndChangePermission(
+                address,
+                size,
+                MemoryState.CodeMemoryAllowed,
+                MemoryState.CodeMemoryAllowed,
+                KMemoryPermission.None,
+                KMemoryPermission.None,
+                MemoryAttribute.Mask,
+                MemoryAttribute.Borrowed,
+                KMemoryPermission.ReadAndWrite,
+                MemoryAttribute.Borrowed,
+                pageList);
+        }
+
         private KernelResult ClearAttributesAndChangePermission(
             ulong address,
             ulong size,
-- 
cgit v1.2.3-70-g09d2