aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/SupervisorCall
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-07-17 01:22:13 -0300
committerGitHub <noreply@github.com>2020-07-17 14:22:13 +1000
commit20774dab14ca8362e716ce87f975be7ea77beead (patch)
treec2d3c7b6abd154648d414d1e01ebf1684efc054c /Ryujinx.HLE/HOS/Kernel/SupervisorCall
parent88619d71b8e4840218c68b712aa184098d2dbccf (diff)
Improve kernel WaitSynchronization syscall implementation (#1362)
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/SupervisorCall')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs75
1 files changed, 65 insertions, 10 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
index fba22fc1..b6d2caf2 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
@@ -8,6 +8,7 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using System;
using System.Collections.Generic;
using System.Threading;
@@ -2139,30 +2140,84 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
handleIndex = 0;
- if ((uint)handlesCount > 0x40)
+ if ((uint)handlesCount > KThread.MaxWaitSyncObjects)
{
return KernelResult.MaximumExceeded;
}
- List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
+ KThread currentThread = _context.Scheduler.GetCurrentThread();
- KProcess process = _context.Scheduler.GetCurrentProcess();
+ var syncObjs = new Span<KSynchronizationObject>(currentThread.WaitSyncObjects).Slice(0, handlesCount);
- for (int index = 0; index < handlesCount; index++)
+ if (handlesCount != 0)
{
- int handle = process.CpuMemory.Read<int>(handlesPtr + (ulong)index * 4);
+ KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
- KSynchronizationObject syncObj = process.HandleTable.GetObject<KSynchronizationObject>(handle);
+ if (currentProcess.MemoryManager.AddrSpaceStart > handlesPtr)
+ {
+ return KernelResult.UserCopyFailed;
+ }
+
+ long handlesSize = handlesCount * 4;
+
+ if (handlesPtr + (ulong)handlesSize <= handlesPtr)
+ {
+ return KernelResult.UserCopyFailed;
+ }
- if (syncObj == null)
+ if (handlesPtr + (ulong)handlesSize - 1 > currentProcess.MemoryManager.AddrSpaceEnd - 1)
{
- break;
+ return KernelResult.UserCopyFailed;
}
- syncObjs.Add(syncObj);
+ Span<int> handles = new Span<int>(currentThread.WaitSyncHandles).Slice(0, handlesCount);
+
+ if (!KernelTransfer.UserToKernelInt32Array(_context, handlesPtr, handles))
+ {
+ return KernelResult.UserCopyFailed;
+ }
+
+ int processedHandles = 0;
+
+ for (; processedHandles < handlesCount; processedHandles++)
+ {
+ KSynchronizationObject syncObj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[processedHandles]);
+
+ if (syncObj == null)
+ {
+ break;
+ }
+
+ syncObjs[processedHandles] = syncObj;
+
+ syncObj.IncrementReferenceCount();
+ }
+
+ if (processedHandles != handlesCount)
+ {
+ // One or more handles are invalid.
+ for (int index = 0; index < processedHandles; index++)
+ {
+ currentThread.WaitSyncObjects[index].DecrementReferenceCount();
+ }
+
+ return KernelResult.InvalidHandle;
+ }
}
- return _context.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex);
+ KernelResult result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex);
+
+ if (result == KernelResult.PortRemoteClosed)
+ {
+ result = KernelResult.Success;
+ }
+
+ for (int index = 0; index < handlesCount; index++)
+ {
+ currentThread.WaitSyncObjects[index].DecrementReferenceCount();
+ }
+
+ return result;
}
public KernelResult CancelSynchronization(int handle)