| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- 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 clientSession);
- if (result != KernelResult.Success)
- {
- currentProcess.HandleTable.CancelHandleReservation(handle);
- return result;
- }
- currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
- clientSession.DecrementReferenceCount();
- return result;
- }
- public KernelResult SendSyncRequest64(int handle)
- {
- return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.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 = _process.CpuMemory.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,
- _process.CpuMemory,
- ipcMessage.Thread,
- 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;
- }
- if (isLight)
- {
- KLightSession session = new KLightSession(_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();
- }
- else
- {
- KSession 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;
- }
- KAutoObject session;
- if (serverPort.IsLight)
- {
- session = serverPort.AcceptIncomingLightConnection();
- }
- else
- {
- session = 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;
- }
- public KernelResult ConnectToPort64(int clientPortHandle, out int clientSessionHandle)
- {
- return ConnectToPort(clientPortHandle, out clientSessionHandle);
- }
- private KernelResult ConnectToPort(int clientPortHandle, out int clientSessionHandle)
- {
- clientSessionHandle = 0;
- KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
- KClientPort clientPort = currentProcess.HandleTable.GetObject<KClientPort>(clientPortHandle);
- if (clientPort == null)
- {
- return KernelResult.InvalidHandle;
- }
- KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
- if (result != KernelResult.Success)
- {
- return result;
- }
- KAutoObject session;
- if (clientPort.IsLight)
- {
- result = clientPort.ConnectLight(out KLightClientSession clientSession);
- session = clientSession;
- }
- else
- {
- result = clientPort.Connect(out KClientSession clientSession);
- session = clientSession;
- }
- if (result != KernelResult.Success)
- {
- currentProcess.HandleTable.CancelHandleReservation(handle);
- return result;
- }
- currentProcess.HandleTable.SetReservedHandleObj(handle, session);
- session.DecrementReferenceCount();
- clientSessionHandle = handle;
- return result;
- }
- }
- }
|