SvcMemory.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. using Ryujinx.HLE.HOS.Kernel.Common;
  2. using Ryujinx.HLE.HOS.Kernel.Memory;
  3. using Ryujinx.HLE.HOS.Kernel.Process;
  4. namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
  5. {
  6. partial class SvcHandler
  7. {
  8. public KernelResult SetHeapSize64([R(1)] ulong size, [R(1)] out ulong position)
  9. {
  10. return SetHeapSize(size, out position);
  11. }
  12. public KernelResult SetHeapSize32([R(1)] uint size, [R(1)] out uint position)
  13. {
  14. ulong temporaryPosition;
  15. KernelResult result = SetHeapSize(size, out temporaryPosition);
  16. position = (uint)temporaryPosition;
  17. return result;
  18. }
  19. private KernelResult SetHeapSize(ulong size, out ulong position)
  20. {
  21. if ((size & 0xfffffffe001fffff) != 0)
  22. {
  23. position = 0;
  24. return KernelResult.InvalidSize;
  25. }
  26. return _process.MemoryManager.SetHeapSize(size, out position);
  27. }
  28. public KernelResult SetMemoryAttribute64(
  29. [R(0)] ulong position,
  30. [R(1)] ulong size,
  31. [R(2)] MemoryAttribute attributeMask,
  32. [R(3)] MemoryAttribute attributeValue)
  33. {
  34. return SetMemoryAttribute(position, size, attributeMask, attributeValue);
  35. }
  36. public KernelResult SetMemoryAttribute32(
  37. [R(0)] uint position,
  38. [R(1)] uint size,
  39. [R(2)] MemoryAttribute attributeMask,
  40. [R(3)] MemoryAttribute attributeValue)
  41. {
  42. return SetMemoryAttribute(position, size, attributeMask, attributeValue);
  43. }
  44. private KernelResult SetMemoryAttribute(
  45. ulong position,
  46. ulong size,
  47. MemoryAttribute attributeMask,
  48. MemoryAttribute attributeValue)
  49. {
  50. if (!PageAligned(position))
  51. {
  52. return KernelResult.InvalidAddress;
  53. }
  54. if (!PageAligned(size) || size == 0)
  55. {
  56. return KernelResult.InvalidSize;
  57. }
  58. MemoryAttribute attributes = attributeMask | attributeValue;
  59. if (attributes != attributeMask ||
  60. (attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
  61. {
  62. return KernelResult.InvalidCombination;
  63. }
  64. KernelResult result = _process.MemoryManager.SetMemoryAttribute(
  65. position,
  66. size,
  67. attributeMask,
  68. attributeValue);
  69. return result;
  70. }
  71. public KernelResult MapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size)
  72. {
  73. return MapMemory(dst, src, size);
  74. }
  75. public KernelResult MapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
  76. {
  77. return MapMemory(dst, src, size);
  78. }
  79. private KernelResult MapMemory(ulong dst, ulong src, ulong size)
  80. {
  81. if (!PageAligned(src | dst))
  82. {
  83. return KernelResult.InvalidAddress;
  84. }
  85. if (!PageAligned(size) || size == 0)
  86. {
  87. return KernelResult.InvalidSize;
  88. }
  89. if (src + size <= src || dst + size <= dst)
  90. {
  91. return KernelResult.InvalidMemState;
  92. }
  93. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  94. if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
  95. {
  96. return KernelResult.InvalidMemState;
  97. }
  98. if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
  99. currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
  100. currentProcess.MemoryManager.InsideAliasRegion (dst, size))
  101. {
  102. return KernelResult.InvalidMemRange;
  103. }
  104. return _process.MemoryManager.Map(dst, src, size);
  105. }
  106. public KernelResult UnmapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size)
  107. {
  108. return UnmapMemory(dst, src, size);
  109. }
  110. public KernelResult UnmapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
  111. {
  112. return UnmapMemory(dst, src, size);
  113. }
  114. private KernelResult UnmapMemory(ulong dst, ulong src, ulong size)
  115. {
  116. if (!PageAligned(src | dst))
  117. {
  118. return KernelResult.InvalidAddress;
  119. }
  120. if (!PageAligned(size) || size == 0)
  121. {
  122. return KernelResult.InvalidSize;
  123. }
  124. if (src + size <= src || dst + size <= dst)
  125. {
  126. return KernelResult.InvalidMemState;
  127. }
  128. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  129. if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
  130. {
  131. return KernelResult.InvalidMemState;
  132. }
  133. if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
  134. currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
  135. currentProcess.MemoryManager.InsideAliasRegion (dst, size))
  136. {
  137. return KernelResult.InvalidMemRange;
  138. }
  139. return _process.MemoryManager.Unmap(dst, src, size);
  140. }
  141. public KernelResult QueryMemory64([R(0)] ulong infoPtr, [R(2)] ulong position, [R(1)] out ulong pageInfo)
  142. {
  143. return QueryMemory(infoPtr, position, out pageInfo);
  144. }
  145. public KernelResult QueryMemory32([R(0)] uint infoPtr, [R(1)] uint r1, [R(2)] uint position, [R(1)] out uint pageInfo)
  146. {
  147. KernelResult result = QueryMemory(infoPtr, position, out ulong pageInfo64);
  148. pageInfo = (uint)pageInfo64;
  149. return result;
  150. }
  151. private KernelResult QueryMemory(ulong infoPtr, ulong position, out ulong pageInfo)
  152. {
  153. KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position);
  154. _process.CpuMemory.WriteUInt64((long)infoPtr + 0x00, blkInfo.Address);
  155. _process.CpuMemory.WriteUInt64((long)infoPtr + 0x08, blkInfo.Size);
  156. _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x10, (int)blkInfo.State & 0xff);
  157. _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x14, (int)blkInfo.Attribute);
  158. _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x18, (int)blkInfo.Permission);
  159. _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x1c, blkInfo.IpcRefCount);
  160. _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x20, blkInfo.DeviceRefCount);
  161. _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x24, 0);
  162. pageInfo = 0;
  163. return KernelResult.Success;
  164. }
  165. public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission)
  166. {
  167. return MapSharedMemory(handle, address, size, permission);
  168. }
  169. public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission permission)
  170. {
  171. return MapSharedMemory(handle, address, size, permission);
  172. }
  173. private KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
  174. {
  175. if (!PageAligned(address))
  176. {
  177. return KernelResult.InvalidAddress;
  178. }
  179. if (!PageAligned(size) || size == 0)
  180. {
  181. return KernelResult.InvalidSize;
  182. }
  183. if (address + size <= address)
  184. {
  185. return KernelResult.InvalidMemState;
  186. }
  187. if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
  188. {
  189. return KernelResult.InvalidPermission;
  190. }
  191. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  192. KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
  193. if (sharedMemory == null)
  194. {
  195. return KernelResult.InvalidHandle;
  196. }
  197. if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
  198. currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
  199. currentProcess.MemoryManager.InsideAliasRegion(address, size))
  200. {
  201. return KernelResult.InvalidMemRange;
  202. }
  203. return sharedMemory.MapIntoProcess(
  204. currentProcess.MemoryManager,
  205. address,
  206. size,
  207. currentProcess,
  208. permission);
  209. }
  210. public KernelResult UnmapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size)
  211. {
  212. return UnmapSharedMemory(handle, address, size);
  213. }
  214. public KernelResult UnmapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size)
  215. {
  216. return UnmapSharedMemory(handle, address, size);
  217. }
  218. private KernelResult UnmapSharedMemory(int handle, ulong address, ulong size)
  219. {
  220. if (!PageAligned(address))
  221. {
  222. return KernelResult.InvalidAddress;
  223. }
  224. if (!PageAligned(size) || size == 0)
  225. {
  226. return KernelResult.InvalidSize;
  227. }
  228. if (address + size <= address)
  229. {
  230. return KernelResult.InvalidMemState;
  231. }
  232. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  233. KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
  234. if (sharedMemory == null)
  235. {
  236. return KernelResult.InvalidHandle;
  237. }
  238. if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
  239. currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
  240. currentProcess.MemoryManager.InsideAliasRegion(address, size))
  241. {
  242. return KernelResult.InvalidMemRange;
  243. }
  244. return sharedMemory.UnmapFromProcess(
  245. currentProcess.MemoryManager,
  246. address,
  247. size,
  248. currentProcess);
  249. }
  250. public KernelResult CreateTransferMemory64(
  251. [R(1)] ulong address,
  252. [R(2)] ulong size,
  253. [R(3)] MemoryPermission permission,
  254. [R(1)] out int handle)
  255. {
  256. return CreateTransferMemory(address, size, permission, out handle);
  257. }
  258. public KernelResult CreateTransferMemory32(
  259. [R(1)] uint address,
  260. [R(2)] uint size,
  261. [R(3)] MemoryPermission permission,
  262. [R(1)] out int handle)
  263. {
  264. return CreateTransferMemory(address, size, permission, out handle);
  265. }
  266. private KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
  267. {
  268. handle = 0;
  269. if (!PageAligned(address))
  270. {
  271. return KernelResult.InvalidAddress;
  272. }
  273. if (!PageAligned(size) || size == 0)
  274. {
  275. return KernelResult.InvalidSize;
  276. }
  277. if (address + size <= address)
  278. {
  279. return KernelResult.InvalidMemState;
  280. }
  281. if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
  282. {
  283. return KernelResult.InvalidPermission;
  284. }
  285. KernelResult result = _process.MemoryManager.ReserveTransferMemory(address, size, permission);
  286. if (result != KernelResult.Success)
  287. {
  288. return result;
  289. }
  290. KTransferMemory transferMemory = new KTransferMemory(_system, address, size);
  291. return _process.HandleTable.GenerateHandle(transferMemory, out handle);
  292. }
  293. public KernelResult MapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size)
  294. {
  295. return MapPhysicalMemory(address, size);
  296. }
  297. public KernelResult MapPhysicalMemory32([R(0)] uint address, [R(1)] uint size)
  298. {
  299. return MapPhysicalMemory(address, size);
  300. }
  301. private KernelResult MapPhysicalMemory(ulong address, ulong size)
  302. {
  303. if (!PageAligned(address))
  304. {
  305. return KernelResult.InvalidAddress;
  306. }
  307. if (!PageAligned(size) || size == 0)
  308. {
  309. return KernelResult.InvalidSize;
  310. }
  311. if (address + size <= address)
  312. {
  313. return KernelResult.InvalidMemRange;
  314. }
  315. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  316. if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
  317. {
  318. return KernelResult.InvalidState;
  319. }
  320. if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
  321. currentProcess.MemoryManager.OutsideAliasRegion(address, size))
  322. {
  323. return KernelResult.InvalidMemRange;
  324. }
  325. return _process.MemoryManager.MapPhysicalMemory(address, size);
  326. }
  327. public KernelResult UnmapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size)
  328. {
  329. return UnmapPhysicalMemory(address, size);
  330. }
  331. public KernelResult UnmapPhysicalMemory32([R(0)] uint address, [R(1)] uint size)
  332. {
  333. return UnmapPhysicalMemory(address, size);
  334. }
  335. private KernelResult UnmapPhysicalMemory(ulong address, ulong size)
  336. {
  337. if (!PageAligned(address))
  338. {
  339. return KernelResult.InvalidAddress;
  340. }
  341. if (!PageAligned(size) || size == 0)
  342. {
  343. return KernelResult.InvalidSize;
  344. }
  345. if (address + size <= address)
  346. {
  347. return KernelResult.InvalidMemRange;
  348. }
  349. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  350. if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
  351. {
  352. return KernelResult.InvalidState;
  353. }
  354. if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
  355. currentProcess.MemoryManager.OutsideAliasRegion(address, size))
  356. {
  357. return KernelResult.InvalidMemRange;
  358. }
  359. return _process.MemoryManager.UnmapPhysicalMemory(address, size);
  360. }
  361. public KernelResult MapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size)
  362. {
  363. return MapProcessCodeMemory(handle, dst, src, size);
  364. }
  365. public KernelResult MapProcessCodeMemory32([R(0)] int handle, [R(1)] uint srcLow, [R(2)] uint dstLow, [R(3)] uint dstHigh, [R(4)] uint srcHigh, [R(5)] uint sizeLow, [R(6)] uint sizeHigh)
  366. {
  367. ulong src = (srcLow | ((ulong)srcHigh << 32));
  368. ulong dst = (dstLow | ((ulong)dstHigh << 32));
  369. ulong size = (sizeLow | ((ulong)sizeHigh << 32));
  370. return MapProcessCodeMemory(handle, dst, src, size);
  371. }
  372. public KernelResult MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
  373. {
  374. if (!PageAligned(dst) || !PageAligned(src))
  375. {
  376. return KernelResult.InvalidAddress;
  377. }
  378. if (!PageAligned(size) || size == 0)
  379. {
  380. return KernelResult.InvalidSize;
  381. }
  382. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  383. KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
  384. if (targetProcess == null)
  385. {
  386. return KernelResult.InvalidHandle;
  387. }
  388. if (targetProcess.MemoryManager.OutsideAddrSpace(dst, size) ||
  389. targetProcess.MemoryManager.OutsideAddrSpace(src, size) ||
  390. targetProcess.MemoryManager.InsideAliasRegion(dst, size) ||
  391. targetProcess.MemoryManager.InsideHeapRegion(dst, size))
  392. {
  393. return KernelResult.InvalidMemRange;
  394. }
  395. if (size + dst <= dst || size + src <= src)
  396. {
  397. return KernelResult.InvalidMemState;
  398. }
  399. return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
  400. }
  401. public KernelResult UnmapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size)
  402. {
  403. return UnmapProcessCodeMemory(handle, dst, src, size);
  404. }
  405. public KernelResult UnmapProcessCodeMemory32([R(0)] int handle, [R(1)] uint srcLow, [R(2)] uint dstLow, [R(3)] uint dstHigh, [R(4)] uint srcHigh, [R(5)] uint sizeLow, [R(6)] uint sizeHigh)
  406. {
  407. ulong src = (srcLow | ((ulong)srcHigh << 32));
  408. ulong dst = (dstLow | ((ulong)dstHigh << 32));
  409. ulong size = (sizeLow | ((ulong)sizeHigh << 32));
  410. return UnmapProcessCodeMemory(handle, dst, src, size);
  411. }
  412. public KernelResult UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
  413. {
  414. if (!PageAligned(dst) || !PageAligned(src))
  415. {
  416. return KernelResult.InvalidAddress;
  417. }
  418. if (!PageAligned(size) || size == 0)
  419. {
  420. return KernelResult.InvalidSize;
  421. }
  422. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  423. KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
  424. if (targetProcess == null)
  425. {
  426. return KernelResult.InvalidHandle;
  427. }
  428. if (targetProcess.MemoryManager.OutsideAddrSpace(dst, size) ||
  429. targetProcess.MemoryManager.OutsideAddrSpace(src, size) ||
  430. targetProcess.MemoryManager.InsideAliasRegion(dst, size) ||
  431. targetProcess.MemoryManager.InsideHeapRegion(dst, size))
  432. {
  433. return KernelResult.InvalidMemRange;
  434. }
  435. if (size + dst <= dst || size + src <= src)
  436. {
  437. return KernelResult.InvalidMemState;
  438. }
  439. return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
  440. }
  441. public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission)
  442. {
  443. return SetProcessMemoryPermission(handle, src, size, permission);
  444. }
  445. public KernelResult SetProcessMemoryPermission32(
  446. [R(0)] int handle,
  447. [R(1)] uint sizeLow,
  448. [R(2)] uint srcLow,
  449. [R(3)] uint srcHigh,
  450. [R(4)] uint sizeHigh,
  451. [R(5)] MemoryPermission permission)
  452. {
  453. ulong src = (srcLow | ((ulong)srcHigh << 32));
  454. ulong size = (sizeLow | ((ulong)sizeHigh << 32));
  455. return SetProcessMemoryPermission(handle, src, size, permission);
  456. }
  457. public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission)
  458. {
  459. if (!PageAligned(src))
  460. {
  461. return KernelResult.InvalidAddress;
  462. }
  463. if (!PageAligned(size) || size == 0)
  464. {
  465. return KernelResult.InvalidSize;
  466. }
  467. if (permission != MemoryPermission.None &&
  468. permission != MemoryPermission.Read &&
  469. permission != MemoryPermission.ReadAndWrite &&
  470. permission != MemoryPermission.ReadAndExecute)
  471. {
  472. return KernelResult.InvalidPermission;
  473. }
  474. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  475. KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
  476. if (targetProcess == null)
  477. {
  478. return KernelResult.InvalidHandle;
  479. }
  480. if (targetProcess.MemoryManager.OutsideAddrSpace(src, size))
  481. {
  482. return KernelResult.InvalidMemState;
  483. }
  484. return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission);
  485. }
  486. private static bool PageAligned(ulong position)
  487. {
  488. return (position & (KMemoryManager.PageSize - 1)) == 0;
  489. }
  490. }
  491. }