KBufferDescriptorTable.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. using Ryujinx.Common;
  2. using Ryujinx.HLE.HOS.Kernel.Common;
  3. using Ryujinx.HLE.HOS.Kernel.Memory;
  4. using System.Collections.Generic;
  5. namespace Ryujinx.HLE.HOS.Kernel.Ipc
  6. {
  7. class KBufferDescriptorTable
  8. {
  9. private const int MaxInternalBuffersCount = 8;
  10. private List<KBufferDescriptor> _sendBufferDescriptors;
  11. private List<KBufferDescriptor> _receiveBufferDescriptors;
  12. private List<KBufferDescriptor> _exchangeBufferDescriptors;
  13. public KBufferDescriptorTable()
  14. {
  15. _sendBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
  16. _receiveBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
  17. _exchangeBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
  18. }
  19. public KernelResult AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
  20. {
  21. return Add(_sendBufferDescriptors, src, dst, size, state);
  22. }
  23. public KernelResult AddReceiveBuffer(ulong src, ulong dst, ulong size, MemoryState state)
  24. {
  25. return Add(_receiveBufferDescriptors, src, dst, size, state);
  26. }
  27. public KernelResult AddExchangeBuffer(ulong src, ulong dst, ulong size, MemoryState state)
  28. {
  29. return Add(_exchangeBufferDescriptors, src, dst, size, state);
  30. }
  31. private KernelResult Add(List<KBufferDescriptor> list, ulong src, ulong dst, ulong size, MemoryState state)
  32. {
  33. if (list.Count < MaxInternalBuffersCount)
  34. {
  35. list.Add(new KBufferDescriptor(src, dst, size, state));
  36. return KernelResult.Success;
  37. }
  38. return KernelResult.OutOfMemory;
  39. }
  40. public KernelResult CopyBuffersToClient(KMemoryManager memoryManager)
  41. {
  42. KernelResult result = CopyToClient(memoryManager, _receiveBufferDescriptors);
  43. if (result != KernelResult.Success)
  44. {
  45. return result;
  46. }
  47. return CopyToClient(memoryManager, _exchangeBufferDescriptors);
  48. }
  49. private KernelResult CopyToClient(KMemoryManager memoryManager, List<KBufferDescriptor> list)
  50. {
  51. foreach (KBufferDescriptor desc in list)
  52. {
  53. MemoryState stateMask;
  54. switch (desc.State)
  55. {
  56. case MemoryState.IpcBuffer0: stateMask = MemoryState.IpcSendAllowedType0; break;
  57. case MemoryState.IpcBuffer1: stateMask = MemoryState.IpcSendAllowedType1; break;
  58. case MemoryState.IpcBuffer3: stateMask = MemoryState.IpcSendAllowedType3; break;
  59. default: return KernelResult.InvalidCombination;
  60. }
  61. MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
  62. if (desc.State == MemoryState.IpcBuffer0)
  63. {
  64. attributeMask |= MemoryAttribute.DeviceMapped;
  65. }
  66. ulong clientAddrTruncated = BitUtils.AlignDown(desc.ClientAddress, KMemoryManager.PageSize);
  67. ulong clientAddrRounded = BitUtils.AlignUp (desc.ClientAddress, KMemoryManager.PageSize);
  68. // Check if address is not aligned, in this case we need to perform 2 copies.
  69. if (clientAddrTruncated != clientAddrRounded)
  70. {
  71. ulong copySize = clientAddrRounded - desc.ClientAddress;
  72. if (copySize > desc.Size)
  73. {
  74. copySize = desc.Size;
  75. }
  76. KernelResult result = memoryManager.CopyDataFromCurrentProcess(
  77. desc.ClientAddress,
  78. copySize,
  79. stateMask,
  80. stateMask,
  81. MemoryPermission.ReadAndWrite,
  82. attributeMask,
  83. MemoryAttribute.None,
  84. desc.ServerAddress);
  85. if (result != KernelResult.Success)
  86. {
  87. return result;
  88. }
  89. }
  90. ulong clientEndAddr = desc.ClientAddress + desc.Size;
  91. ulong serverEndAddr = desc.ServerAddress + desc.Size;
  92. ulong clientEndAddrTruncated = BitUtils.AlignDown(clientEndAddr, KMemoryManager.PageSize);
  93. ulong clientEndAddrRounded = BitUtils.AlignUp (clientEndAddr, KMemoryManager.PageSize);
  94. ulong serverEndAddrTruncated = BitUtils.AlignDown(clientEndAddr, KMemoryManager.PageSize);
  95. if (clientEndAddrTruncated < clientAddrRounded)
  96. {
  97. KernelResult result = memoryManager.CopyDataToCurrentProcess(
  98. clientEndAddrTruncated,
  99. clientEndAddr - clientEndAddrTruncated,
  100. serverEndAddrTruncated,
  101. stateMask,
  102. stateMask,
  103. MemoryPermission.ReadAndWrite,
  104. attributeMask,
  105. MemoryAttribute.None);
  106. if (result != KernelResult.Success)
  107. {
  108. return result;
  109. }
  110. }
  111. }
  112. return KernelResult.Success;
  113. }
  114. public KernelResult UnmapServerBuffers(KMemoryManager memoryManager)
  115. {
  116. KernelResult result = UnmapServer(memoryManager, _sendBufferDescriptors);
  117. if (result != KernelResult.Success)
  118. {
  119. return result;
  120. }
  121. result = UnmapServer(memoryManager, _receiveBufferDescriptors);
  122. if (result != KernelResult.Success)
  123. {
  124. return result;
  125. }
  126. return UnmapServer(memoryManager, _exchangeBufferDescriptors);
  127. }
  128. private KernelResult UnmapServer(KMemoryManager memoryManager, List<KBufferDescriptor> list)
  129. {
  130. foreach (KBufferDescriptor descriptor in list)
  131. {
  132. KernelResult result = memoryManager.UnmapNoAttributeIfStateEquals(
  133. descriptor.ServerAddress,
  134. descriptor.Size,
  135. descriptor.State);
  136. if (result != KernelResult.Success)
  137. {
  138. return result;
  139. }
  140. }
  141. return KernelResult.Success;
  142. }
  143. public KernelResult RestoreClientBuffers(KMemoryManager memoryManager)
  144. {
  145. KernelResult result = RestoreClient(memoryManager, _sendBufferDescriptors);
  146. if (result != KernelResult.Success)
  147. {
  148. return result;
  149. }
  150. result = RestoreClient(memoryManager, _receiveBufferDescriptors);
  151. if (result != KernelResult.Success)
  152. {
  153. return result;
  154. }
  155. return RestoreClient(memoryManager, _exchangeBufferDescriptors);
  156. }
  157. private KernelResult RestoreClient(KMemoryManager memoryManager, List<KBufferDescriptor> list)
  158. {
  159. foreach (KBufferDescriptor descriptor in list)
  160. {
  161. KernelResult result = memoryManager.UnmapIpcRestorePermission(
  162. descriptor.ClientAddress,
  163. descriptor.Size,
  164. descriptor.State);
  165. if (result != KernelResult.Success)
  166. {
  167. return result;
  168. }
  169. }
  170. return KernelResult.Success;
  171. }
  172. }
  173. }