aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary <me@thog.eu>2021-10-24 01:24:49 +0200
committerGitHub <noreply@github.com>2021-10-24 01:24:49 +0200
commitc94d47cc408910af8342d47886937dd9feb32f4d (patch)
tree8d78e8d0a8370be6c1f88ffe9d1694de73dc27d5
parente7e65ccbc9caed8b7211399a1040fcd4a7ef77da (diff)
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
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs46
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs11
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs32
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs8
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs8
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs2
6 files changed, 102 insertions, 5 deletions
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)
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs b/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
index 8bfd8d94..12300e4f 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
@@ -3,14 +3,15 @@ using System;
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
[Flags]
- enum KMemoryPermission : byte
+ enum KMemoryPermission : uint
{
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,
ReadAndExecute = Read | Execute
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
index 4718d412..237c1a54 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
@@ -819,6 +819,38 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
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(
ulong position,
ulong size,
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
index 1875facb..d9a14502 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
@@ -88,6 +88,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
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(
[R(0)] uint position,
[R(1)] uint size,
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
index c22397cf..00dbb1e4 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
@@ -109,6 +109,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
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(
[R(0)] ulong position,
[R(1)] ulong size,
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs
index 790a3179..bf263d7b 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs
+++ b/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>
{
{ 0x01, nameof(Syscall64.SetHeapSize64) },
+ { 0x02, nameof(Syscall64.SetMemoryPermission64) },
{ 0x03, nameof(Syscall64.SetMemoryAttribute64) },
{ 0x04, nameof(Syscall64.MapMemory64) },
{ 0x05, nameof(Syscall64.UnmapMemory64) },
@@ -94,6 +95,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
Dictionary<int, string> svcFuncs32 = new Dictionary<int, string>
{
{ 0x01, nameof(Syscall32.SetHeapSize32) },
+ { 0x02, nameof(Syscall32.SetMemoryPermission32) },
{ 0x03, nameof(Syscall32.SetMemoryAttribute32) },
{ 0x04, nameof(Syscall32.MapMemory32) },
{ 0x05, nameof(Syscall32.UnmapMemory32) },