diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-11-28 20:18:09 -0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-11-28 20:18:09 -0200 |
| commit | 00579927e43bf55ee06ae02933c1e755fb4120eb (patch) | |
| tree | 0fd06db7b28e0accf87b465ec6f4dc74691febab /Ryujinx.HLE/HOS/Kernel/SvcThread.cs | |
| parent | e7fe7d724778535f8eff390abef54274a343c0b7 (diff) | |
Better process implementation (#491)
* Initial implementation of KProcess
* Some improvements to the memory manager, implement back guest stack trace printing
* Better GetInfo implementation, improve checking in some places with information from process capabilities
* Allow the cpu to read/write from the correct memory locations for accesses crossing a page boundary
* Change long -> ulong for address/size on memory related methods to avoid unnecessary casts
* Attempt at implementing ldr:ro with new KProcess
* Allow BSS with size 0 on ldr:ro
* Add checking for memory block slab heap usage, return errors if full, exit gracefully
* Use KMemoryBlockSize const from KMemoryManager
* Allow all methods to read from non-contiguous locations
* Fix for TransactParcelAuto
* Address PR feedback, additionally fix some small issues related to the KIP loader and implement SVCs GetProcessId, GetProcessList, GetSystemInfo, CreatePort and ManageNamedPort
* Fix wrong check for source pages count from page list on MapPhysicalMemory
* Fix some issues with UnloadNro on ldr:ro
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/SvcThread.cs')
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/SvcThread.cs | 198 |
1 files changed, 129 insertions, 69 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs index 53a557de..ded8f8dc 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs @@ -7,46 +7,82 @@ namespace Ryujinx.HLE.HOS.Kernel { partial class SvcHandler { - private void SvcCreateThread(CpuThreadState ThreadState) + private void CreateThread64(CpuThreadState ThreadState) { - long EntryPoint = (long)ThreadState.X1; - long ArgsPtr = (long)ThreadState.X2; - long StackTop = (long)ThreadState.X3; - int Priority = (int)ThreadState.X4; - int ProcessorId = (int)ThreadState.X5; + ulong Entrypoint = ThreadState.X1; + ulong ArgsPtr = ThreadState.X2; + ulong StackTop = ThreadState.X3; + int Priority = (int)ThreadState.X4; + int CpuCore = (int)ThreadState.X5; - if ((uint)Priority > 0x3f) - { - Logger.PrintWarning(LogClass.KernelSvc, $"Invalid priority 0x{Priority:x8}!"); + KernelResult Result = CreateThread(Entrypoint, ArgsPtr, StackTop, Priority, CpuCore, out int Handle); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPriority); + ThreadState.X0 = (ulong)Result; + ThreadState.X1 = (ulong)Handle; + } - return; + private KernelResult CreateThread( + ulong Entrypoint, + ulong ArgsPtr, + ulong StackTop, + int Priority, + int CpuCore, + out int Handle) + { + Handle = 0; + + KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); + + if (CpuCore == -2) + { + CpuCore = CurrentProcess.DefaultCpuCore; } - if (ProcessorId == -2) + if ((uint)CpuCore >= KScheduler.CpuCoresCount || !CurrentProcess.IsCpuCoreAllowed(CpuCore)) { - //TODO: Get this value from the NPDM file. - ProcessorId = 0; + return KernelResult.InvalidCpuCore; } - else if ((uint)ProcessorId > 3) + + if ((uint)Priority >= KScheduler.PrioritiesCount || !CurrentProcess.IsPriorityAllowed(Priority)) { - Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{ProcessorId:x8}!"); + return KernelResult.InvalidPriority; + } - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId); + long Timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100); - return; + if (CurrentProcess.ResourceLimit != null && + !CurrentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, Timeout)) + { + return KernelResult.ResLimitExceeded; } - int Handle = Process.MakeThread( - EntryPoint, - StackTop, + KThread Thread = new KThread(System); + + KernelResult Result = CurrentProcess.InitializeThread( + Thread, + Entrypoint, ArgsPtr, + StackTop, Priority, - ProcessorId); + CpuCore); - ThreadState.X0 = 0; - ThreadState.X1 = (ulong)Handle; + if (Result != KernelResult.Success) + { + CurrentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1); + + return Result; + } + + Result = Process.HandleTable.GenerateHandle(Thread, out Handle); + + if (Result != KernelResult.Success) + { + Thread.Terminate(); + + CurrentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1); + } + + return Result; } private void SvcStartThread(CpuThreadState ThreadState) @@ -57,11 +93,11 @@ namespace Ryujinx.HLE.HOS.Kernel if (Thread != null) { - long Result = Thread.Start(); + KernelResult Result = Thread.Start(); - if (Result != 0) + if (Result != KernelResult.Success) { - Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\"."); } ThreadState.X0 = (ulong)Result; @@ -78,9 +114,9 @@ namespace Ryujinx.HLE.HOS.Kernel { KThread CurrentThread = System.Scheduler.GetCurrentThread(); - CurrentThread.Exit(); + System.Scheduler.ExitThread(CurrentThread); - System.Scheduler.StopThread(CurrentThread); + CurrentThread.Exit(); } private void SvcSleepThread(CpuThreadState ThreadState) @@ -176,46 +212,60 @@ namespace Ryujinx.HLE.HOS.Kernel } } - private void SvcSetThreadCoreMask(CpuThreadState ThreadState) + private void SetThreadCoreMask64(CpuThreadState ThreadState) { int Handle = (int)ThreadState.X0; - int PrefferedCore = (int)ThreadState.X1; + int PreferredCore = (int)ThreadState.X1; long AffinityMask = (long)ThreadState.X2; Logger.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + Handle .ToString("x8") + ", " + - "PrefferedCore = 0x" + PrefferedCore.ToString("x8") + ", " + + "PreferredCore = 0x" + PreferredCore.ToString("x8") + ", " + "AffinityMask = 0x" + AffinityMask .ToString("x16")); - if (PrefferedCore == -2) + KernelResult Result = SetThreadCoreMask(Handle, PreferredCore, AffinityMask); + + if (Result != KernelResult.Success) { - //TODO: Get this value from the NPDM file. - PrefferedCore = 0; + Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\"."); + } - AffinityMask = 1 << PrefferedCore; + ThreadState.X0 = (ulong)Result; + } + + private KernelResult SetThreadCoreMask(int Handle, int PreferredCore, long AffinityMask) + { + KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); + + if (PreferredCore == -2) + { + PreferredCore = CurrentProcess.DefaultCpuCore; + + AffinityMask = 1 << PreferredCore; } else { - //TODO: Check allowed cores from NPDM file. - - if ((uint)PrefferedCore > 3) + if ((CurrentProcess.Capabilities.AllowedCpuCoresMask | AffinityMask) != + CurrentProcess.Capabilities.AllowedCpuCoresMask) { - if ((PrefferedCore | 2) != -1) - { - Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{PrefferedCore:x8}!"); + return KernelResult.InvalidCpuCore; + } - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId); + if (AffinityMask == 0) + { + return KernelResult.InvalidCombination; + } - return; + if ((uint)PreferredCore > 3) + { + if ((PreferredCore | 2) != -1) + { + return KernelResult.InvalidCpuCore; } } - else if ((AffinityMask & (1 << PrefferedCore)) == 0) + else if ((AffinityMask & (1 << PreferredCore)) == 0) { - Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{AffinityMask:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); - - return; + return KernelResult.InvalidCombination; } } @@ -223,26 +273,15 @@ namespace Ryujinx.HLE.HOS.Kernel if (Thread == null) { - Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); - - return; - } - - long Result = Thread.SetCoreAndAffinityMask(PrefferedCore, AffinityMask); - - if (Result != 0) - { - Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + return KernelResult.InvalidHandle; } - ThreadState.X0 = (ulong)Result; + return Thread.SetCoreAndAffinityMask(PreferredCore, AffinityMask); } private void SvcGetCurrentProcessorNumber(CpuThreadState ThreadState) { - ThreadState.X0 = (ulong)Process.GetThread(ThreadState.Tpidr).CurrentCore; + ThreadState.X0 = (ulong)System.Scheduler.GetCurrentThread().CurrentCore; } private void SvcGetThreadId(CpuThreadState ThreadState) @@ -254,7 +293,7 @@ namespace Ryujinx.HLE.HOS.Kernel if (Thread != null) { ThreadState.X0 = 0; - ThreadState.X1 = (ulong)Thread.ThreadId; + ThreadState.X1 = (ulong)Thread.ThreadUid; } else { @@ -280,15 +319,24 @@ namespace Ryujinx.HLE.HOS.Kernel return; } - if (Thread.Owner != Process) + if (Thread.Owner != System.Scheduler.GetCurrentProcess()) { - Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread owner process!"); + Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process."); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return; } + if (Thread == System.Scheduler.GetCurrentThread()) + { + Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted."); + + ThreadState.X0 = (ulong)KernelResult.InvalidThread; + + return; + } + long Result = Thread.SetActivity(Pause); if (Result != 0) @@ -304,6 +352,9 @@ namespace Ryujinx.HLE.HOS.Kernel long Position = (long)ThreadState.X0; int Handle = (int)ThreadState.X1; + KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); + KThread CurrentThread = System.Scheduler.GetCurrentThread(); + KThread Thread = Process.HandleTable.GetObject<KThread>(Handle); if (Thread == null) @@ -315,9 +366,18 @@ namespace Ryujinx.HLE.HOS.Kernel return; } - if (Process.GetThread(ThreadState.Tpidr) == Thread) + if (Thread.Owner != CurrentProcess) + { + Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process."); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (CurrentThread == Thread) { - Logger.PrintWarning(LogClass.KernelSvc, $"Thread handle 0x{Handle:x8} is current thread!"); + Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted."); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread); |
