| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- using Ryujinx.Common.Logging;
- using Ryujinx.Horizon.Common;
- using Ryujinx.Horizon.Sdk.OsTypes;
- using Ryujinx.Horizon.Sdk.Sf.Cmif;
- using Ryujinx.Horizon.Sdk.Sm;
- using System;
- using System.Runtime.InteropServices;
- namespace Ryujinx.Horizon.Sdk.Sf.Hipc
- {
- class ServerSessionManager
- {
- public Result AcceptSession(int portHandle, ServiceObjectHolder obj)
- {
- return AcceptSession(out _, portHandle, obj);
- }
- private Result AcceptSession(out ServerSession session, int portHandle, ServiceObjectHolder obj)
- {
- return AcceptSessionImpl(out session, portHandle, obj);
- }
- private Result AcceptSessionImpl(out ServerSession session, int portHandle, ServiceObjectHolder obj)
- {
- session = null;
- Result result = HorizonStatic.Syscall.AcceptSession(out int sessionHandle, portHandle);
- if (result.IsFailure)
- {
- return result;
- }
- bool succeeded = false;
- try
- {
- result = RegisterSessionImpl(out session, sessionHandle, obj);
- if (result.IsFailure)
- {
- return result;
- }
- succeeded = true;
- }
- finally
- {
- if (!succeeded)
- {
- HorizonStatic.Syscall.CloseHandle(sessionHandle);
- }
- }
- return Result.Success;
- }
- public Result RegisterSession(int sessionHandle, ServiceObjectHolder obj)
- {
- return RegisterSession(out _, sessionHandle, obj);
- }
- public Result RegisterSession(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
- {
- return RegisterSessionImpl(out session, sessionHandle, obj);
- }
- private Result RegisterSessionImpl(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
- {
- Result result = CreateSessionImpl(out session, sessionHandle, obj);
- if (result.IsFailure)
- {
- return result;
- }
- session.PointerBuffer = GetSessionPointerBuffer(session);
- session.SavedMessage = GetSessionSavedMessageBuffer(session);
- RegisterSessionToWaitList(session);
- return Result.Success;
- }
- protected virtual void RegisterSessionToWaitList(ServerSession session)
- {
- throw new NotSupportedException();
- }
- private Result CreateSessionImpl(out ServerSession session, int sessionHandle, ServiceObjectHolder obj)
- {
- session = AllocateSession(sessionHandle, obj);
- if (session == null)
- {
- return HipcResult.OutOfSessionMemory;
- }
- return Result.Success;
- }
- protected virtual ServerSession AllocateSession(int sessionHandle, ServiceObjectHolder obj)
- {
- throw new NotSupportedException();
- }
- protected virtual void FreeSession(ServerSession session)
- {
- throw new NotSupportedException();
- }
- protected virtual Server AllocateServer(
- int portIndex,
- int portHandle,
- ServiceName name,
- bool managed,
- ServiceObjectHolder staticHoder)
- {
- throw new NotSupportedException();
- }
- protected virtual void DestroyServer(Server server)
- {
- throw new NotSupportedException();
- }
- protected virtual PointerAndSize GetSessionPointerBuffer(ServerSession session)
- {
- throw new NotSupportedException();
- }
- protected virtual PointerAndSize GetSessionSavedMessageBuffer(ServerSession session)
- {
- throw new NotSupportedException();
- }
- private void DestroySession(ServerSession session)
- {
- FreeSession(session);
- }
- protected void CloseSessionImpl(ServerSession session)
- {
- int sessionHandle = session.Handle;
- Os.FinalizeMultiWaitHolder(session);
- DestroySession(session);
- HorizonStatic.Syscall.CloseHandle(sessionHandle).AbortOnFailure();
- }
- private static CommandType GetCmifCommandType(ReadOnlySpan<byte> message)
- {
- return MemoryMarshal.Cast<byte, Header>(message)[0].Type;
- }
- public Result ProcessRequest(ServerSession session, Span<byte> message)
- {
- if (session.IsClosed || GetCmifCommandType(message) == CommandType.Close)
- {
- CloseSessionImpl(session);
- return Result.Success;
- }
- else
- {
- Result result = ProcessRequestImpl(session, message, message);
- if (result.IsSuccess)
- {
- RegisterSessionToWaitList(session);
- return Result.Success;
- }
- else if (SfResult.RequestContextChanged(result))
- {
- return result;
- }
- else
- {
- Logger.Warning?.Print(LogClass.KernelIpc, $"Request processing returned error {result}");
- CloseSessionImpl(session);
- return Result.Success;
- }
- }
- }
- private Result ProcessRequestImpl(ServerSession session, Span<byte> inMessage, Span<byte> outMessage)
- {
- CommandType commandType = GetCmifCommandType(inMessage);
- using var _ = new ScopedInlineContextChange(GetInlineContext(commandType, inMessage));
- switch (commandType)
- {
- case CommandType.Request:
- case CommandType.RequestWithContext:
- return DispatchRequest(session.ServiceObjectHolder, session, inMessage, outMessage);
- case CommandType.Control:
- case CommandType.ControlWithContext:
- return DispatchManagerRequest(session, inMessage, outMessage);
- default:
- return HipcResult.UnknownCommandType;
- }
- }
- private static int GetInlineContext(CommandType commandType, ReadOnlySpan<byte> inMessage)
- {
- switch (commandType)
- {
- case CommandType.RequestWithContext:
- case CommandType.ControlWithContext:
- if (inMessage.Length >= 0x10)
- {
- return MemoryMarshal.Cast<byte, int>(inMessage)[3];
- }
- break;
- }
- return 0;
- }
- protected Result ReceiveRequest(ServerSession session, Span<byte> message)
- {
- return ReceiveRequestImpl(session, message);
- }
- private Result ReceiveRequestImpl(ServerSession session, Span<byte> message)
- {
- PointerAndSize pointerBuffer = session.PointerBuffer;
- while (true)
- {
- if (pointerBuffer.Address != 0)
- {
- HipcMessageData messageData = HipcMessage.WriteMessage(message, new HipcMetadata()
- {
- Type = (int)CommandType.Invalid,
- ReceiveStaticsCount = HipcMessage.AutoReceiveStatic
- });
- messageData.ReceiveList[0] = new HipcReceiveListEntry(pointerBuffer.Address, pointerBuffer.Size);
- }
- else
- {
- MemoryMarshal.Cast<byte, Header>(message)[0] = new Header()
- {
- Type = CommandType.Invalid
- };
- }
- Result result = Api.Receive(out ReceiveResult recvResult, session.Handle, message);
- if (result.IsFailure)
- {
- return result;
- }
- switch (recvResult)
- {
- case ReceiveResult.Success:
- session.IsClosed = false;
- return Result.Success;
- case ReceiveResult.Closed:
- session.IsClosed = true;
- return Result.Success;
- }
- }
- }
- protected virtual Result DispatchManagerRequest(ServerSession session, Span<byte> inMessage, Span<byte> outMessage)
- {
- return SfResult.NotSupported;
- }
- protected virtual Result DispatchRequest(
- ServiceObjectHolder objectHolder,
- ServerSession session,
- Span<byte> inMessage,
- Span<byte> outMessage)
- {
- HipcMessage request;
- try
- {
- request = new HipcMessage(inMessage);
- }
- catch (ArgumentOutOfRangeException)
- {
- return HipcResult.InvalidRequestSize;
- }
- var dispatchCtx = new ServiceDispatchContext()
- {
- ServiceObject = objectHolder.ServiceObject,
- Manager = this,
- Session = session,
- HandlesToClose = new HandlesToClose(),
- PointerBuffer = session.PointerBuffer,
- InMessageBuffer = inMessage,
- OutMessageBuffer = outMessage,
- Request = request
- };
- ReadOnlySpan<byte> inRawData = MemoryMarshal.Cast<uint, byte>(dispatchCtx.Request.Data.DataWords);
- int inRawSize = dispatchCtx.Request.Meta.DataWordsCount * sizeof(uint);
- if (inRawSize < 0x10)
- {
- return HipcResult.InvalidRequestSize;
- }
- Result result = objectHolder.ProcessMessage(ref dispatchCtx, inRawData);
- if (result.IsFailure)
- {
- return result;
- }
- result = Api.Reply(session.SessionHandle, outMessage);
- ref var handlesToClose = ref dispatchCtx.HandlesToClose;
- for (int i = 0; i < handlesToClose.Count; i++)
- {
- HorizonStatic.Syscall.CloseHandle(handlesToClose[i]).AbortOnFailure();
- }
- return result;
- }
- public ServerSessionManager GetSessionManagerByTag(uint tag)
- {
- // Official FW does not do anything with the tag currently.
- return this;
- }
- }
- }
|