2023-01-04 22:15:45 +00:00
|
|
|
using Ryujinx.Horizon.Common;
|
|
|
|
using Ryujinx.Horizon.Sdk.Sf.Cmif;
|
|
|
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
|
|
|
using System;
|
|
|
|
|
|
|
|
namespace Ryujinx.Horizon.Sdk
|
|
|
|
{
|
|
|
|
static class ServiceUtil
|
|
|
|
{
|
|
|
|
public static Result SendRequest(out CmifResponse response, int sessionHandle, uint requestId, bool sendPid, scoped ReadOnlySpan<byte> data)
|
|
|
|
{
|
|
|
|
ulong tlsAddress = HorizonStatic.ThreadContext.TlsAddress;
|
2023-07-01 11:42:10 +01:00
|
|
|
int tlsSize = Api.TlsMessageBufferSize;
|
2023-01-04 22:15:45 +00:00
|
|
|
|
|
|
|
using (var tlsRegion = HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize))
|
|
|
|
{
|
2023-07-01 11:42:10 +01:00
|
|
|
CmifRequest request = CmifMessage.CreateRequest(tlsRegion.Memory.Span, new CmifRequestFormat
|
2023-01-04 22:15:45 +00:00
|
|
|
{
|
2023-07-01 11:42:10 +01:00
|
|
|
DataSize = data.Length,
|
2023-01-04 22:15:45 +00:00
|
|
|
RequestId = requestId,
|
2023-07-01 11:42:10 +01:00
|
|
|
SendPid = sendPid,
|
2023-01-04 22:15:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
data.CopyTo(request.Data);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result result = HorizonStatic.Syscall.SendSyncRequest(sessionHandle);
|
|
|
|
|
|
|
|
if (result.IsFailure)
|
|
|
|
{
|
|
|
|
response = default;
|
2023-01-08 12:13:39 +00:00
|
|
|
|
2023-01-04 22:15:45 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
|
|
|
|
}
|
2024-01-25 22:06:53 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2023-01-04 22:15:45 +00:00
|
|
|
}
|
2023-07-01 11:42:10 +01:00
|
|
|
}
|