SvcMemory.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. using ChocolArm64.State;
  2. using Ryujinx.Common.Logging;
  3. using static Ryujinx.HLE.HOS.ErrorCode;
  4. namespace Ryujinx.HLE.HOS.Kernel
  5. {
  6. partial class SvcHandler
  7. {
  8. private void SvcSetHeapSize(CpuThreadState ThreadState)
  9. {
  10. ulong Size = ThreadState.X1;
  11. if ((Size & 0xFFFFFFFE001FFFFF) != 0)
  12. {
  13. Logger.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!");
  14. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  15. return;
  16. }
  17. long Result = Process.MemoryManager.TrySetHeapSize((long)Size, out long Position);
  18. ThreadState.X0 = (ulong)Result;
  19. if (Result == 0)
  20. {
  21. ThreadState.X1 = (ulong)Position;
  22. }
  23. else
  24. {
  25. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
  26. }
  27. }
  28. private void SvcSetMemoryAttribute(CpuThreadState ThreadState)
  29. {
  30. long Position = (long)ThreadState.X0;
  31. long Size = (long)ThreadState.X1;
  32. if (!PageAligned(Position))
  33. {
  34. Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
  35. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  36. return;
  37. }
  38. if (!PageAligned(Size) || Size == 0)
  39. {
  40. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
  41. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  42. return;
  43. }
  44. MemoryAttribute AttributeMask = (MemoryAttribute)ThreadState.X2;
  45. MemoryAttribute AttributeValue = (MemoryAttribute)ThreadState.X3;
  46. MemoryAttribute Attributes = AttributeMask | AttributeValue;
  47. if (Attributes != AttributeMask ||
  48. (Attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
  49. {
  50. Logger.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!");
  51. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
  52. return;
  53. }
  54. long Result = Process.MemoryManager.SetMemoryAttribute(
  55. Position,
  56. Size,
  57. AttributeMask,
  58. AttributeValue);
  59. if (Result != 0)
  60. {
  61. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
  62. }
  63. else
  64. {
  65. Memory.StopObservingRegion(Position, Size);
  66. }
  67. ThreadState.X0 = (ulong)Result;
  68. }
  69. private void SvcMapMemory(CpuThreadState ThreadState)
  70. {
  71. long Dst = (long)ThreadState.X0;
  72. long Src = (long)ThreadState.X1;
  73. long Size = (long)ThreadState.X2;
  74. if (!PageAligned(Src | Dst))
  75. {
  76. Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
  77. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  78. return;
  79. }
  80. if (!PageAligned(Size) || Size == 0)
  81. {
  82. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
  83. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  84. return;
  85. }
  86. if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst)
  87. {
  88. Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
  89. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  90. return;
  91. }
  92. if (!InsideAddrSpace(Src, Size))
  93. {
  94. Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!");
  95. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  96. return;
  97. }
  98. if (!InsideNewMapRegion(Dst, Size))
  99. {
  100. Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!");
  101. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
  102. return;
  103. }
  104. long Result = Process.MemoryManager.Map(Src, Dst, Size);
  105. if (Result != 0)
  106. {
  107. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
  108. }
  109. ThreadState.X0 = (ulong)Result;
  110. }
  111. private void SvcUnmapMemory(CpuThreadState ThreadState)
  112. {
  113. long Dst = (long)ThreadState.X0;
  114. long Src = (long)ThreadState.X1;
  115. long Size = (long)ThreadState.X2;
  116. if (!PageAligned(Src | Dst))
  117. {
  118. Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
  119. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  120. return;
  121. }
  122. if (!PageAligned(Size) || Size == 0)
  123. {
  124. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
  125. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  126. return;
  127. }
  128. if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst)
  129. {
  130. Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
  131. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  132. return;
  133. }
  134. if (!InsideAddrSpace(Src, Size))
  135. {
  136. Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!");
  137. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  138. return;
  139. }
  140. if (!InsideNewMapRegion(Dst, Size))
  141. {
  142. Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!");
  143. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
  144. return;
  145. }
  146. long Result = Process.MemoryManager.Unmap(Src, Dst, Size);
  147. if (Result != 0)
  148. {
  149. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
  150. }
  151. ThreadState.X0 = (ulong)Result;
  152. }
  153. private void SvcQueryMemory(CpuThreadState ThreadState)
  154. {
  155. long InfoPtr = (long)ThreadState.X0;
  156. long Position = (long)ThreadState.X2;
  157. KMemoryInfo BlkInfo = Process.MemoryManager.QueryMemory(Position);
  158. Memory.WriteInt64(InfoPtr + 0x00, BlkInfo.Position);
  159. Memory.WriteInt64(InfoPtr + 0x08, BlkInfo.Size);
  160. Memory.WriteInt32(InfoPtr + 0x10, (int)BlkInfo.State & 0xff);
  161. Memory.WriteInt32(InfoPtr + 0x14, (int)BlkInfo.Attribute);
  162. Memory.WriteInt32(InfoPtr + 0x18, (int)BlkInfo.Permission);
  163. Memory.WriteInt32(InfoPtr + 0x1c, BlkInfo.IpcRefCount);
  164. Memory.WriteInt32(InfoPtr + 0x20, BlkInfo.DeviceRefCount);
  165. Memory.WriteInt32(InfoPtr + 0x24, 0);
  166. ThreadState.X0 = 0;
  167. ThreadState.X1 = 0;
  168. }
  169. private void SvcMapSharedMemory(CpuThreadState ThreadState)
  170. {
  171. int Handle = (int)ThreadState.X0;
  172. long Position = (long)ThreadState.X1;
  173. long Size = (long)ThreadState.X2;
  174. if (!PageAligned(Position))
  175. {
  176. Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
  177. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  178. return;
  179. }
  180. if (!PageAligned(Size) || Size == 0)
  181. {
  182. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
  183. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  184. return;
  185. }
  186. if ((ulong)(Position + Size) <= (ulong)Position)
  187. {
  188. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
  189. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  190. return;
  191. }
  192. MemoryPermission Permission = (MemoryPermission)ThreadState.X3;
  193. if ((Permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
  194. {
  195. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!");
  196. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
  197. return;
  198. }
  199. KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
  200. if (SharedMemory == null)
  201. {
  202. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!");
  203. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  204. return;
  205. }
  206. if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size))
  207. {
  208. Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!");
  209. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  210. return;
  211. }
  212. if (SharedMemory.Size != Size)
  213. {
  214. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} does not match shared memory size 0x{SharedMemory.Size:16}!");
  215. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  216. return;
  217. }
  218. long Result = Process.MemoryManager.MapSharedMemory(SharedMemory, Permission, Position);
  219. if (Result != 0)
  220. {
  221. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
  222. }
  223. ThreadState.X0 = (ulong)Result;
  224. }
  225. private void SvcUnmapSharedMemory(CpuThreadState ThreadState)
  226. {
  227. int Handle = (int)ThreadState.X0;
  228. long Position = (long)ThreadState.X1;
  229. long Size = (long)ThreadState.X2;
  230. if (!PageAligned(Position))
  231. {
  232. Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
  233. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  234. return;
  235. }
  236. if (!PageAligned(Size) || Size == 0)
  237. {
  238. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
  239. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  240. return;
  241. }
  242. if ((ulong)(Position + Size) <= (ulong)Position)
  243. {
  244. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
  245. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  246. return;
  247. }
  248. KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
  249. if (SharedMemory == null)
  250. {
  251. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!");
  252. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
  253. return;
  254. }
  255. if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size))
  256. {
  257. Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!");
  258. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  259. return;
  260. }
  261. long Result = Process.MemoryManager.UnmapSharedMemory(Position, Size);
  262. if (Result != 0)
  263. {
  264. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
  265. }
  266. ThreadState.X0 = (ulong)Result;
  267. }
  268. private void SvcCreateTransferMemory(CpuThreadState ThreadState)
  269. {
  270. long Position = (long)ThreadState.X1;
  271. long Size = (long)ThreadState.X2;
  272. if (!PageAligned(Position))
  273. {
  274. Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
  275. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  276. return;
  277. }
  278. if (!PageAligned(Size) || Size == 0)
  279. {
  280. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
  281. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  282. return;
  283. }
  284. if ((ulong)(Position + Size) <= (ulong)Position)
  285. {
  286. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
  287. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  288. return;
  289. }
  290. MemoryPermission Permission = (MemoryPermission)ThreadState.X3;
  291. if (Permission > MemoryPermission.ReadAndWrite || Permission == MemoryPermission.Write)
  292. {
  293. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!");
  294. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
  295. return;
  296. }
  297. Process.MemoryManager.ReserveTransferMemory(Position, Size, Permission);
  298. KTransferMemory TransferMemory = new KTransferMemory(Position, Size);
  299. KernelResult Result = Process.HandleTable.GenerateHandle(TransferMemory, out int Handle);
  300. ThreadState.X0 = (uint)Result;
  301. ThreadState.X1 = (ulong)Handle;
  302. }
  303. private void SvcMapPhysicalMemory(CpuThreadState ThreadState)
  304. {
  305. long Position = (long)ThreadState.X0;
  306. long Size = (long)ThreadState.X1;
  307. if (!PageAligned(Position))
  308. {
  309. Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
  310. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  311. return;
  312. }
  313. if (!PageAligned(Size) || Size == 0)
  314. {
  315. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
  316. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  317. return;
  318. }
  319. if ((ulong)(Position + Size) <= (ulong)Position)
  320. {
  321. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
  322. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  323. return;
  324. }
  325. if (!InsideAddrSpace(Position, Size))
  326. {
  327. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!");
  328. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  329. return;
  330. }
  331. long Result = Process.MemoryManager.MapPhysicalMemory(Position, Size);
  332. if (Result != 0)
  333. {
  334. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
  335. }
  336. ThreadState.X0 = (ulong)Result;
  337. }
  338. private void SvcUnmapPhysicalMemory(CpuThreadState ThreadState)
  339. {
  340. long Position = (long)ThreadState.X0;
  341. long Size = (long)ThreadState.X1;
  342. if (!PageAligned(Position))
  343. {
  344. Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
  345. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
  346. return;
  347. }
  348. if (!PageAligned(Size) || Size == 0)
  349. {
  350. Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
  351. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
  352. return;
  353. }
  354. if ((ulong)(Position + Size) <= (ulong)Position)
  355. {
  356. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
  357. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  358. return;
  359. }
  360. if (!InsideAddrSpace(Position, Size))
  361. {
  362. Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!");
  363. ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
  364. return;
  365. }
  366. long Result = Process.MemoryManager.UnmapPhysicalMemory(Position, Size);
  367. if (Result != 0)
  368. {
  369. Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
  370. }
  371. ThreadState.X0 = (ulong)Result;
  372. }
  373. private static bool PageAligned(long Position)
  374. {
  375. return (Position & (KMemoryManager.PageSize - 1)) == 0;
  376. }
  377. private bool InsideAddrSpace(long Position, long Size)
  378. {
  379. ulong Start = (ulong)Position;
  380. ulong End = (ulong)Size + Start;
  381. return Start >= (ulong)Process.MemoryManager.AddrSpaceStart &&
  382. End < (ulong)Process.MemoryManager.AddrSpaceEnd;
  383. }
  384. private bool InsideMapRegion(long Position, long Size)
  385. {
  386. ulong Start = (ulong)Position;
  387. ulong End = (ulong)Size + Start;
  388. return Start >= (ulong)Process.MemoryManager.MapRegionStart &&
  389. End < (ulong)Process.MemoryManager.MapRegionEnd;
  390. }
  391. private bool InsideHeapRegion(long Position, long Size)
  392. {
  393. ulong Start = (ulong)Position;
  394. ulong End = (ulong)Size + Start;
  395. return Start >= (ulong)Process.MemoryManager.HeapRegionStart &&
  396. End < (ulong)Process.MemoryManager.HeapRegionEnd;
  397. }
  398. private bool InsideNewMapRegion(long Position, long Size)
  399. {
  400. ulong Start = (ulong)Position;
  401. ulong End = (ulong)Size + Start;
  402. return Start >= (ulong)Process.MemoryManager.NewMapRegionStart &&
  403. End < (ulong)Process.MemoryManager.NewMapRegionEnd;
  404. }
  405. }
  406. }