aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/SvcSystem.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SvcSystem.cs584
1 files changed, 505 insertions, 79 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs
index 54aef5d7..1c1d76f1 100644
--- a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs
@@ -1,5 +1,6 @@
using ChocolArm64.Memory;
using ChocolArm64.State;
+using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
@@ -13,13 +14,9 @@ namespace Ryujinx.HLE.HOS.Kernel
{
partial class SvcHandler
{
- private const int AllowedCpuIdBitmask = 0b1111;
-
- private const bool EnableProcessDebugging = false;
-
private void SvcExitProcess(CpuThreadState ThreadState)
{
- Device.System.ExitProcess(Process.ProcessId);
+ System.Scheduler.GetCurrentProcess().Terminate();
}
private void SignalEvent64(CpuThreadState ThreadState)
@@ -106,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Kernel
else if (Obj is KTransferMemory TransferMemory)
{
Process.MemoryManager.ResetTransferMemory(
- TransferMemory.Position,
+ TransferMemory.Address,
TransferMemory.Size);
}
@@ -120,18 +117,28 @@ namespace Ryujinx.HLE.HOS.Kernel
private KernelResult ResetSignal(int Handle)
{
- KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
+ KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
+
+ KReadableEvent ReadableEvent = CurrentProcess.HandleTable.GetObject<KReadableEvent>(Handle);
KernelResult Result;
- //TODO: KProcess support.
if (ReadableEvent != null)
{
Result = ReadableEvent.ClearIfSignaled();
}
else
{
- Result = KernelResult.InvalidHandle;
+ KProcess Process = CurrentProcess.HandleTable.GetKProcess(Handle);
+
+ if (Process != null)
+ {
+ Result = Process.ClearIfNotExited();
+ }
+ else
+ {
+ Result = KernelResult.InvalidHandle;
+ }
}
if (Result == KernelResult.InvalidState)
@@ -187,17 +194,13 @@ namespace Ryujinx.HLE.HOS.Kernel
private void SendSyncRequest(CpuThreadState ThreadState, long MessagePtr, long Size, int Handle)
{
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
byte[] MessageData = Memory.ReadBytes(MessagePtr, Size);
KSession Session = Process.HandleTable.GetObject<KSession>(Handle);
if (Session != null)
{
- //Process.Scheduler.Suspend(CurrThread);
-
- System.CriticalSectionLock.Lock();
+ System.CriticalSection.Enter();
KThread CurrentThread = System.Scheduler.GetCurrentThread();
@@ -214,7 +217,9 @@ namespace Ryujinx.HLE.HOS.Kernel
Message,
MessagePtr));
- System.CriticalSectionLock.Unlock();
+ System.ThreadCounter.AddCount();
+
+ System.CriticalSection.Leave();
ThreadState.X0 = (ulong)CurrentThread.ObjSyncResult;
}
@@ -238,25 +243,65 @@ namespace Ryujinx.HLE.HOS.Kernel
IpcMessage.Message,
IpcMessage.MessagePtr);
+ System.ThreadCounter.Signal();
+
IpcMessage.Thread.Reschedule(ThreadSchedState.Running);
}
+ private void GetProcessId64(CpuThreadState ThreadState)
+ {
+ int Handle = (int)ThreadState.X1;
+
+ KernelResult Result = GetProcessId(Handle, out long Pid);
+
+ ThreadState.X0 = (ulong)Result;
+ ThreadState.X1 = (ulong)Pid;
+ }
+
+ private KernelResult GetProcessId(int Handle, out long Pid)
+ {
+ KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
+
+ KProcess Process = CurrentProcess.HandleTable.GetKProcess(Handle);
+
+ if (Process == null)
+ {
+ KThread Thread = CurrentProcess.HandleTable.GetKThread(Handle);
+
+ if (Thread != null)
+ {
+ Process = Thread.Owner;
+ }
+
+ //TODO: KDebugEvent.
+ }
+
+ Pid = Process?.Pid ?? 0;
+
+ return Process != null
+ ? KernelResult.Success
+ : KernelResult.InvalidHandle;
+ }
+
private void SvcBreak(CpuThreadState ThreadState)
{
long Reason = (long)ThreadState.X0;
long Unknown = (long)ThreadState.X1;
long Info = (long)ThreadState.X2;
+ KThread CurrentThread = System.Scheduler.GetCurrentThread();
+
if ((Reason & (1 << 31)) == 0)
{
- Process.PrintStackTrace(ThreadState);
+ CurrentThread.PrintGuestStackTrace();
throw new GuestBrokeExecutionException();
}
else
{
- Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered");
- Process.PrintStackTrace(ThreadState);
+ Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered.");
+
+ CurrentThread.PrintGuestStackTrace();
}
}
@@ -272,98 +317,243 @@ namespace Ryujinx.HLE.HOS.Kernel
ThreadState.X0 = 0;
}
- private void SvcGetInfo(CpuThreadState ThreadState)
+ private void GetInfo64(CpuThreadState ThreadState)
{
long StackPtr = (long)ThreadState.X0;
- int InfoType = (int)ThreadState.X1;
- long Handle = (long)ThreadState.X2;
- int InfoId = (int)ThreadState.X3;
+ uint Id = (uint)ThreadState.X1;
+ int Handle = (int)ThreadState.X2;
+ long SubId = (long)ThreadState.X3;
- //Fail for info not available on older Kernel versions.
- if (InfoType == 18 ||
- InfoType == 19 ||
- InfoType == 20 ||
- InfoType == 21 ||
- InfoType == 22)
- {
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
+ KernelResult Result = GetInfo(Id, Handle, SubId, out long Value);
- return;
- }
+ ThreadState.X0 = (ulong)Result;
+ ThreadState.X1 = (ulong)Value;
+ }
+
+ private KernelResult GetInfo(uint Id, int Handle, long SubId, out long Value)
+ {
+ Value = 0;
- switch (InfoType)
+ switch (Id)
{
case 0:
- ThreadState.X1 = AllowedCpuIdBitmask;
- break;
-
+ case 1:
case 2:
- ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionStart;
- break;
-
case 3:
- ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionEnd -
- (ulong)Process.MemoryManager.MapRegionStart;
- break;
-
case 4:
- ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionStart;
- break;
-
case 5:
- ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionEnd -
- (ulong)Process.MemoryManager.HeapRegionStart;
- break;
-
case 6:
- ThreadState.X1 = (ulong)Process.Device.Memory.Allocator.TotalAvailableSize;
- break;
-
case 7:
- ThreadState.X1 = (ulong)Process.Device.Memory.Allocator.TotalUsedSize;
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 20:
+ case 21:
+ case 22:
+ {
+ if (SubId != 0)
+ {
+ return KernelResult.InvalidCombination;
+ }
+
+ KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
+
+ KProcess Process = CurrentProcess.HandleTable.GetKProcess(Handle);
+
+ if (Process == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
+
+ switch (Id)
+ {
+ case 0: Value = Process.Capabilities.AllowedCpuCoresMask; break;
+ case 1: Value = Process.Capabilities.AllowedThreadPriosMask; break;
+
+ case 2: Value = (long)Process.MemoryManager.AliasRegionStart; break;
+ case 3: Value = (long)(Process.MemoryManager.AliasRegionEnd -
+ Process.MemoryManager.AliasRegionStart); break;
+
+ case 4: Value = (long)Process.MemoryManager.HeapRegionStart; break;
+ case 5: Value = (long)(Process.MemoryManager.HeapRegionEnd -
+ Process.MemoryManager.HeapRegionStart); break;
+
+ case 6: Value = (long)Process.GetMemoryCapacity(); break;
+
+ case 7: Value = (long)Process.GetMemoryUsage(); break;
+
+ case 12: Value = (long)Process.MemoryManager.GetAddrSpaceBaseAddr(); break;
+
+ case 13: Value = (long)Process.MemoryManager.GetAddrSpaceSize(); break;
+
+ case 14: Value = (long)Process.MemoryManager.StackRegionStart; break;
+ case 15: Value = (long)(Process.MemoryManager.StackRegionEnd -
+ Process.MemoryManager.StackRegionStart); break;
+
+ case 16: Value = (long)Process.PersonalMmHeapPagesCount * KMemoryManager.PageSize; break;
+
+ case 17:
+ if (Process.PersonalMmHeapPagesCount != 0)
+ {
+ Value = Process.MemoryManager.GetMmUsedPages() * KMemoryManager.PageSize;
+ }
+
+ break;
+
+ case 18: Value = Process.TitleId; break;
+
+ case 20: Value = (long)Process.UserExceptionContextAddress; break;
+
+ case 21: Value = (long)Process.GetMemoryCapacityWithoutPersonalMmHeap(); break;
+
+ case 22: Value = (long)Process.GetMemoryUsageWithoutPersonalMmHeap(); break;
+ }
+
break;
+ }
case 8:
- ThreadState.X1 = EnableProcessDebugging ? 1 : 0;
- break;
+ {
+ if (Handle != 0)
+ {
+ return KernelResult.InvalidHandle;
+ }
- case 11:
- ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
- break;
+ if (SubId != 0)
+ {
+ return KernelResult.InvalidCombination;
+ }
- case 12:
- ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceStart;
- break;
+ Value = System.Scheduler.GetCurrentProcess().Debug ? 1 : 0;
- case 13:
- ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceEnd -
- (ulong)Process.MemoryManager.AddrSpaceStart;
break;
+ }
- case 14:
- ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionStart;
- break;
+ case 9:
+ {
+ if (Handle != 0)
+ {
+ return KernelResult.InvalidHandle;
+ }
+
+ if (SubId != 0)
+ {
+ return KernelResult.InvalidCombination;
+ }
+
+ KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
+
+ if (CurrentProcess.ResourceLimit != null)
+ {
+ KHandleTable HandleTable = CurrentProcess.HandleTable;
+ KResourceLimit ResourceLimit = CurrentProcess.ResourceLimit;
+
+ KernelResult Result = HandleTable.GenerateHandle(ResourceLimit, out int ResLimHandle);
+
+ if (Result != KernelResult.Success)
+ {
+ return Result;
+ }
+
+ Value = (uint)ResLimHandle;
+ }
- case 15:
- ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionEnd -
- (ulong)Process.MemoryManager.NewMapRegionStart;
break;
+ }
+
+ case 10:
+ {
+ if (Handle != 0)
+ {
+ return KernelResult.InvalidHandle;
+ }
+
+ int CurrentCore = System.Scheduler.GetCurrentThread().CurrentCore;
+
+ if (SubId != -1 && SubId != CurrentCore)
+ {
+ return KernelResult.InvalidCombination;
+ }
+
+ Value = System.Scheduler.CoreContexts[CurrentCore].TotalIdleTimeTicks;
- case 16:
- ThreadState.X1 = (ulong)(Process.MetaData?.SystemResourceSize ?? 0);
break;
+ }
+
+ case 11:
+ {
+ if (Handle != 0)
+ {
+ return KernelResult.InvalidHandle;
+ }
+
+ if ((ulong)SubId > 3)
+ {
+ return KernelResult.InvalidCombination;
+ }
+
+ KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
+
+
+ Value = CurrentProcess.RandomEntropy[SubId];
- case 17:
- ThreadState.X1 = (ulong)Process.MemoryManager.PersonalMmHeapUsage;
break;
+ }
+
+ case 0xf0000002u:
+ {
+ if (SubId < -1 || SubId > 3)
+ {
+ return KernelResult.InvalidCombination;
+ }
+
+ KThread Thread = System.Scheduler.GetCurrentProcess().HandleTable.GetKThread(Handle);
+
+ if (Thread == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
+
+ KThread CurrentThread = System.Scheduler.GetCurrentThread();
+
+ int CurrentCore = CurrentThread.CurrentCore;
+
+ if (SubId != -1 && SubId != CurrentCore)
+ {
+ return KernelResult.Success;
+ }
- default:
- Process.PrintStackTrace(ThreadState);
+ KCoreContext CoreContext = System.Scheduler.CoreContexts[CurrentCore];
+
+ long TimeDelta = PerformanceCounter.ElapsedMilliseconds - CoreContext.LastContextSwitchTime;
+
+ if (SubId != -1)
+ {
+ Value = KTimeManager.ConvertMillisecondsToTicks(TimeDelta);
+ }
+ else
+ {
+ long TotalTimeRunning = Thread.TotalTimeRunning;
+
+ if (Thread == CurrentThread)
+ {
+ TotalTimeRunning += TimeDelta;
+ }
+
+ Value = KTimeManager.ConvertMillisecondsToTicks(TotalTimeRunning);
+ }
+
+ break;
+ }
- throw new NotImplementedException($"SvcGetInfo: {InfoType} 0x{Handle:x8} {InfoId}");
+ default: return KernelResult.InvalidEnumValue;
}
- ThreadState.X0 = 0;
+ return KernelResult.Success;
}
private void CreateEvent64(CpuThreadState State)
@@ -397,5 +587,241 @@ namespace Ryujinx.HLE.HOS.Kernel
return Result;
}
+
+ private void GetProcessList64(CpuThreadState State)
+ {
+ ulong Address = State.X1;
+ int MaxOut = (int)State.X2;
+
+ KernelResult Result = GetProcessList(Address, MaxOut, out int Count);
+
+ State.X0 = (ulong)Result;
+ State.X1 = (ulong)Count;
+ }
+
+ private KernelResult GetProcessList(ulong Address, int MaxCount, out int Count)
+ {
+ Count = 0;
+
+ if ((MaxCount >> 28) != 0)
+ {
+ return KernelResult.MaximumExceeded;
+ }
+
+ if (MaxCount != 0)
+ {
+ KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
+
+ ulong CopySize = (ulong)MaxCount * 8;
+
+ if (Address + CopySize <= Address)
+ {
+ return KernelResult.InvalidMemState;
+ }
+
+ if (CurrentProcess.MemoryManager.OutsideAddrSpace(Address, CopySize))
+ {
+ return KernelResult.InvalidMemState;
+ }
+ }
+
+ int CopyCount = 0;
+
+ lock (System.Processes)
+ {
+ foreach (KProcess Process in System.Processes.Values)
+ {
+ if (CopyCount < MaxCount)
+ {
+ if (!KernelTransfer.KernelToUserInt64(System, (long)Address + CopyCount * 8, Process.Pid))
+ {
+ return KernelResult.UserCopyFailed;
+ }
+ }
+
+ CopyCount++;
+ }
+ }
+
+ Count = CopyCount;
+
+ return KernelResult.Success;
+ }
+
+ private void GetSystemInfo64(CpuThreadState State)
+ {
+ uint Id = (uint)State.X1;
+ int Handle = (int)State.X2;
+ long SubId = (long)State.X3;
+
+ KernelResult Result = GetSystemInfo(Id, Handle, SubId, out long Value);
+
+ State.X0 = (ulong)Result;
+ State.X1 = (ulong)Value;
+ }
+
+ private KernelResult GetSystemInfo(uint Id, int Handle, long SubId, out long Value)
+ {
+ Value = 0;
+
+ if (Id > 2)
+ {
+ return KernelResult.InvalidEnumValue;
+ }
+
+ if (Handle != 0)
+ {
+ return KernelResult.InvalidHandle;
+ }
+
+ if (Id < 2)
+ {
+ if ((ulong)SubId > 3)
+ {
+ return KernelResult.InvalidCombination;
+ }
+
+ KMemoryRegionManager Region = System.MemoryRegions[SubId];
+
+ switch (Id)
+ {
+ //Memory region capacity.
+ case 0: Value = (long)Region.Size; break;
+
+ //Memory region free space.
+ case 1:
+ {
+ ulong FreePagesCount = Region.GetFreePages();
+
+ Value = (long)(FreePagesCount * KMemoryManager.PageSize);
+
+ break;
+ }
+ }
+ }
+ else /* if (Id == 2) */
+ {
+ if ((ulong)SubId > 1)
+ {
+ return KernelResult.InvalidCombination;
+ }
+
+ switch (SubId)
+ {
+ case 0: Value = System.PrivilegedProcessLowestId; break;
+ case 1: Value = System.PrivilegedProcessHighestId; break;
+ }
+ }
+
+ return KernelResult.Success;
+ }
+
+ private void CreatePort64(CpuThreadState State)
+ {
+ int MaxSessions = (int)State.X2;
+ bool IsLight = (State.X3 & 1) != 0;
+ long NameAddress = (long)State.X4;
+
+ KernelResult Result = CreatePort(
+ MaxSessions,
+ IsLight,
+ NameAddress,
+ out int ServerPortHandle,
+ out int ClientPortHandle);
+
+ State.X0 = (ulong)Result;
+ State.X1 = (ulong)ServerPortHandle;
+ State.X2 = (ulong)ClientPortHandle;
+ }
+
+ private KernelResult CreatePort(
+ int MaxSessions,
+ bool IsLight,
+ long NameAddress,
+ out int ServerPortHandle,
+ out int ClientPortHandle)
+ {
+ ServerPortHandle = ClientPortHandle = 0;
+
+ if (MaxSessions < 1)
+ {
+ return KernelResult.MaximumExceeded;
+ }
+
+ KPort Port = new KPort(System);
+
+ Port.Initialize(MaxSessions, IsLight, NameAddress);
+
+ KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
+
+ KernelResult Result = CurrentProcess.HandleTable.GenerateHandle(Port.ClientPort, out ClientPortHandle);
+
+ if (Result != KernelResult.Success)
+ {
+ return Result;
+ }
+
+ Result = CurrentProcess.HandleTable.GenerateHandle(Port.ServerPort, out ServerPortHandle);
+
+ if (Result != KernelResult.Success)
+ {
+ CurrentProcess.HandleTable.CloseHandle(ClientPortHandle);
+ }
+
+ return Result;
+ }
+
+ private void ManageNamedPort64(CpuThreadState State)
+ {
+ long NameAddress = (long)State.X1;
+ int MaxSessions = (int)State.X2;
+
+ KernelResult Result = ManageNamedPort(NameAddress, MaxSessions, out int Handle);
+
+ State.X0 = (ulong)Result;
+ State.X1 = (ulong)Handle;
+ }
+
+ private KernelResult ManageNamedPort(long NameAddress, int MaxSessions, out int Handle)
+ {
+ Handle = 0;
+
+ if (!KernelTransfer.UserToKernelString(System, NameAddress, 12, out string Name))
+ {
+ return KernelResult.UserCopyFailed;
+ }
+
+ if (MaxSessions < 0 || Name.Length > 11)
+ {
+ return KernelResult.MaximumExceeded;
+ }
+
+ if (MaxSessions == 0)
+ {
+ return KClientPort.RemoveName(System, Name);
+ }
+
+ KPort Port = new KPort(System);
+
+ KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
+
+ KernelResult Result = CurrentProcess.HandleTable.GenerateHandle(Port.ServerPort, out Handle);
+
+ if (Result != KernelResult.Success)
+ {
+ return Result;
+ }
+
+ Port.Initialize(MaxSessions, false, 0);
+
+ Result = Port.SetName(Name);
+
+ if (Result != KernelResult.Success)
+ {
+ CurrentProcess.HandleTable.CloseHandle(Handle);
+ }
+
+ return Result;
+ }
}
}