CmifMessage.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using Ryujinx.Horizon.Common;
  2. using Ryujinx.Horizon.Sdk.Sf.Hipc;
  3. using System;
  4. using System.Runtime.CompilerServices;
  5. using System.Runtime.InteropServices;
  6. namespace Ryujinx.Horizon.Sdk.Sf.Cmif
  7. {
  8. static class CmifMessage
  9. {
  10. public const uint CmifInHeaderMagic = 0x49434653; // SFCI
  11. public const uint CmifOutHeaderMagic = 0x4f434653; // SFCO
  12. public static CmifRequest CreateRequest(Span<byte> output, CmifRequestFormat format)
  13. {
  14. int totalSize = 16;
  15. if (format.ObjectId != 0)
  16. {
  17. totalSize += Unsafe.SizeOf<CmifDomainInHeader>() + format.ObjectsCount * sizeof(int);
  18. }
  19. totalSize += Unsafe.SizeOf<CmifInHeader>() + format.DataSize;
  20. totalSize = (totalSize + 1) & ~1;
  21. int outPointerSizeTableOffset = totalSize;
  22. int outPointerSizeTableSize = format.OutAutoBuffersCount + format.OutPointersCount;
  23. totalSize += sizeof(ushort) * outPointerSizeTableSize;
  24. int rawDataSizeInWords = (totalSize + sizeof(uint) - 1) / sizeof(uint);
  25. CmifRequest request = new()
  26. {
  27. Hipc = HipcMessage.WriteMessage(output, new HipcMetadata()
  28. {
  29. Type = format.Context != 0 ? (int)CommandType.RequestWithContext : (int)CommandType.Request,
  30. SendStaticsCount = format.InAutoBuffersCount + format.InPointersCount,
  31. SendBuffersCount = format.InAutoBuffersCount + format.InBuffersCount,
  32. ReceiveBuffersCount = format.OutAutoBuffersCount + format.OutBuffersCount,
  33. ExchangeBuffersCount = format.InOutBuffersCount,
  34. DataWordsCount = rawDataSizeInWords,
  35. ReceiveStaticsCount = outPointerSizeTableSize + format.OutFixedPointersCount,
  36. SendPid = format.SendPid,
  37. CopyHandlesCount = format.HandlesCount,
  38. MoveHandlesCount = 0
  39. })
  40. };
  41. Span<uint> data = request.Hipc.DataWords;
  42. if (format.ObjectId != 0)
  43. {
  44. ref CmifDomainInHeader domainHeader = ref MemoryMarshal.Cast<uint, CmifDomainInHeader>(data)[0];
  45. int payloadSize = Unsafe.SizeOf<CmifInHeader>() + format.DataSize;
  46. domainHeader = new CmifDomainInHeader()
  47. {
  48. Type = CmifDomainRequestType.SendMessage,
  49. ObjectsCount = (byte)format.ObjectsCount,
  50. DataSize = (ushort)payloadSize,
  51. ObjectId = format.ObjectId,
  52. Padding = 0,
  53. Token = format.Context
  54. };
  55. data = data[(Unsafe.SizeOf<CmifDomainInHeader>() / sizeof(uint))..];
  56. request.Objects = data[((payloadSize + sizeof(uint) - 1) / sizeof(uint))..];
  57. }
  58. ref CmifInHeader header = ref MemoryMarshal.Cast<uint, CmifInHeader>(data)[0];
  59. header = new CmifInHeader()
  60. {
  61. Magic = CmifInHeaderMagic,
  62. Version = format.Context != 0 ? 1u : 0u,
  63. CommandId = format.RequestId,
  64. Token = format.ObjectId != 0 ? 0u : format.Context
  65. };
  66. request.Data = MemoryMarshal.Cast<uint, byte>(data)[Unsafe.SizeOf<CmifInHeader>()..];
  67. int paddingSizeBefore = (rawDataSizeInWords - request.Hipc.DataWords.Length) * sizeof(uint);
  68. Span<byte> outPointerTable = MemoryMarshal.Cast<uint, byte>(request.Hipc.DataWords)[(outPointerSizeTableOffset - paddingSizeBefore)..];
  69. request.OutPointerSizes = MemoryMarshal.Cast<byte, ushort>(outPointerTable);
  70. request.ServerPointerSize = format.ServerPointerSize;
  71. return request;
  72. }
  73. public static Result ParseResponse(out CmifResponse response, Span<byte> input, bool isDomain, int size)
  74. {
  75. HipcMessage responseMessage = new(input);
  76. Span<byte> data = MemoryMarshal.Cast<uint, byte>(responseMessage.Data.DataWords);
  77. Span<uint> objects = Span<uint>.Empty;
  78. if (isDomain)
  79. {
  80. data = data[Unsafe.SizeOf<CmifDomainOutHeader>()..];
  81. objects = MemoryMarshal.Cast<byte, uint>(data[(Unsafe.SizeOf<CmifOutHeader>() + size)..]);
  82. }
  83. CmifOutHeader header = MemoryMarshal.Cast<byte, CmifOutHeader>(data)[0];
  84. if (header.Magic != CmifOutHeaderMagic)
  85. {
  86. response = default;
  87. return SfResult.InvalidOutHeader;
  88. }
  89. if (header.Result.IsFailure)
  90. {
  91. response = default;
  92. return header.Result;
  93. }
  94. response = new CmifResponse()
  95. {
  96. Data = data[Unsafe.SizeOf<CmifOutHeader>()..],
  97. Objects = objects,
  98. CopyHandles = responseMessage.Data.CopyHandles,
  99. MoveHandles = responseMessage.Data.MoveHandles
  100. };
  101. return Result.Success;
  102. }
  103. }
  104. }