aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-12-18 03:33:36 -0200
committerGitHub <noreply@github.com>2018-12-18 03:33:36 -0200
commit0039bb639493b2d1e2764cae380311ba8e87704b (patch)
tree63a912a95c8261775c2acb8a5b9ca0f10ad4ae33 /Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs
parent2534a7f10c627810e6e0272b4cc9758e90f733c1 (diff)
Refactor SVC handler (#540)
* Refactor SVC handler * Get rid of KernelErr * Split kernel code files into multiple folders
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs250
1 files changed, 250 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs
new file mode 100644
index 00000000..ecda9e2d
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs
@@ -0,0 +1,250 @@
+using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Process;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
+{
+ partial class SvcHandler
+ {
+ public KernelResult WaitSynchronization64(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
+ {
+ return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
+ }
+
+ private KernelResult WaitSynchronization(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
+ {
+ handleIndex = 0;
+
+ if ((uint)handlesCount > 0x40)
+ {
+ return KernelResult.MaximumExceeded;
+ }
+
+ List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
+
+ for (int index = 0; index < handlesCount; index++)
+ {
+ int handle = _memory.ReadInt32((long)handlesPtr + index * 4);
+
+ KSynchronizationObject syncObj = _process.HandleTable.GetObject<KSynchronizationObject>(handle);
+
+ if (syncObj == null)
+ {
+ break;
+ }
+
+ syncObjs.Add(syncObj);
+ }
+
+ return _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex);
+ }
+
+ public KernelResult CancelSynchronization64(int handle)
+ {
+ return CancelSynchronization(handle);
+ }
+
+ private KernelResult CancelSynchronization(int handle)
+ {
+ KThread thread = _process.HandleTable.GetKThread(handle);
+
+ if (thread == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
+
+ thread.CancelSynchronization();
+
+ return KernelResult.Success;
+ }
+
+ public KernelResult ArbitrateLock64(int ownerHandle, ulong mutexAddress, int requesterHandle)
+ {
+ return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
+ }
+
+ private KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
+ {
+ if (IsPointingInsideKernel(mutexAddress))
+ {
+ return KernelResult.InvalidMemState;
+ }
+
+ if (IsAddressNotWordAligned(mutexAddress))
+ {
+ return KernelResult.InvalidAddress;
+ }
+
+ KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
+
+ return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
+ }
+
+ public KernelResult ArbitrateUnlock64(ulong mutexAddress)
+ {
+ return ArbitrateUnlock(mutexAddress);
+ }
+
+ private KernelResult ArbitrateUnlock(ulong mutexAddress)
+ {
+ if (IsPointingInsideKernel(mutexAddress))
+ {
+ return KernelResult.InvalidMemState;
+ }
+
+ if (IsAddressNotWordAligned(mutexAddress))
+ {
+ return KernelResult.InvalidAddress;
+ }
+
+ KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
+
+ return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
+ }
+
+ public KernelResult WaitProcessWideKeyAtomic64(
+ ulong mutexAddress,
+ ulong condVarAddress,
+ int handle,
+ long timeout)
+ {
+ return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
+ }
+
+ private KernelResult WaitProcessWideKeyAtomic(
+ ulong mutexAddress,
+ ulong condVarAddress,
+ int handle,
+ long timeout)
+ {
+ if (IsPointingInsideKernel(mutexAddress))
+ {
+ return KernelResult.InvalidMemState;
+ }
+
+ if (IsAddressNotWordAligned(mutexAddress))
+ {
+ return KernelResult.InvalidAddress;
+ }
+
+ KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
+
+ return currentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
+ mutexAddress,
+ condVarAddress,
+ handle,
+ timeout);
+ }
+
+ public KernelResult SignalProcessWideKey64(ulong address, int count)
+ {
+ return SignalProcessWideKey(address, count);
+ }
+
+ private KernelResult SignalProcessWideKey(ulong address, int count)
+ {
+ KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
+
+ currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
+
+ return KernelResult.Success;
+ }
+
+ public KernelResult WaitForAddress64(ulong address, ArbitrationType type, int value, long timeout)
+ {
+ return WaitForAddress(address, type, value, timeout);
+ }
+
+ private KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout)
+ {
+ if (IsPointingInsideKernel(address))
+ {
+ return KernelResult.InvalidMemState;
+ }
+
+ if (IsAddressNotWordAligned(address))
+ {
+ return KernelResult.InvalidAddress;
+ }
+
+ KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
+
+ KernelResult result;
+
+ switch (type)
+ {
+ case ArbitrationType.WaitIfLessThan:
+ result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, false, timeout);
+ break;
+
+ case ArbitrationType.DecrementAndWaitIfLessThan:
+ result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, true, timeout);
+ break;
+
+ case ArbitrationType.WaitIfEqual:
+ result = currentProcess.AddressArbiter.WaitForAddressIfEqual(address, value, timeout);
+ break;
+
+ default:
+ result = KernelResult.InvalidEnumValue;
+ break;
+ }
+
+ return result;
+ }
+
+ public KernelResult SignalToAddress64(ulong address, SignalType type, int value, int count)
+ {
+ return SignalToAddress(address, type, value, count);
+ }
+
+ private KernelResult SignalToAddress(ulong address, SignalType type, int value, int count)
+ {
+ if (IsPointingInsideKernel(address))
+ {
+ return KernelResult.InvalidMemState;
+ }
+
+ if (IsAddressNotWordAligned(address))
+ {
+ return KernelResult.InvalidAddress;
+ }
+
+ KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
+
+ KernelResult result;
+
+ switch (type)
+ {
+ case SignalType.Signal:
+ result = currentProcess.AddressArbiter.Signal(address, count);
+ break;
+
+ case SignalType.SignalAndIncrementIfEqual:
+ result = currentProcess.AddressArbiter.SignalAndIncrementIfEqual(address, value, count);
+ break;
+
+ case SignalType.SignalAndModifyIfEqual:
+ result = currentProcess.AddressArbiter.SignalAndModifyIfEqual(address, value, count);
+ break;
+
+ default:
+ result = KernelResult.InvalidEnumValue;
+ break;
+ }
+
+ return result;
+ }
+
+ private bool IsPointingInsideKernel(ulong address)
+ {
+ return (address + 0x1000000000) < 0xffffff000;
+ }
+
+ private bool IsAddressNotWordAligned(ulong address)
+ {
+ return (address & 3) != 0;
+ }
+ }
+} \ No newline at end of file