Просмотр исходного кода

Better implementation of SetThreadCoreMask that allows changing the Core Mask (untested, no clue if it actually works)

gdkchan 8 лет назад
Родитель
Сommit
b2b1d7dcd7

+ 22 - 0
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))

+ 1 - 1
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; }

+ 3 - 0
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;

+ 83 - 2
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;
+
+            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);
 
-            //TODO: Error codes.
+                    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)