aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Horizon/Sdk/ServiceUtil.cs')
-rw-r--r--src/Ryujinx.Horizon/Sdk/ServiceUtil.cs249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs b/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs
index ccd6c93a..5527c1e3 100644
--- a/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs
+++ b/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs
@@ -35,5 +35,254 @@ namespace Ryujinx.Horizon.Sdk
return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
}
+
+ public static Result SendRequest(
+ out CmifResponse response,
+ int sessionHandle,
+ uint requestId,
+ bool sendPid,
+ scoped ReadOnlySpan<byte> data,
+ ReadOnlySpan<HipcBufferFlags> bufferFlags,
+ ReadOnlySpan<PointerAndSize> buffers)
+ {
+ ulong tlsAddress = HorizonStatic.ThreadContext.TlsAddress;
+ int tlsSize = Api.TlsMessageBufferSize;
+
+ using (var tlsRegion = HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize))
+ {
+ CmifRequestFormat format = new()
+ {
+ DataSize = data.Length,
+ RequestId = requestId,
+ SendPid = sendPid,
+ };
+
+ for (int index = 0; index < bufferFlags.Length; index++)
+ {
+ FormatProcessBuffer(ref format, bufferFlags[index]);
+ }
+
+ CmifRequest request = CmifMessage.CreateRequest(tlsRegion.Memory.Span, format);
+
+ for (int index = 0; index < buffers.Length; index++)
+ {
+ RequestProcessBuffer(ref request, buffers[index], bufferFlags[index]);
+ }
+
+ data.CopyTo(request.Data);
+ }
+
+ Result result = HorizonStatic.Syscall.SendSyncRequest(sessionHandle);
+
+ if (result.IsFailure)
+ {
+ response = default;
+
+ return result;
+ }
+
+ return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
+ }
+
+ private static void FormatProcessBuffer(ref CmifRequestFormat format, HipcBufferFlags flags)
+ {
+ if (flags == 0)
+ {
+ return;
+ }
+
+ bool isIn = flags.HasFlag(HipcBufferFlags.In);
+ bool isOut = flags.HasFlag(HipcBufferFlags.Out);
+
+ if (flags.HasFlag(HipcBufferFlags.AutoSelect))
+ {
+ if (isIn)
+ {
+ format.InAutoBuffersCount++;
+ }
+
+ if (isOut)
+ {
+ format.OutAutoBuffersCount++;
+ }
+ }
+ else if (flags.HasFlag(HipcBufferFlags.Pointer))
+ {
+ if (isIn)
+ {
+ format.InPointersCount++;
+ }
+
+ if (isOut)
+ {
+ if (flags.HasFlag(HipcBufferFlags.FixedSize))
+ {
+ format.OutFixedPointersCount++;
+ }
+ else
+ {
+ format.OutPointersCount++;
+ }
+ }
+ }
+ else if (flags.HasFlag(HipcBufferFlags.MapAlias))
+ {
+ if (isIn && isOut)
+ {
+ format.InOutBuffersCount++;
+ }
+ else if (isIn)
+ {
+ format.InBuffersCount++;
+ }
+ else
+ {
+ format.OutBuffersCount++;
+ }
+ }
+ }
+
+ private static void RequestProcessBuffer(ref CmifRequest request, PointerAndSize buffer, HipcBufferFlags flags)
+ {
+ if (flags == 0)
+ {
+ return;
+ }
+
+ bool isIn = flags.HasFlag(HipcBufferFlags.In);
+ bool isOut = flags.HasFlag(HipcBufferFlags.Out);
+
+ if (flags.HasFlag(HipcBufferFlags.AutoSelect))
+ {
+ HipcBufferMode mode = HipcBufferMode.Normal;
+
+ if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
+ {
+ mode = HipcBufferMode.NonSecure;
+ }
+
+ if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
+ {
+ mode = HipcBufferMode.NonDevice;
+ }
+
+ if (isIn)
+ {
+ RequestInAutoBuffer(ref request, buffer.Address, buffer.Size, mode);
+ }
+
+ if (isOut)
+ {
+ RequestOutAutoBuffer(ref request, buffer.Address, buffer.Size, mode);
+ }
+ }
+ else if (flags.HasFlag(HipcBufferFlags.Pointer))
+ {
+ if (isIn)
+ {
+ RequestInPointer(ref request, buffer.Address, buffer.Size);
+ }
+
+ if (isOut)
+ {
+ if (flags.HasFlag(HipcBufferFlags.FixedSize))
+ {
+ RequestOutFixedPointer(ref request, buffer.Address, buffer.Size);
+ }
+ else
+ {
+ RequestOutPointer(ref request, buffer.Address, buffer.Size);
+ }
+ }
+ }
+ else if (flags.HasFlag(HipcBufferFlags.MapAlias))
+ {
+ HipcBufferMode mode = HipcBufferMode.Normal;
+
+ if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
+ {
+ mode = HipcBufferMode.NonSecure;
+ }
+
+ if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
+ {
+ mode = HipcBufferMode.NonDevice;
+ }
+
+ if (isIn && isOut)
+ {
+ RequestInOutBuffer(ref request, buffer.Address, buffer.Size, mode);
+ }
+ else if (isIn)
+ {
+ RequestInBuffer(ref request, buffer.Address, buffer.Size, mode);
+ }
+ else
+ {
+ RequestOutBuffer(ref request, buffer.Address, buffer.Size, mode);
+ }
+ }
+ }
+
+ private static void RequestInAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
+ {
+ if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize)
+ {
+ RequestInPointer(ref request, bufferAddress, bufferSize);
+ RequestInBuffer(ref request, 0UL, 0UL, mode);
+ }
+ else
+ {
+ RequestInPointer(ref request, 0UL, 0UL);
+ RequestInBuffer(ref request, bufferAddress, bufferSize, mode);
+ }
+ }
+
+ private static void RequestOutAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
+ {
+ if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize)
+ {
+ RequestOutPointer(ref request, bufferAddress, bufferSize);
+ RequestOutBuffer(ref request, 0UL, 0UL, mode);
+ }
+ else
+ {
+ RequestOutPointer(ref request, 0UL, 0UL);
+ RequestOutBuffer(ref request, bufferAddress, bufferSize, mode);
+ }
+ }
+
+ private static void RequestInBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
+ {
+ request.Hipc.SendBuffers[request.SendBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
+ }
+
+ private static void RequestOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
+ {
+ request.Hipc.ReceiveBuffers[request.RecvBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
+ }
+
+ private static void RequestInOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
+ {
+ request.Hipc.ExchangeBuffers[request.ExchBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
+ }
+
+ private static void RequestInPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
+ {
+ request.Hipc.SendStatics[request.SendStaticIndex++] = new HipcStaticDescriptor(bufferAddress, (ushort)bufferSize, request.CurrentInPointerId++);
+ request.ServerPointerSize -= (int)bufferSize;
+ }
+
+ private static void RequestOutFixedPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
+ {
+ request.Hipc.ReceiveList[request.RecvListIndex++] = new HipcReceiveListEntry(bufferAddress, (ushort)bufferSize);
+ request.ServerPointerSize -= (int)bufferSize;
+ }
+
+ private static void RequestOutPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
+ {
+ RequestOutFixedPointer(ref request, bufferAddress, bufferSize);
+ request.OutPointerSizes[request.OutPointerSizeIndex++] = (ushort)bufferSize;
+ }
}
}