Move IPC related SVCs into a separate file, and logging on RegisterService (sm)
This commit is contained in:
parent
89e703302b
commit
6b9f4d38e4
4 changed files with 455 additions and 444 deletions
|
@ -1,10 +1,7 @@
|
|||
using ChocolArm64.Events;
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
|
@ -16,26 +13,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
private Horizon _system;
|
||||
private MemoryManager _memory;
|
||||
|
||||
private struct HleIpcMessage
|
||||
{
|
||||
public KThread Thread { get; private set; }
|
||||
public KClientSession Session { get; private set; }
|
||||
public IpcMessage Message { get; private set; }
|
||||
public long MessagePtr { get; private set; }
|
||||
|
||||
public HleIpcMessage(
|
||||
KThread thread,
|
||||
KClientSession session,
|
||||
IpcMessage message,
|
||||
long messagePtr)
|
||||
{
|
||||
Thread = thread;
|
||||
Session = session;
|
||||
Message = message;
|
||||
MessagePtr = messagePtr;
|
||||
}
|
||||
}
|
||||
|
||||
public SvcHandler(Switch device, KProcess process)
|
||||
{
|
||||
_device = device;
|
||||
|
|
452
Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs
Normal file
452
Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs
Normal file
|
@ -0,0 +1,452 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private struct HleIpcMessage
|
||||
{
|
||||
public KThread Thread { get; private set; }
|
||||
public KClientSession Session { get; private set; }
|
||||
public IpcMessage Message { get; private set; }
|
||||
public long MessagePtr { get; private set; }
|
||||
|
||||
public HleIpcMessage(
|
||||
KThread thread,
|
||||
KClientSession session,
|
||||
IpcMessage message,
|
||||
long messagePtr)
|
||||
{
|
||||
Thread = thread;
|
||||
Session = session;
|
||||
Message = message;
|
||||
MessagePtr = messagePtr;
|
||||
}
|
||||
}
|
||||
|
||||
public KernelResult ConnectToNamedPort64(ulong namePtr, out int handle)
|
||||
{
|
||||
return ConnectToNamedPort(namePtr, out handle);
|
||||
}
|
||||
|
||||
private KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name))
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
if (name.Length > 11)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
KAutoObject autoObj = KAutoObject.FindNamedObject(_system, name);
|
||||
|
||||
if (!(autoObj is KClientPort clientPort))
|
||||
{
|
||||
return KernelResult.NotFound;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = clientPort.Connect(out KClientSession session);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
currentProcess.HandleTable.CancelHandleReservation(handle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
currentProcess.HandleTable.SetReservedHandleObj(handle, session);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequest64(int handle)
|
||||
{
|
||||
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.ThreadState.Tpidr, 0x100, handle);
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle)
|
||||
{
|
||||
return SendSyncRequest(messagePtr, size, handle);
|
||||
}
|
||||
|
||||
private KernelResult SendSyncRequest(ulong messagePtr, ulong size, int handle)
|
||||
{
|
||||
byte[] messageData = _memory.ReadBytes((long)messagePtr, (long)size);
|
||||
|
||||
KClientSession clientSession = _process.HandleTable.GetObject<KClientSession>(handle);
|
||||
|
||||
if (clientSession == null || clientSession.Service == null)
|
||||
{
|
||||
return SendSyncRequest_(handle);
|
||||
}
|
||||
|
||||
if (clientSession != null)
|
||||
{
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = KernelResult.Success;
|
||||
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
IpcMessage message = new IpcMessage(messageData, (long)messagePtr);
|
||||
|
||||
ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
|
||||
currentThread,
|
||||
clientSession,
|
||||
message,
|
||||
(long)messagePtr));
|
||||
|
||||
_system.ThreadCounter.AddCount();
|
||||
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return currentThread.ObjSyncResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
|
||||
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessIpcRequest(object state)
|
||||
{
|
||||
HleIpcMessage ipcMessage = (HleIpcMessage)state;
|
||||
|
||||
ipcMessage.Thread.ObjSyncResult = IpcHandler.IpcCall(
|
||||
_device,
|
||||
_process,
|
||||
_memory,
|
||||
ipcMessage.Session,
|
||||
ipcMessage.Message,
|
||||
ipcMessage.MessagePtr);
|
||||
|
||||
_system.ThreadCounter.Signal();
|
||||
|
||||
ipcMessage.Thread.Reschedule(ThreadSchedState.Running);
|
||||
}
|
||||
|
||||
private KernelResult SendSyncRequest_(int handle)
|
||||
{
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KClientSession session = currentProcess.HandleTable.GetObject<KClientSession>(handle);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
return session.SendSyncRequest();
|
||||
}
|
||||
|
||||
public KernelResult CreateSession64(
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverSessionHandle,
|
||||
out int clientSessionHandle)
|
||||
{
|
||||
return CreateSession(isLight, namePtr, out serverSessionHandle, out clientSessionHandle);
|
||||
}
|
||||
|
||||
private KernelResult CreateSession(
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverSessionHandle,
|
||||
out int clientSessionHandle)
|
||||
{
|
||||
serverSessionHandle = 0;
|
||||
clientSessionHandle = 0;
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KResourceLimit resourceLimit = currentProcess.ResourceLimit;
|
||||
|
||||
KernelResult result = KernelResult.Success;
|
||||
|
||||
if (resourceLimit != null && !resourceLimit.Reserve(LimitableResource.Session, 1))
|
||||
{
|
||||
return KernelResult.ResLimitExceeded;
|
||||
}
|
||||
|
||||
KSession session;
|
||||
|
||||
if (isLight)
|
||||
{
|
||||
session = new KLightSession(_system);
|
||||
}
|
||||
else
|
||||
{
|
||||
session = new KSession(_system);
|
||||
}
|
||||
|
||||
result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
|
||||
|
||||
if (result == KernelResult.Success)
|
||||
{
|
||||
result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
currentProcess.HandleTable.CloseHandle(serverSessionHandle);
|
||||
|
||||
serverSessionHandle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
session.ServerSession.DecrementReferenceCount();
|
||||
session.ClientSession.DecrementReferenceCount();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult AcceptSession64(int portHandle, out int sessionHandle)
|
||||
{
|
||||
return AcceptSession(portHandle, out sessionHandle);
|
||||
}
|
||||
|
||||
private KernelResult AcceptSession(int portHandle, out int sessionHandle)
|
||||
{
|
||||
sessionHandle = 0;
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KServerPort serverPort = currentProcess.HandleTable.GetObject<KServerPort>(portHandle);
|
||||
|
||||
if (serverPort == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
KServerSession session = serverPort.IsLight
|
||||
? serverPort.AcceptLightIncomingConnection()
|
||||
: serverPort.AcceptIncomingConnection();
|
||||
|
||||
if (session != null)
|
||||
{
|
||||
currentProcess.HandleTable.SetReservedHandleObj(handle, session);
|
||||
|
||||
session.DecrementReferenceCount();
|
||||
|
||||
sessionHandle = handle;
|
||||
|
||||
result = KernelResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcess.HandleTable.CancelHandleReservation(handle);
|
||||
|
||||
result = KernelResult.NotFound;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult ReplyAndReceive64(
|
||||
ulong handlesPtr,
|
||||
int handlesCount,
|
||||
int replyTargetHandle,
|
||||
long timeout,
|
||||
out int handleIndex)
|
||||
{
|
||||
handleIndex = 0;
|
||||
|
||||
if ((uint)handlesCount > 0x40)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
ulong copySize = (ulong)((long)handlesCount * 4);
|
||||
|
||||
if (!currentProcess.MemoryManager.InsideAddrSpace(handlesPtr, copySize))
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
if (handlesPtr + copySize < handlesPtr)
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
int[] handles = new int[handlesCount];
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32Array(_system, handlesPtr, handles))
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount];
|
||||
|
||||
for (int index = 0; index < handlesCount; index++)
|
||||
{
|
||||
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
syncObjs[index] = obj;
|
||||
}
|
||||
|
||||
KernelResult result;
|
||||
|
||||
if (replyTargetHandle != 0)
|
||||
{
|
||||
KServerSession replyTarget = currentProcess.HandleTable.GetObject<KServerSession>(replyTargetHandle);
|
||||
|
||||
if (replyTarget == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
result = replyTarget.Reply();
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
while ((result = _system.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success)
|
||||
{
|
||||
KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((result = session.Receive()) != KernelResult.NotFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult CreatePort64(
|
||||
int maxSessions,
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverPortHandle,
|
||||
out int clientPortHandle)
|
||||
{
|
||||
return CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
|
||||
}
|
||||
|
||||
private KernelResult CreatePort(
|
||||
int maxSessions,
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverPortHandle,
|
||||
out int clientPortHandle)
|
||||
{
|
||||
serverPortHandle = clientPortHandle = 0;
|
||||
|
||||
if (maxSessions < 1)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
KPort port = new KPort(_system, maxSessions, isLight, (long)namePtr);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public KernelResult ManageNamedPort64(ulong namePtr, int maxSessions, out int handle)
|
||||
{
|
||||
return ManageNamedPort(namePtr, maxSessions, out handle);
|
||||
}
|
||||
|
||||
private KernelResult ManageNamedPort(ulong namePtr, int maxSessions, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if (!KernelTransfer.UserToKernelString(_system, namePtr, 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, maxSessions, false, 0);
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = port.ClientPort.SetName(name);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
currentProcess.HandleTable.CloseHandle(handle);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,11 @@ using ChocolArm64.Memory;
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
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 System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
|
@ -143,140 +141,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _system.Scheduler.GetCurrentThread().Context.ThreadState.CntpctEl0;
|
||||
}
|
||||
|
||||
public KernelResult ConnectToNamedPort64(ulong namePtr, out int handle)
|
||||
{
|
||||
return ConnectToNamedPort(namePtr, out handle);
|
||||
}
|
||||
|
||||
private KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name))
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
if (name.Length > 11)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
KAutoObject autoObj = KAutoObject.FindNamedObject(_system, name);
|
||||
|
||||
if (!(autoObj is KClientPort clientPort))
|
||||
{
|
||||
return KernelResult.NotFound;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = clientPort.Connect(out KClientSession session);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
currentProcess.HandleTable.CancelHandleReservation(handle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
currentProcess.HandleTable.SetReservedHandleObj(handle, session);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequest64(int handle)
|
||||
{
|
||||
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.ThreadState.Tpidr, 0x100, handle);
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle)
|
||||
{
|
||||
return SendSyncRequest(messagePtr, size, handle);
|
||||
}
|
||||
|
||||
private KernelResult SendSyncRequest(ulong messagePtr, ulong size, int handle)
|
||||
{
|
||||
byte[] messageData = _memory.ReadBytes((long)messagePtr, (long)size);
|
||||
|
||||
KClientSession clientSession = _process.HandleTable.GetObject<KClientSession>(handle);
|
||||
|
||||
if (clientSession == null || clientSession.Service == null)
|
||||
{
|
||||
return SendSyncRequest_(handle);
|
||||
}
|
||||
|
||||
if (clientSession != null)
|
||||
{
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = KernelResult.Success;
|
||||
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
IpcMessage message = new IpcMessage(messageData, (long)messagePtr);
|
||||
|
||||
ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
|
||||
currentThread,
|
||||
clientSession,
|
||||
message,
|
||||
(long)messagePtr));
|
||||
|
||||
_system.ThreadCounter.AddCount();
|
||||
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return currentThread.ObjSyncResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
|
||||
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessIpcRequest(object state)
|
||||
{
|
||||
HleIpcMessage ipcMessage = (HleIpcMessage)state;
|
||||
|
||||
ipcMessage.Thread.ObjSyncResult = IpcHandler.IpcCall(
|
||||
_device,
|
||||
_process,
|
||||
_memory,
|
||||
ipcMessage.Session,
|
||||
ipcMessage.Message,
|
||||
ipcMessage.MessagePtr);
|
||||
|
||||
_system.ThreadCounter.Signal();
|
||||
|
||||
ipcMessage.Thread.Reschedule(ThreadSchedState.Running);
|
||||
}
|
||||
|
||||
private KernelResult SendSyncRequest_(int handle)
|
||||
{
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KClientSession session = currentProcess.HandleTable.GetObject<KClientSession>(handle);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
return session.SendSyncRequest();
|
||||
}
|
||||
|
||||
public KernelResult GetProcessId64(int handle, out long pid)
|
||||
{
|
||||
return GetProcessId(handle, out pid);
|
||||
|
@ -573,201 +437,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult CreateSession64(
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverSessionHandle,
|
||||
out int clientSessionHandle)
|
||||
{
|
||||
return CreateSession(isLight, namePtr, out serverSessionHandle, out clientSessionHandle);
|
||||
}
|
||||
|
||||
private KernelResult CreateSession(
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverSessionHandle,
|
||||
out int clientSessionHandle)
|
||||
{
|
||||
serverSessionHandle = 0;
|
||||
clientSessionHandle = 0;
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KResourceLimit resourceLimit = currentProcess.ResourceLimit;
|
||||
|
||||
KernelResult result = KernelResult.Success;
|
||||
|
||||
if (resourceLimit != null && !resourceLimit.Reserve(LimitableResource.Session, 1))
|
||||
{
|
||||
return KernelResult.ResLimitExceeded;
|
||||
}
|
||||
|
||||
KSession session;
|
||||
|
||||
if (isLight)
|
||||
{
|
||||
session = new KLightSession(_system);
|
||||
}
|
||||
else
|
||||
{
|
||||
session = new KSession(_system);
|
||||
}
|
||||
|
||||
result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
|
||||
|
||||
if (result == KernelResult.Success)
|
||||
{
|
||||
result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
currentProcess.HandleTable.CloseHandle(serverSessionHandle);
|
||||
|
||||
serverSessionHandle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
session.ServerSession.DecrementReferenceCount();
|
||||
session.ClientSession.DecrementReferenceCount();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult AcceptSession64(int portHandle, out int sessionHandle)
|
||||
{
|
||||
return AcceptSession(portHandle, out sessionHandle);
|
||||
}
|
||||
|
||||
private KernelResult AcceptSession(int portHandle, out int sessionHandle)
|
||||
{
|
||||
sessionHandle = 0;
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KServerPort serverPort = currentProcess.HandleTable.GetObject<KServerPort>(portHandle);
|
||||
|
||||
if (serverPort == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
KServerSession session = serverPort.IsLight
|
||||
? serverPort.AcceptLightIncomingConnection()
|
||||
: serverPort.AcceptIncomingConnection();
|
||||
|
||||
if (session != null)
|
||||
{
|
||||
currentProcess.HandleTable.SetReservedHandleObj(handle, session);
|
||||
|
||||
session.DecrementReferenceCount();
|
||||
|
||||
sessionHandle = handle;
|
||||
|
||||
result = KernelResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentProcess.HandleTable.CancelHandleReservation(handle);
|
||||
|
||||
result = KernelResult.NotFound;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult ReplyAndReceive64(
|
||||
ulong handlesPtr,
|
||||
int handlesCount,
|
||||
int replyTargetHandle,
|
||||
long timeout,
|
||||
out int handleIndex)
|
||||
{
|
||||
handleIndex = 0;
|
||||
|
||||
if ((uint)handlesCount > 0x40)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
ulong copySize = (ulong)((long)handlesCount * 4);
|
||||
|
||||
if (!currentProcess.MemoryManager.InsideAddrSpace(handlesPtr, copySize))
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
if (handlesPtr + copySize < handlesPtr)
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
int[] handles = new int[handlesCount];
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32Array(_system, handlesPtr, handles))
|
||||
{
|
||||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount];
|
||||
|
||||
for (int index = 0; index < handlesCount; index++)
|
||||
{
|
||||
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
syncObjs[index] = obj;
|
||||
}
|
||||
|
||||
KernelResult result;
|
||||
|
||||
if (replyTargetHandle != 0)
|
||||
{
|
||||
KServerSession replyTarget = currentProcess.HandleTable.GetObject<KServerSession>(replyTargetHandle);
|
||||
|
||||
if (replyTarget == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
result = replyTarget.Reply();
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
while ((result = _system.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success)
|
||||
{
|
||||
KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((result = session.Receive()) != KernelResult.NotFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult CreateEvent64(out int wEventHandle, out int rEventHandle)
|
||||
{
|
||||
return CreateEvent(out wEventHandle, out rEventHandle);
|
||||
|
@ -910,95 +579,5 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult CreatePort64(
|
||||
int maxSessions,
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverPortHandle,
|
||||
out int clientPortHandle)
|
||||
{
|
||||
return CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
|
||||
}
|
||||
|
||||
private KernelResult CreatePort(
|
||||
int maxSessions,
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverPortHandle,
|
||||
out int clientPortHandle)
|
||||
{
|
||||
serverPortHandle = clientPortHandle = 0;
|
||||
|
||||
if (maxSessions < 1)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
KPort port = new KPort(_system, maxSessions, isLight, (long)namePtr);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public KernelResult ManageNamedPort64(ulong namePtr, int maxSessions, out int handle)
|
||||
{
|
||||
return ManageNamedPort(namePtr, maxSessions, out handle);
|
||||
}
|
||||
|
||||
private KernelResult ManageNamedPort(ulong namePtr, int maxSessions, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if (!KernelTransfer.UserToKernelString(_system, namePtr, 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, maxSessions, false, 0);
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = port.ClientPort.SetName(name);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
currentProcess.HandleTable.CloseHandle(handle);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
|
@ -108,6 +109,8 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||
return ErrorCode.MakeError(ErrorModule.Sm, SmErr.InvalidName);
|
||||
}
|
||||
|
||||
Logger.PrintInfo(LogClass.ServiceSm, $"Register \"{name}\".");
|
||||
|
||||
KPort port = new KPort(context.Device.System, maxSessions, isLight, 0);
|
||||
|
||||
if (!_registeredServices.TryAdd(name, port))
|
||||
|
|
Loading…
Add table
Reference in a new issue