| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- using Ryujinx.Common;
- using Ryujinx.Horizon.Common;
- using Ryujinx.Horizon.Sdk.Sf.Cmif;
- using Ryujinx.Horizon.Sdk.Sf.Hipc;
- using System;
- using System.Linq;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- namespace Ryujinx.Horizon.Sdk.Sf
- {
- class HipcCommandProcessor : ServerMessageProcessor
- {
- private readonly CommandArg[] _args;
- private readonly int[] _inOffsets;
- private readonly int[] _outOffsets;
- private readonly PointerAndSize[] _bufferRanges;
- private readonly bool _hasInProcessIdHolder;
- private readonly int _inObjectsCount;
- private readonly int _outObjectsCount;
- private readonly int _inMapAliasBuffersCount;
- private readonly int _outMapAliasBuffersCount;
- private readonly int _inPointerBuffersCount;
- private readonly int _outPointerBuffersCount;
- private readonly int _outFixedSizePointerBuffersCount;
- private readonly int _inMoveHandlesCount;
- private readonly int _inCopyHandlesCount;
- private readonly int _outMoveHandlesCount;
- private readonly int _outCopyHandlesCount;
- public int FunctionArgumentsCount => _args.Length;
- public int InRawDataSize => BitUtils.AlignUp(_inOffsets[^1], sizeof(ushort));
- public int OutRawDataSize => BitUtils.AlignUp(_outOffsets[^1], sizeof(uint));
- private int OutUnfixedSizePointerBuffersCount => _outPointerBuffersCount - _outFixedSizePointerBuffersCount;
- public HipcCommandProcessor(CommandArg[] args)
- {
- _args = args;
- for (int i = 0; i < args.Length; i++)
- {
- var argInfo = args[i];
- switch (argInfo.Type)
- {
- case CommandArgType.Buffer:
- var flags = argInfo.BufferFlags;
- if (flags.HasFlag(HipcBufferFlags.In))
- {
- if (flags.HasFlag(HipcBufferFlags.AutoSelect))
- {
- _inMapAliasBuffersCount++;
- _inPointerBuffersCount++;
- }
- else if (flags.HasFlag(HipcBufferFlags.MapAlias))
- {
- _inMapAliasBuffersCount++;
- }
- else if (flags.HasFlag(HipcBufferFlags.Pointer))
- {
- _inPointerBuffersCount++;
- }
- }
- else
- {
- bool autoSelect = flags.HasFlag(HipcBufferFlags.AutoSelect);
- if (autoSelect || flags.HasFlag(HipcBufferFlags.Pointer))
- {
- _outPointerBuffersCount++;
- if (flags.HasFlag(HipcBufferFlags.FixedSize))
- {
- _outFixedSizePointerBuffersCount++;
- }
- }
- if (autoSelect || flags.HasFlag(HipcBufferFlags.MapAlias))
- {
- _outMapAliasBuffersCount++;
- }
- }
- break;
- case CommandArgType.InCopyHandle:
- _inCopyHandlesCount++;
- break;
- case CommandArgType.InMoveHandle:
- _inMoveHandlesCount++;
- break;
- case CommandArgType.InObject:
- _inObjectsCount++;
- break;
- case CommandArgType.ProcessId:
- _hasInProcessIdHolder = true;
- break;
- case CommandArgType.OutCopyHandle:
- _outCopyHandlesCount++;
- break;
- case CommandArgType.OutMoveHandle:
- _outMoveHandlesCount++;
- break;
- case CommandArgType.OutObject:
- _outObjectsCount++;
- break;
- }
- }
- _inOffsets = RawDataOffsetCalculator.Calculate(args.Where(x => x.Type == CommandArgType.InArgument).ToArray());
- _outOffsets = RawDataOffsetCalculator.Calculate(args.Where(x => x.Type == CommandArgType.OutArgument).ToArray());
- _bufferRanges = new PointerAndSize[args.Length];
- }
- public int GetInArgOffset(int argIndex)
- {
- return _inOffsets[argIndex];
- }
- public int GetOutArgOffset(int argIndex)
- {
- return _outOffsets[argIndex];
- }
- public PointerAndSize GetBufferRange(int argIndex)
- {
- return _bufferRanges[argIndex];
- }
- public Result ProcessBuffers(ref ServiceDispatchContext context, bool[] isBufferMapAlias, ServerMessageRuntimeMetadata runtimeMetadata)
- {
- bool mapAliasBuffersValid = true;
- ulong pointerBufferTail = context.PointerBuffer.Address;
- ulong pointerBufferHead = pointerBufferTail + context.PointerBuffer.Size;
- int sendMapAliasIndex = 0;
- int recvMapAliasIndex = 0;
- int sendPointerIndex = 0;
- int unfixedRecvPointerIndex = 0;
- for (int i = 0; i < _args.Length; i++)
- {
- if (_args[i].Type != CommandArgType.Buffer)
- {
- continue;
- }
- var flags = _args[i].BufferFlags;
- bool isMapAlias;
- if (flags.HasFlag(HipcBufferFlags.MapAlias))
- {
- isMapAlias = true;
- }
- else if (flags.HasFlag(HipcBufferFlags.Pointer))
- {
- isMapAlias = false;
- }
- else /* if (flags.HasFlag(HipcBufferFlags.HipcAutoSelect)) */
- {
- var descriptor = flags.HasFlag(HipcBufferFlags.In)
- ? context.Request.Data.SendBuffers[sendMapAliasIndex]
- : context.Request.Data.ReceiveBuffers[recvMapAliasIndex];
- isMapAlias = descriptor.Address != 0UL;
- }
- isBufferMapAlias[i] = isMapAlias;
- if (isMapAlias)
- {
- var descriptor = flags.HasFlag(HipcBufferFlags.In)
- ? context.Request.Data.SendBuffers[sendMapAliasIndex++]
- : context.Request.Data.ReceiveBuffers[recvMapAliasIndex++];
- _bufferRanges[i] = new PointerAndSize(descriptor.Address, descriptor.Size);
- if (!IsMapTransferModeValid(flags, descriptor.Mode))
- {
- mapAliasBuffersValid = false;
- }
- }
- else
- {
- if (flags.HasFlag(HipcBufferFlags.In))
- {
- var descriptor = context.Request.Data.SendStatics[sendPointerIndex++];
- ulong address = descriptor.Address;
- ulong size = descriptor.Size;
- _bufferRanges[i] = new PointerAndSize(address, size);
- if (size != 0)
- {
- pointerBufferTail = Math.Max(pointerBufferTail, address + size);
- }
- }
- else /* if (flags.HasFlag(HipcBufferFlags.Out)) */
- {
- ulong size;
- if (flags.HasFlag(HipcBufferFlags.FixedSize))
- {
- size = _args[i].BufferFixedSize;
- }
- else
- {
- var data = MemoryMarshal.Cast<uint, byte>(context.Request.Data.DataWords);
- var recvPointerSizes = MemoryMarshal.Cast<byte, ushort>(data[runtimeMetadata.UnfixedOutPointerSizeOffset..]);
- size = recvPointerSizes[unfixedRecvPointerIndex++];
- }
- pointerBufferHead = BitUtils.AlignDown(pointerBufferHead - size, 0x10UL);
- _bufferRanges[i] = new PointerAndSize(pointerBufferHead, size);
- }
- }
- }
- if (!mapAliasBuffersValid)
- {
- return HipcResult.InvalidCmifRequest;
- }
- if (_outPointerBuffersCount != 0 && pointerBufferTail > pointerBufferHead)
- {
- return HipcResult.PointerBufferTooSmall;
- }
- return Result.Success;
- }
- private static bool IsMapTransferModeValid(HipcBufferFlags flags, HipcBufferMode mode)
- {
- if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
- {
- return mode == HipcBufferMode.NonSecure;
- }
- else if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
- {
- return mode == HipcBufferMode.NonDevice;
- }
- else
- {
- return mode == HipcBufferMode.Normal;
- }
- }
- public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias)
- {
- int recvPointerIndex = 0;
- for (int i = 0; i < _args.Length; i++)
- {
- if (_args[i].Type != CommandArgType.Buffer)
- {
- continue;
- }
- var flags = _args[i].BufferFlags;
- if (flags.HasFlag(HipcBufferFlags.Out))
- {
- var buffer = _bufferRanges[i];
- if (flags.HasFlag(HipcBufferFlags.Pointer))
- {
- response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
- }
- else if (flags.HasFlag(HipcBufferFlags.AutoSelect))
- {
- if (!isBufferMapAlias[i])
- {
- response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
- }
- else
- {
- response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(0UL, 0, recvPointerIndex);
- }
- }
- recvPointerIndex++;
- }
- }
- }
- public override void SetImplementationProcessor(ServerMessageProcessor impl)
- {
- // We don't need to do anything here as this should be always the last processor to be called.
- }
- public override ServerMessageRuntimeMetadata GetRuntimeMetadata()
- {
- return new ServerMessageRuntimeMetadata(
- (ushort)InRawDataSize,
- (ushort)OutRawDataSize,
- (byte)Unsafe.SizeOf<CmifInHeader>(),
- (byte)Unsafe.SizeOf<CmifOutHeader>(),
- (byte)_inObjectsCount,
- (byte)_outObjectsCount);
- }
- public override Result PrepareForProcess(ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata)
- {
- ref var meta = ref context.Request.Meta;
- bool requestValid = true;
- requestValid &= meta.SendPid == _hasInProcessIdHolder;
- requestValid &= meta.SendStaticsCount == _inPointerBuffersCount;
- requestValid &= meta.SendBuffersCount == _inMapAliasBuffersCount;
- requestValid &= meta.ReceiveBuffersCount == _outMapAliasBuffersCount;
- requestValid &= meta.ExchangeBuffersCount == 0;
- requestValid &= meta.CopyHandlesCount == _inCopyHandlesCount;
- requestValid &= meta.MoveHandlesCount == _inMoveHandlesCount;
- int rawSizeInBytes = meta.DataWordsCount * sizeof(uint);
- int commandRawSize = BitUtils.AlignUp(runtimeMetadata.UnfixedOutPointerSizeOffset + (OutUnfixedSizePointerBuffersCount * sizeof(ushort)), sizeof(uint));
- requestValid &= rawSizeInBytes >= commandRawSize;
- return requestValid ? Result.Success : HipcResult.InvalidCmifRequest;
- }
- public Result GetInObjects(ServerMessageProcessor processor, Span<IServiceObject> objects)
- {
- if (objects.Length == 0)
- {
- return Result.Success;
- }
- ServiceObjectHolder[] inObjects = new ServiceObjectHolder[objects.Length];
- Result result = processor.GetInObjects(inObjects);
- if (result.IsFailure)
- {
- return result;
- }
- int inObjectIndex = 0;
- for (int i = 0; i < _args.Length; i++)
- {
- if (_args[i].Type == CommandArgType.InObject)
- {
- int index = inObjectIndex++;
- var inObject = inObjects[index];
- objects[index] = inObject?.ServiceObject;
- }
- }
- return Result.Success;
- }
- public override Result GetInObjects(Span<ServiceObjectHolder> inObjects)
- {
- return SfResult.NotSupported;
- }
- public override HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
- {
- int rawDataSize = OutRawDataSize + runtimeMetadata.OutHeadersSize;
- var response = HipcMessage.WriteResponse(
- context.OutMessageBuffer,
- _outPointerBuffersCount,
- (BitUtils.AlignUp(rawDataSize, 4) + 0x10) / sizeof(uint),
- _outCopyHandlesCount,
- _outMoveHandlesCount + runtimeMetadata.OutObjectsCount);
- outRawData = MemoryMarshal.Cast<uint, byte>(response.DataWords);
- return response;
- }
- public override void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
- {
- int rawDataSize = runtimeMetadata.OutHeadersSize;
- var response = HipcMessage.WriteResponse(
- context.OutMessageBuffer,
- 0,
- (BitUtils.AlignUp(rawDataSize, 4) + 0x10) / sizeof(uint),
- 0,
- 0);
- outRawData = MemoryMarshal.Cast<uint, byte>(response.DataWords);
- }
- public void SetOutObjects(ref ServiceDispatchContext context, HipcMessageData response, Span<IServiceObject> objects)
- {
- if (objects.Length == 0)
- {
- return;
- }
- ServiceObjectHolder[] outObjects = new ServiceObjectHolder[objects.Length];
- for (int i = 0; i < objects.Length; i++)
- {
- outObjects[i] = objects[i] != null ? new ServiceObjectHolder(objects[i]) : null;
- }
- context.Processor.SetOutObjects(ref context, response, outObjects);
- }
- public override void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects)
- {
- for (int index = 0; index < _outObjectsCount; index++)
- {
- SetOutObjectImpl(index, response, context.Manager, outObjects[index]);
- }
- }
- private void SetOutObjectImpl(int index, HipcMessageData response, ServerSessionManager manager, ServiceObjectHolder obj)
- {
- if (obj == null)
- {
- response.MoveHandles[index] = 0;
- return;
- }
- Api.CreateSession(out int serverHandle, out int clientHandle).AbortOnFailure();
- manager.RegisterSession(serverHandle, obj).AbortOnFailure();
- response.MoveHandles[index] = clientHandle;
- }
- }
- }
|