diff --git a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs index a154b1c619..33f7fb1449 100644 --- a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs +++ b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs @@ -196,6 +196,28 @@ namespace Ryujinx.Core.OsHle.Handles Resume(Thread); } + public bool TryRunning(KThread Thread) + { + if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) + { + throw new InvalidOperationException(); + } + + lock (SchedLock) + { + if (WaitingToRun.HasThread(SchedThread) && AddActiveCore(Thread)) + { + WaitingToRun.Remove(SchedThread); + + RunThread(SchedThread); + + return true; + } + + return false; + } + } + public void Resume(KThread Thread) { if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) diff --git a/Ryujinx.Core/OsHle/Handles/KThread.cs b/Ryujinx.Core/OsHle/Handles/KThread.cs index 1a044665a3..a430974c1a 100644 --- a/Ryujinx.Core/OsHle/Handles/KThread.cs +++ b/Ryujinx.Core/OsHle/Handles/KThread.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Core.OsHle.Handles public int ActualPriority { get; private set; } public int WantedPriority { get; private set; } - public int IdealCore { get; private set; } + public int IdealCore { get; set; } public int ActualCore { get; set; } public int WaitHandle { get; set; } diff --git a/Ryujinx.Core/OsHle/Kernel/KernelErr.cs b/Ryujinx.Core/OsHle/Kernel/KernelErr.cs index 87f9cf3b34..17c0044cd2 100644 --- a/Ryujinx.Core/OsHle/Kernel/KernelErr.cs +++ b/Ryujinx.Core/OsHle/Kernel/KernelErr.cs @@ -5,7 +5,10 @@ namespace Ryujinx.Core.OsHle.Kernel public const int InvalidAlignment = 102; public const int InvalidAddress = 106; public const int InvalidMemRange = 110; + public const int InvalidPriority = 112; + public const int InvalidCoreId = 113; public const int InvalidHandle = 114; + public const int InvalidCoreMask = 116; public const int Timeout = 117; public const int Canceled = 118; public const int CountOutOfRange = 119; diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs index 71f3347a3c..94912f536f 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs @@ -17,11 +17,28 @@ namespace Ryujinx.Core.OsHle.Kernel int Priority = (int)ThreadState.X4; int ProcessorId = (int)ThreadState.X5; + if ((uint)Priority > 0x3f) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid priority 0x{Priority:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPriority); + + return; + } + if (ProcessorId == -2) { //TODO: Get this value from the NPDM file. ProcessorId = 0; } + else if ((uint)ProcessorId > 3) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{ProcessorId:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId); + + return; + } int Handle = Process.MakeThread( EntryPoint, @@ -125,9 +142,73 @@ namespace Ryujinx.Core.OsHle.Kernel private void SvcSetThreadCoreMask(AThreadState ThreadState) { - ThreadState.X0 = 0; + int Handle = (int)ThreadState.X0; + int IdealCore = (int)ThreadState.X1; + long CoreMask = (long)ThreadState.X2; - //TODO: Error codes. + KThread Thread = GetThread(ThreadState.Tpidr, Handle); + + if (IdealCore == -2) + { + //TODO: Get this value from the NPDM file. + IdealCore = 0; + + CoreMask = 1 << IdealCore; + } + else if (IdealCore != -3) + { + if ((uint)IdealCore > 3) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{IdealCore:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId); + + return; + } + + if ((CoreMask & (1 << IdealCore)) == 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreMask); + + return; + } + } + + if (Thread == null) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (IdealCore == -3) + { + if ((CoreMask & (1 << Thread.IdealCore)) == 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreMask); + + return; + } + } + else + { + Thread.IdealCore = IdealCore; + } + + Thread.CoreMask = (int)CoreMask; + + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + Process.Scheduler.Yield(CurrThread); + Process.Scheduler.TryRunning(Thread); + + ThreadState.X0 = 0; } private void SvcGetCurrentProcessorNumber(AThreadState ThreadState)