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
This commit is contained in:
parent
e7fe7d7247
commit
00579927e4
119 changed files with 7998 additions and 3232 deletions
|
@ -7,48 +7,84 @@ 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);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ProcessorId == -2)
|
||||
{
|
||||
//TODO: Get this value from the NPDM file.
|
||||
ProcessorId = 0;
|
||||
}
|
||||
else if ((uint)ProcessorId > 3)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{ProcessorId:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int Handle = Process.MakeThread(
|
||||
EntryPoint,
|
||||
StackTop,
|
||||
ArgsPtr,
|
||||
Priority,
|
||||
ProcessorId);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
ThreadState.X1 = (ulong)Handle;
|
||||
}
|
||||
|
||||
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 ((uint)CpuCore >= KScheduler.CpuCoresCount || !CurrentProcess.IsCpuCoreAllowed(CpuCore))
|
||||
{
|
||||
return KernelResult.InvalidCpuCore;
|
||||
}
|
||||
|
||||
if ((uint)Priority >= KScheduler.PrioritiesCount || !CurrentProcess.IsPriorityAllowed(Priority))
|
||||
{
|
||||
return KernelResult.InvalidPriority;
|
||||
}
|
||||
|
||||
long Timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
|
||||
|
||||
if (CurrentProcess.ResourceLimit != null &&
|
||||
!CurrentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, Timeout))
|
||||
{
|
||||
return KernelResult.ResLimitExceeded;
|
||||
}
|
||||
|
||||
KThread Thread = new KThread(System);
|
||||
|
||||
KernelResult Result = CurrentProcess.InitializeThread(
|
||||
Thread,
|
||||
Entrypoint,
|
||||
ArgsPtr,
|
||||
StackTop,
|
||||
Priority,
|
||||
CpuCore);
|
||||
|
||||
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)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
|
@ -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)
|
||||
{
|
||||
//TODO: Get this value from the NPDM file.
|
||||
PrefferedCore = 0;
|
||||
KernelResult Result = SetThreadCoreMask(Handle, PreferredCore, AffinityMask);
|
||||
|
||||
AffinityMask = 1 << PrefferedCore;
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
}
|
||||
|
||||
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)
|
||||
return KernelResult.InvalidCpuCore;
|
||||
}
|
||||
|
||||
if (AffinityMask == 0)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
if ((uint)PreferredCore > 3)
|
||||
{
|
||||
if ((PreferredCore | 2) != -1)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{PrefferedCore:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId);
|
||||
|
||||
return;
|
||||
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;
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
long Result = Thread.SetCoreAndAffinityMask(PrefferedCore, AffinityMask);
|
||||
|
||||
if (Result != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
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, $"Thread handle 0x{Handle:x8} is current thread!");
|
||||
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, "Invalid thread, current thread is not accepted.");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue