diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2020-07-17 01:22:13 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-17 14:22:13 +1000 |
| commit | 20774dab14ca8362e716ce87f975be7ea77beead (patch) | |
| tree | c2d3c7b6abd154648d414d1e01ebf1684efc054c /Ryujinx.HLE/HOS/Kernel/SupervisorCall | |
| parent | 88619d71b8e4840218c68b712aa184098d2dbccf (diff) | |
Improve kernel WaitSynchronization syscall implementation (#1362)
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/SupervisorCall')
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs | 75 |
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) |
