KProcessCapabilities.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. using Ryujinx.HLE.HOS.Kernel.Common;
  2. using Ryujinx.HLE.HOS.Kernel.Memory;
  3. using Ryujinx.HLE.HOS.Kernel.Threading;
  4. using System;
  5. using System.Numerics;
  6. namespace Ryujinx.HLE.HOS.Kernel.Process
  7. {
  8. class KProcessCapabilities
  9. {
  10. public byte[] SvcAccessMask { get; private set; }
  11. public byte[] IrqAccessMask { get; private set; }
  12. public ulong AllowedCpuCoresMask { get; private set; }
  13. public ulong AllowedThreadPriosMask { get; private set; }
  14. public int DebuggingFlags { get; private set; }
  15. public int HandleTableSize { get; private set; }
  16. public int KernelReleaseVersion { get; private set; }
  17. public int ApplicationType { get; private set; }
  18. public KProcessCapabilities()
  19. {
  20. SvcAccessMask = new byte[0x10];
  21. IrqAccessMask = new byte[0x80];
  22. }
  23. public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
  24. {
  25. AllowedCpuCoresMask = 0xf;
  26. AllowedThreadPriosMask = ulong.MaxValue;
  27. DebuggingFlags &= ~3;
  28. KernelReleaseVersion = KProcess.KernelVersionPacked;
  29. return Parse(capabilities, memoryManager);
  30. }
  31. public KernelResult InitializeForUser(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
  32. {
  33. return Parse(capabilities, memoryManager);
  34. }
  35. private KernelResult Parse(ReadOnlySpan<int> capabilities, KPageTableBase memoryManager)
  36. {
  37. int mask0 = 0;
  38. int mask1 = 0;
  39. for (int index = 0; index < capabilities.Length; index++)
  40. {
  41. int cap = capabilities[index];
  42. if (((cap + 1) & ~cap) != 0x40)
  43. {
  44. KernelResult result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
  45. if (result != KernelResult.Success)
  46. {
  47. return result;
  48. }
  49. }
  50. else
  51. {
  52. if ((uint)index + 1 >= capabilities.Length)
  53. {
  54. return KernelResult.InvalidCombination;
  55. }
  56. int prevCap = cap;
  57. cap = capabilities[++index];
  58. if (((cap + 1) & ~cap) != 0x40)
  59. {
  60. return KernelResult.InvalidCombination;
  61. }
  62. if ((cap & 0x78000000) != 0)
  63. {
  64. return KernelResult.MaximumExceeded;
  65. }
  66. if ((cap & 0x7ffff80) == 0)
  67. {
  68. return KernelResult.InvalidSize;
  69. }
  70. long address = ((long)(uint)prevCap << 5) & 0xffffff000;
  71. long size = ((long)(uint)cap << 5) & 0xfffff000;
  72. if (((ulong)(address + size - 1) >> 36) != 0)
  73. {
  74. return KernelResult.InvalidAddress;
  75. }
  76. KMemoryPermission perm = (prevCap >> 31) != 0
  77. ? KMemoryPermission.Read
  78. : KMemoryPermission.ReadAndWrite;
  79. KernelResult result;
  80. if ((cap >> 31) != 0)
  81. {
  82. result = memoryManager.MapNormalMemory(address, size, perm);
  83. }
  84. else
  85. {
  86. result = memoryManager.MapIoMemory(address, size, perm);
  87. }
  88. if (result != KernelResult.Success)
  89. {
  90. return result;
  91. }
  92. }
  93. }
  94. return KernelResult.Success;
  95. }
  96. private KernelResult ParseCapability(int cap, ref int mask0, ref int mask1, KPageTableBase memoryManager)
  97. {
  98. int code = (cap + 1) & ~cap;
  99. if (code == 1)
  100. {
  101. return KernelResult.InvalidCapability;
  102. }
  103. else if (code == 0)
  104. {
  105. return KernelResult.Success;
  106. }
  107. int codeMask = 1 << (32 - BitOperations.LeadingZeroCount((uint)code + 1));
  108. // Check if the property was already set.
  109. if (((mask0 & codeMask) & 0x1e008) != 0)
  110. {
  111. return KernelResult.InvalidCombination;
  112. }
  113. mask0 |= codeMask;
  114. switch (code)
  115. {
  116. case 8:
  117. {
  118. if (AllowedCpuCoresMask != 0 || AllowedThreadPriosMask != 0)
  119. {
  120. return KernelResult.InvalidCapability;
  121. }
  122. int lowestCpuCore = (cap >> 16) & 0xff;
  123. int highestCpuCore = (cap >> 24) & 0xff;
  124. if (lowestCpuCore > highestCpuCore)
  125. {
  126. return KernelResult.InvalidCombination;
  127. }
  128. int highestThreadPrio = (cap >> 4) & 0x3f;
  129. int lowestThreadPrio = (cap >> 10) & 0x3f;
  130. if (lowestThreadPrio > highestThreadPrio)
  131. {
  132. return KernelResult.InvalidCombination;
  133. }
  134. if (highestCpuCore >= KScheduler.CpuCoresCount)
  135. {
  136. return KernelResult.InvalidCpuCore;
  137. }
  138. AllowedCpuCoresMask = GetMaskFromMinMax(lowestCpuCore, highestCpuCore);
  139. AllowedThreadPriosMask = GetMaskFromMinMax(lowestThreadPrio, highestThreadPrio);
  140. break;
  141. }
  142. case 0x10:
  143. {
  144. int slot = (cap >> 29) & 7;
  145. int svcSlotMask = 1 << slot;
  146. if ((mask1 & svcSlotMask) != 0)
  147. {
  148. return KernelResult.InvalidCombination;
  149. }
  150. mask1 |= svcSlotMask;
  151. int svcMask = (cap >> 5) & 0xffffff;
  152. int baseSvc = slot * 24;
  153. for (int index = 0; index < 24; index++)
  154. {
  155. if (((svcMask >> index) & 1) == 0)
  156. {
  157. continue;
  158. }
  159. int svcId = baseSvc + index;
  160. if (svcId > 0x7f)
  161. {
  162. return KernelResult.MaximumExceeded;
  163. }
  164. SvcAccessMask[svcId / 8] |= (byte)(1 << (svcId & 7));
  165. }
  166. break;
  167. }
  168. case 0x80:
  169. {
  170. long address = ((long)(uint)cap << 4) & 0xffffff000;
  171. memoryManager.MapIoMemory(address, KPageTableBase.PageSize, KMemoryPermission.ReadAndWrite);
  172. break;
  173. }
  174. case 0x800:
  175. {
  176. // TODO: GIC distributor check.
  177. int irq0 = (cap >> 12) & 0x3ff;
  178. int irq1 = (cap >> 22) & 0x3ff;
  179. if (irq0 != 0x3ff)
  180. {
  181. IrqAccessMask[irq0 / 8] |= (byte)(1 << (irq0 & 7));
  182. }
  183. if (irq1 != 0x3ff)
  184. {
  185. IrqAccessMask[irq1 / 8] |= (byte)(1 << (irq1 & 7));
  186. }
  187. break;
  188. }
  189. case 0x2000:
  190. {
  191. int applicationType = cap >> 14;
  192. if ((uint)applicationType > 7)
  193. {
  194. return KernelResult.ReservedValue;
  195. }
  196. ApplicationType = applicationType;
  197. break;
  198. }
  199. case 0x4000:
  200. {
  201. // Note: This check is bugged on kernel too, we are just replicating the bug here.
  202. if ((KernelReleaseVersion >> 17) != 0 || cap < 0x80000)
  203. {
  204. return KernelResult.ReservedValue;
  205. }
  206. KernelReleaseVersion = cap;
  207. break;
  208. }
  209. case 0x8000:
  210. {
  211. int handleTableSize = cap >> 26;
  212. if ((uint)handleTableSize > 0x3ff)
  213. {
  214. return KernelResult.ReservedValue;
  215. }
  216. HandleTableSize = handleTableSize;
  217. break;
  218. }
  219. case 0x10000:
  220. {
  221. int debuggingFlags = cap >> 19;
  222. if ((uint)debuggingFlags > 3)
  223. {
  224. return KernelResult.ReservedValue;
  225. }
  226. DebuggingFlags &= ~3;
  227. DebuggingFlags |= debuggingFlags;
  228. break;
  229. }
  230. default: return KernelResult.InvalidCapability;
  231. }
  232. return KernelResult.Success;
  233. }
  234. private static ulong GetMaskFromMinMax(int min, int max)
  235. {
  236. int range = max - min + 1;
  237. if (range == 64)
  238. {
  239. return ulong.MaxValue;
  240. }
  241. ulong mask = (1UL << range) - 1;
  242. return mask << min;
  243. }
  244. }
  245. }