From dc837c00428b6f67079e362631fe7fc503ceeacb Mon Sep 17 00:00:00 2001 From: Mary Date: Sun, 24 Oct 2021 01:40:13 +0200 Subject: [PATCH] kernel: Add resource limit related syscalls (#2773) * kernel: Add resource limit related syscalls This commit implements all resource limit related syscalls. * Fix register mapping being wrong for SetResourceLimitLimitValue * Address gdkchan's comment --- .../HOS/Kernel/Common/KResourceLimit.cs | 38 ++++++++ .../HOS/Kernel/SupervisorCall/Syscall.cs | 89 +++++++++++++++++++ .../HOS/Kernel/SupervisorCall/Syscall32.cs | 42 +++++++++ .../HOS/Kernel/SupervisorCall/Syscall64.cs | 25 ++++++ .../HOS/Kernel/SupervisorCall/SyscallTable.cs | 14 ++- 5 files changed, 206 insertions(+), 2 deletions(-) diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs b/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs index 64b964da44..7caff21a0d 100644 --- a/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs +++ b/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs @@ -11,6 +11,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common private readonly long[] _current; private readonly long[] _limit; private readonly long[] _current2; + private readonly long[] _peak; private readonly object _lock; @@ -23,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common _current = new long[(int)LimitableResource.Count]; _limit = new long[(int)LimitableResource.Count]; _current2 = new long[(int)LimitableResource.Count]; + _peak = new long[(int)LimitableResource.Count]; _lock = new object(); @@ -79,6 +81,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Common _current[index] = newCurrent; _current2[index] += amount; + if (_current[index] > _peak[index]) + { + _peak[index] = _current[index]; + } + success = true; } } @@ -122,6 +129,36 @@ namespace Ryujinx.HLE.HOS.Kernel.Common } } + public long GetCurrentValue(LimitableResource resource) + { + int index = GetIndex(resource); + + lock (_lock) + { + return _current[index]; + } + } + + public long GetLimitValue(LimitableResource resource) + { + int index = GetIndex(resource); + + lock (_lock) + { + return _limit[index]; + } + } + + public long GetPeakValue(LimitableResource resource) + { + int index = GetIndex(resource); + + lock (_lock) + { + return _peak[index]; + } + } + public KernelResult SetLimitValue(LimitableResource resource, long limit) { int index = GetIndex(resource); @@ -131,6 +168,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common if (_current[index] <= limit) { _limit[index] = limit; + _peak[index] = _current[index]; return KernelResult.Success; } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index 237c1a544d..a1e84935ae 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -1918,6 +1918,95 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + public KernelResult GetResourceLimitLimitValue(int handle, LimitableResource resource, out long limitValue) + { + limitValue = 0; + + if (resource >= LimitableResource.Count) + { + return KernelResult.InvalidEnumValue; + } + + KResourceLimit resourceLimit = KernelStatic.GetCurrentProcess().HandleTable.GetObject(handle); + + if (resourceLimit == null) + { + return KernelResult.InvalidHandle; + } + + limitValue = resourceLimit.GetLimitValue(resource); + + return KernelResult.Success; + } + + public KernelResult GetResourceLimitCurrentValue(int handle, LimitableResource resource, out long limitValue) + { + limitValue = 0; + + if (resource >= LimitableResource.Count) + { + return KernelResult.InvalidEnumValue; + } + + KResourceLimit resourceLimit = KernelStatic.GetCurrentProcess().HandleTable.GetObject(handle); + + if (resourceLimit == null) + { + return KernelResult.InvalidHandle; + } + + limitValue = resourceLimit.GetCurrentValue(resource); + + return KernelResult.Success; + } + + public KernelResult GetResourceLimitPeakValue(int handle, LimitableResource resource, out long peak) + { + peak = 0; + + if (resource >= LimitableResource.Count) + { + return KernelResult.InvalidEnumValue; + } + + KResourceLimit resourceLimit = KernelStatic.GetCurrentProcess().HandleTable.GetObject(handle); + + if (resourceLimit == null) + { + return KernelResult.InvalidHandle; + } + + peak = resourceLimit.GetPeakValue(resource); + + return KernelResult.Success; + } + + public KernelResult CreateResourceLimit(out int handle) + { + KResourceLimit limit = new KResourceLimit(_context); + + KProcess process = KernelStatic.GetCurrentProcess(); + + return process.HandleTable.GenerateHandle(limit, out handle); + } + + public KernelResult SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue) + { + if (resource >= LimitableResource.Count) + { + return KernelResult.InvalidEnumValue; + } + + KResourceLimit resourceLimit = KernelStatic.GetCurrentProcess().HandleTable.GetObject(handle); + + if (resourceLimit == null) + { + return KernelResult.InvalidHandle; + } + + return resourceLimit.SetLimitValue(resource, limitValue); + } + // Thread public KernelResult CreateThread( diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs index d9a14502f5..bfecad203b 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs @@ -295,6 +295,48 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + public KernelResult GetResourceLimitLimitValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int limitValueLow, [R(2)] out int limitValueHigh) + { + KernelResult result = _syscall.GetResourceLimitLimitValue(handle, resource, out long limitValue); + + limitValueHigh = (int)(limitValue >> 32); + limitValueLow = (int)(limitValue & uint.MaxValue); + + return result; + } + + public KernelResult GetResourceLimitCurrentValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int limitValueLow, [R(2)] out int limitValueHigh) + { + KernelResult result = _syscall.GetResourceLimitCurrentValue(handle, resource, out long limitValue); + + limitValueHigh = (int)(limitValue >> 32); + limitValueLow = (int)(limitValue & uint.MaxValue); + + return result; + } + + public KernelResult GetResourceLimitPeakValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int peakLow, [R(2)] out int peakHigh) + { + KernelResult result = _syscall.GetResourceLimitPeakValue(handle, resource, out long peak); + + peakHigh = (int)(peak >> 32); + peakLow = (int)(peak & uint.MaxValue); + + return result; + } + + public KernelResult CreateResourceLimit32([R(1)] out int handle) + { + return _syscall.CreateResourceLimit(out handle); + } + + public KernelResult SetResourceLimitLimitValue32([R(0)] int handle, [R(1)] LimitableResource resource, [R(2)] uint limitValueLow, [R(3)] uint limitValueHigh) + { + long limitValue = (long)(limitValueLow | ((ulong)limitValueHigh << 32)); + + return _syscall.SetResourceLimitLimitValue(handle, resource, limitValue); + } + public KernelResult FlushProcessDataCache32( [R(0)] uint processHandle, [R(2)] uint addressLow, diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs index 00dbb1e4f6..0ed11a8114 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs @@ -267,6 +267,31 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _syscall.GetSystemInfo(id, handle, subId, out value); } + public KernelResult GetResourceLimitLimitValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long limitValue) + { + return _syscall.GetResourceLimitLimitValue(handle, resource, out limitValue); + } + + public KernelResult GetResourceLimitCurrentValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long limitValue) + { + return _syscall.GetResourceLimitCurrentValue(handle, resource, out limitValue); + } + + public KernelResult GetResourceLimitPeakValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long peak) + { + return _syscall.GetResourceLimitPeakValue(handle, resource, out peak); + } + + public KernelResult CreateResourceLimit64([R(1)] out int handle) + { + return _syscall.CreateResourceLimit(out handle); + } + + public KernelResult SetResourceLimitLimitValue64([R(0)] int handle, [R(1)] LimitableResource resource, [R(2)] long limitValue) + { + return _syscall.SetResourceLimitLimitValue(handle, resource, limitValue); + } + // Thread public KernelResult CreateThread64( diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs index bf263d7b86..bbd77c36ec 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs @@ -65,10 +65,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { 0x29, nameof(Syscall64.GetInfo64) }, { 0x2c, nameof(Syscall64.MapPhysicalMemory64) }, { 0x2d, nameof(Syscall64.UnmapPhysicalMemory64) }, + { 0x30, nameof(Syscall64.GetResourceLimitLimitValue64) }, + { 0x31, nameof(Syscall64.GetResourceLimitCurrentValue64) }, { 0x32, nameof(Syscall64.SetThreadActivity64) }, { 0x33, nameof(Syscall64.GetThreadContext364) }, { 0x34, nameof(Syscall64.WaitForAddress64) }, { 0x35, nameof(Syscall64.SignalToAddress64) }, + { 0x37, nameof(Syscall64.GetResourceLimitPeakValue64) }, { 0x40, nameof(Syscall64.CreateSession64) }, { 0x41, nameof(Syscall64.AcceptSession64) }, { 0x43, nameof(Syscall64.ReplyAndReceive64) }, @@ -84,7 +87,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { 0x73, nameof(Syscall64.SetProcessMemoryPermission64) }, { 0x77, nameof(Syscall64.MapProcessCodeMemory64) }, { 0x78, nameof(Syscall64.UnmapProcessCodeMemory64) }, - { 0x7B, nameof(Syscall64.TerminateProcess64) } + { 0x7B, nameof(Syscall64.TerminateProcess64) }, + { 0x7D, nameof(Syscall64.CreateResourceLimit64) }, + { 0x7E, nameof(Syscall64.SetResourceLimitLimitValue64) } }; foreach (KeyValuePair value in svcFuncs64) @@ -134,10 +139,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { 0x29, nameof(Syscall32.GetInfo32) }, { 0x2c, nameof(Syscall32.MapPhysicalMemory32) }, { 0x2d, nameof(Syscall32.UnmapPhysicalMemory32) }, + { 0x30, nameof(Syscall32.GetResourceLimitLimitValue32) }, + { 0x31, nameof(Syscall32.GetResourceLimitCurrentValue32) }, { 0x32, nameof(Syscall32.SetThreadActivity32) }, { 0x33, nameof(Syscall32.GetThreadContext332) }, { 0x34, nameof(Syscall32.WaitForAddress32) }, { 0x35, nameof(Syscall32.SignalToAddress32) }, + { 0x37, nameof(Syscall32.GetResourceLimitPeakValue32) }, { 0x40, nameof(Syscall32.CreateSession32) }, { 0x41, nameof(Syscall32.AcceptSession32) }, { 0x43, nameof(Syscall32.ReplyAndReceive32) }, @@ -153,7 +161,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { 0x73, nameof(Syscall32.SetProcessMemoryPermission32) }, { 0x77, nameof(Syscall32.MapProcessCodeMemory32) }, { 0x78, nameof(Syscall32.UnmapProcessCodeMemory32) }, - { 0x7B, nameof(Syscall32.TerminateProcess32) } + { 0x7B, nameof(Syscall32.TerminateProcess32) }, + { 0x7D, nameof(Syscall32.CreateResourceLimit32) }, + { 0x7E, nameof(Syscall32.SetResourceLimitLimitValue32) } }; foreach (KeyValuePair value in svcFuncs32)