aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs273
1 files changed, 184 insertions, 89 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
index c1e7026b..5e32ca58 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
@@ -7,124 +7,223 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Memory;
using System;
+using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
class Syscall
{
- private readonly Switch _device;
private readonly KernelContext _context;
- public Syscall(Switch device, KernelContext context)
+ public Syscall(KernelContext context)
{
- _device = device;
_context = context;
}
- // IPC
+ // Process
- public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
+ public KernelResult GetProcessId(int handle, out long pid)
+ {
+ KProcess currentProcess = _context.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;
+ }
+
+ public KernelResult CreateProcess(
+ ProcessCreationInfo info,
+ ReadOnlySpan<int> capabilities,
+ out int handle,
+ IProcessContextFactory contextFactory,
+ ThreadStart customThreadStart = null)
{
handle = 0;
- if (!KernelTransfer.UserToKernelString(_context, namePtr, 12, out string name))
+ if ((info.Flags & ~ProcessCreationFlags.All) != 0)
{
- return KernelResult.UserCopyFailed;
+ return KernelResult.InvalidEnumValue;
}
- if (name.Length > 11)
+ // TODO: Address space check.
+
+ if ((info.Flags & ProcessCreationFlags.PoolPartitionMask) > ProcessCreationFlags.PoolPartitionSystemNonSecure)
{
- return KernelResult.MaximumExceeded;
+ return KernelResult.InvalidEnumValue;
}
- KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name);
+ if ((info.CodeAddress & 0x1fffff) != 0)
+ {
+ return KernelResult.InvalidAddress;
+ }
- if (!(autoObj is KClientPort clientPort))
+ if (info.CodePagesCount < 0 || info.SystemResourcePagesCount < 0)
{
- return KernelResult.NotFound;
+ return KernelResult.InvalidSize;
}
- KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
+ if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
+ !info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
+ {
+ return KernelResult.InvalidThread;
+ }
- KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
+ KHandleTable handleTable = _context.Scheduler.GetCurrentProcess().HandleTable;
- if (result != KernelResult.Success)
+ KProcess process = new KProcess(_context);
+
+ using var _ = new OnScopeExit(process.DecrementReferenceCount);
+
+ KResourceLimit resourceLimit;
+
+ if (info.ResourceLimitHandle != 0)
{
- return result;
+ resourceLimit = handleTable.GetObject<KResourceLimit>(info.ResourceLimitHandle);
+
+ if (resourceLimit == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
+ }
+ else
+ {
+ resourceLimit = _context.ResourceLimit;
}
- result = clientPort.Connect(out KClientSession clientSession);
+ MemoryRegion memRegion = (info.Flags & ProcessCreationFlags.PoolPartitionMask) switch
+ {
+ ProcessCreationFlags.PoolPartitionApplication => MemoryRegion.Application,
+ ProcessCreationFlags.PoolPartitionApplet => MemoryRegion.Applet,
+ ProcessCreationFlags.PoolPartitionSystem => MemoryRegion.Service,
+ ProcessCreationFlags.PoolPartitionSystemNonSecure => MemoryRegion.NvServices,
+ _ => MemoryRegion.NvServices
+ };
+
+ KernelResult result = process.Initialize(
+ info,
+ capabilities,
+ resourceLimit,
+ memRegion,
+ contextFactory,
+ customThreadStart);
if (result != KernelResult.Success)
{
- currentProcess.HandleTable.CancelHandleReservation(handle);
-
return result;
}
- currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
-
- clientSession.DecrementReferenceCount();
+ _context.Processes.TryAdd(process.Pid, process);
- return result;
+ return handleTable.GenerateHandle(process, out handle);
}
- public KernelResult SendSyncRequestHLE(int handle)
+ public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
{
- KProcess process = _context.Scheduler.GetCurrentProcess();
+ KProcess process = _context.Scheduler.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
- KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
+ if (process == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
- if (clientSession == null || clientSession.Service == null)
+ if ((uint)cpuCore >= KScheduler.CpuCoresCount || !process.IsCpuCoreAllowed(cpuCore))
{
- return SendSyncRequest(handle);
+ return KernelResult.InvalidCpuCore;
+ }
+
+ if ((uint)priority >= KScheduler.PrioritiesCount || !process.IsPriorityAllowed(priority))
+ {
+ return KernelResult.InvalidPriority;
+ }
+
+ process.DefaultCpuCore = cpuCore;
+
+ KernelResult result = process.Start(priority, mainThreadStackSize);
+
+ if (result != KernelResult.Success)
+ {
+ return result;
}
- return SendSyncRequestWithUserBufferHLE((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
+ process.IncrementReferenceCount();
+
+ return KernelResult.Success;
}
- public KernelResult SendSyncRequestWithUserBufferHLE(ulong messagePtr, ulong messageSize, int handle)
+ // IPC
+
+ public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
{
- KProcess process = _context.Scheduler.GetCurrentProcess();
+ handle = 0;
- byte[] messageData = new byte[messageSize];
+ if (!KernelTransfer.UserToKernelString(_context, namePtr, 12, out string name))
+ {
+ return KernelResult.UserCopyFailed;
+ }
- process.CpuMemory.Read(messagePtr, messageData);
+ return ConnectToNamedPort(name, out handle);
+ }
- KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
+ public KernelResult ConnectToNamedPort(string name, out int handle)
+ {
+ handle = 0;
- if (clientSession == null || clientSession.Service == null)
+ if (name.Length > 11)
{
- return SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
+ return KernelResult.MaximumExceeded;
}
- if (clientSession != null)
- {
- _context.CriticalSection.Enter();
+ KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name);
- KThread currentThread = _context.Scheduler.GetCurrentThread();
+ if (!(autoObj is KClientPort clientPort))
+ {
+ return KernelResult.NotFound;
+ }
- currentThread.SignaledObj = null;
- currentThread.ObjSyncResult = KernelResult.Success;
+ KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
- currentThread.Reschedule(ThreadSchedState.Paused);
+ KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
- clientSession.Service.Server.PushMessage(_device, currentThread, clientSession, messagePtr, messageSize);
+ if (result != KernelResult.Success)
+ {
+ return result;
+ }
- _context.CriticalSection.Leave();
+ result = clientPort.Connect(out KClientSession clientSession);
- return currentThread.ObjSyncResult;
- }
- else
+ if (result != KernelResult.Success)
{
- Logger.Warning?.Print(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
+ currentProcess.HandleTable.CancelHandleReservation(handle);
- return KernelResult.InvalidHandle;
+ return result;
}
+
+ currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
+
+ clientSession.DecrementReferenceCount();
+
+ return result;
}
- private KernelResult SendSyncRequest(int handle)
+ public KernelResult SendSyncRequest(int handle)
{
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
@@ -407,9 +506,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed;
}
- KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount];
+ return ReplyAndReceive(handles, replyTargetHandle, timeout, out handleIndex);
+ }
- for (int index = 0; index < handlesCount; index++)
+ public KernelResult ReplyAndReceive(ReadOnlySpan<int> handles, int replyTargetHandle, long timeout, out int handleIndex)
+ {
+ handleIndex = 0;
+
+ KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
+
+ KSynchronizationObject[] syncObjs = new KSynchronizationObject[handles.Length];
+
+ for (int index = 0; index < handles.Length; index++)
{
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
@@ -601,7 +709,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed;
}
- if (maxSessions < 0 || name.Length > 11)
+ if (name.Length > 11)
+ {
+ return KernelResult.MaximumExceeded;
+ }
+
+ return ManageNamedPort(name, maxSessions, out handle);
+ }
+
+ public KernelResult ManageNamedPort(string name, int maxSessions, out int handle)
+ {
+ handle = 0;
+
+ if (maxSessions < 0)
{
return KernelResult.MaximumExceeded;
}
@@ -826,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
- public KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
+ public KernelResult MapSharedMemory(int handle, ulong address, ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
{
@@ -843,7 +963,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemState;
}
- if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
+ if ((permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
{
return KernelResult.InvalidPermission;
}
@@ -912,7 +1032,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
currentProcess);
}
- public KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
+ public KernelResult CreateTransferMemory(ulong address, ulong size, KMemoryPermission permission, out int handle)
{
handle = 0;
@@ -931,7 +1051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemState;
}
- if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
+ if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write)
{
return KernelResult.InvalidPermission;
}
@@ -1119,7 +1239,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
}
- public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission)
+ public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, KMemoryPermission permission)
{
if (!PageAligned(src))
{
@@ -1131,10 +1251,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidSize;
}
- if (permission != MemoryPermission.None &&
- permission != MemoryPermission.Read &&
- permission != MemoryPermission.ReadAndWrite &&
- permission != MemoryPermission.ReadAndExecute)
+ if (permission != KMemoryPermission.None &&
+ permission != KMemoryPermission.Read &&
+ permission != KMemoryPermission.ReadAndWrite &&
+ permission != KMemoryPermission.ReadAndExecute)
{
return KernelResult.InvalidPermission;
}
@@ -1282,31 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _context.Scheduler.GetCurrentThread().Context.CntpctEl0;
}
- public KernelResult GetProcessId(int handle, out long pid)
- {
- KProcess currentProcess = _context.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;
- }
-
public void Break(ulong reason)
{
KThread currentThread = _context.Scheduler.GetCurrentThread();
@@ -1997,7 +2092,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidThread;
}
- MemoryManager memory = currentProcess.CpuMemory;
+ IVirtualMemoryManager memory = currentProcess.CpuMemory;
memory.Write(address + 0x0, thread.Context.GetX(0));
memory.Write(address + 0x8, thread.Context.GetX(1));