diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-05-07 15:53:23 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-05-07 15:53:23 -0300 |
| commit | 34037701c708cb70bbf44dea71ee0912f7b4102b (patch) | |
| tree | ca4cf2bde85dea48af12033b8d0446f17b611f4f /Ryujinx.Core/OsHle/Kernel | |
| parent | 4419e8d6b43432eae94a3a9304f7df22b34738a8 (diff) | |
NvServices refactoring (#120)
* Initial implementation of NvMap/NvHostCtrl
* More work on NvHostCtrl
* Refactoring of nvservices, move GPU Vmm, make Vmm per-process, refactor most gpu devices, move Gpu to Core, fix CbBind
* Implement GetGpuTime, support CancelSynchronization, fix issue on InsertWaitingMutex, proper double buffering support (again, not working properly for commercial games, only hb)
* Try to fix perf regression reading/writing textures, moved syncpts and events to a UserCtx class, delete global state when the process exits, other minor tweaks
* Remove now unused code, add comment about probably wrong result codes
Diffstat (limited to 'Ryujinx.Core/OsHle/Kernel')
| -rw-r--r-- | Ryujinx.Core/OsHle/Kernel/KernelErr.cs | 2 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Kernel/SvcHandler.cs | 21 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Kernel/SvcSystem.cs | 85 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs | 6 |
4 files changed, 96 insertions, 18 deletions
diff --git a/Ryujinx.Core/OsHle/Kernel/KernelErr.cs b/Ryujinx.Core/OsHle/Kernel/KernelErr.cs index b568405b..87f9cf3b 100644 --- a/Ryujinx.Core/OsHle/Kernel/KernelErr.cs +++ b/Ryujinx.Core/OsHle/Kernel/KernelErr.cs @@ -7,6 +7,8 @@ namespace Ryujinx.Core.OsHle.Kernel public const int InvalidMemRange = 110; public const int InvalidHandle = 114; public const int Timeout = 117; + public const int Canceled = 118; + public const int CountOutOfRange = 119; public const int InvalidInfo = 120; } }
\ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs index e855b77d..1874360b 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs @@ -5,6 +5,8 @@ using Ryujinx.Core.Logging; using Ryujinx.Core.OsHle.Handles; using System; using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Threading; namespace Ryujinx.Core.OsHle.Kernel { @@ -18,12 +20,16 @@ namespace Ryujinx.Core.OsHle.Kernel private Process Process; private AMemory Memory; + private ConcurrentDictionary<KThread, AutoResetEvent> SyncWaits; + private object CondVarLock; private HashSet<(HSharedMem, long)> MappedSharedMems; private ulong CurrentHeapSize; + private const uint SelfHandle = 0xffff8001; + private static Random Rng; public SvcHandler(Switch Ns, Process Process) @@ -51,6 +57,7 @@ namespace Ryujinx.Core.OsHle.Kernel { 0x16, SvcCloseHandle }, { 0x17, SvcResetSignal }, { 0x18, SvcWaitSynchronization }, + { 0x19, SvcCancelSynchronization }, { 0x1a, SvcArbitrateLock }, { 0x1b, SvcArbitrateUnlock }, { 0x1c, SvcWaitProcessWideKeyAtomic }, @@ -70,6 +77,8 @@ namespace Ryujinx.Core.OsHle.Kernel this.Process = Process; this.Memory = Process.Memory; + SyncWaits = new ConcurrentDictionary<KThread, AutoResetEvent>(); + CondVarLock = new object(); MappedSharedMems = new HashSet<(HSharedMem, long)>(); @@ -100,6 +109,18 @@ namespace Ryujinx.Core.OsHle.Kernel } } + private KThread GetThread(long Tpidr, int Handle) + { + if ((uint)Handle == SelfHandle) + { + return Process.GetThread(Tpidr); + } + else + { + return Process.HandleTable.GetData<KThread>(Handle); + } + } + public void Dispose() { Dispose(true); diff --git a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs index 601b211c..e5b080a8 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs @@ -40,7 +40,7 @@ namespace Ryujinx.Core.OsHle.Kernel if (Obj == null) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Tried to CloseHandle on invalid handle 0x{Handle:x8}!"); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); @@ -88,9 +88,21 @@ namespace Ryujinx.Core.OsHle.Kernel int HandlesCount = (int)ThreadState.X2; ulong Timeout = ThreadState.X3; + Ns.Log.PrintDebug(LogClass.KernelSvc, + "HandlesPtr = " + HandlesPtr .ToString("x16") + ", " + + "HandlesCount = " + HandlesCount.ToString("x8") + ", " + + "Timeout = " + Timeout .ToString("x16")); + + if ((uint)HandlesCount > 0x40) + { + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange); + + return; + } + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - WaitHandle[] Handles = new WaitHandle[HandlesCount]; + WaitHandle[] Handles = new WaitHandle[HandlesCount + 1]; for (int Index = 0; Index < HandlesCount; Index++) { @@ -110,34 +122,73 @@ namespace Ryujinx.Core.OsHle.Kernel Handles[Index] = SyncObj.WaitEvent; } - Process.Scheduler.Suspend(CurrThread.ProcessorId); + using (AutoResetEvent WaitEvent = new AutoResetEvent(false)) + { + if (!SyncWaits.TryAdd(CurrThread, WaitEvent)) + { + throw new InvalidOperationException(); + } + + Handles[HandlesCount] = WaitEvent; - int HandleIndex; + Process.Scheduler.Suspend(CurrThread.ProcessorId); - ulong Result = 0; + int HandleIndex; - if (Timeout != ulong.MaxValue) - { - HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout)); + ulong Result = 0; + + if (Timeout != ulong.MaxValue) + { + HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout)); + } + else + { + HandleIndex = WaitHandle.WaitAny(Handles); + } if (HandleIndex == WaitHandle.WaitTimeout) { Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); } + else if (HandleIndex == HandlesCount) + { + Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled); + } + + SyncWaits.TryRemove(CurrThread, out _); + + Process.Scheduler.Resume(CurrThread); + + ThreadState.X0 = Result; + + if (Result == 0) + { + ThreadState.X1 = (ulong)HandleIndex; + } } - else + } + + private void SvcCancelSynchronization(AThreadState ThreadState) + { + int ThreadHandle = (int)ThreadState.X0; + + KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle); + + if (Thread == null) { - HandleIndex = WaitHandle.WaitAny(Handles); - } + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!"); - Process.Scheduler.Resume(CurrThread); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - ThreadState.X0 = Result; + return; + } - if (Result == 0) + if (SyncWaits.TryRemove(Thread, out AutoResetEvent WaitEvent)) { - ThreadState.X1 = (ulong)HandleIndex; + WaitEvent.Set(); } + + ThreadState.X0 = 0; } private void SvcGetSystemTick(AThreadState ThreadState) @@ -190,13 +241,13 @@ namespace Ryujinx.Core.OsHle.Kernel IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr); - IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr); + long Result = IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr); Thread.Yield(); Process.Scheduler.Resume(CurrThread); - ThreadState.X0 = 0; + ThreadState.X0 = (ulong)Result; } else { diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs index e382cf75..57608cda 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs @@ -191,6 +191,8 @@ namespace Ryujinx.Core.OsHle.Kernel InsertWaitingMutexThread(OwnerThreadHandle, WaitThread); + Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state..."); + Process.Scheduler.EnterWait(CurrThread); } @@ -297,6 +299,8 @@ namespace Ryujinx.Core.OsHle.Kernel } } + Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state..."); + if (Timeout != ulong.MaxValue) { return Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout)); @@ -407,7 +411,7 @@ namespace Ryujinx.Core.OsHle.Kernel if (CurrThread != WaitThread) { - if (WaitThread.NextCondVarThread != null) + if (WaitThread.NextMutexThread != null) { throw new InvalidOperationException(); } |
