KTransferMemory.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using Ryujinx.Common;
  2. using Ryujinx.HLE.HOS.Kernel.Common;
  3. using Ryujinx.HLE.HOS.Kernel.Process;
  4. using System;
  5. namespace Ryujinx.HLE.HOS.Kernel.Memory
  6. {
  7. class KTransferMemory : KAutoObject
  8. {
  9. private KProcess _creator;
  10. // TODO: Remove when we no longer need to read it from the owner directly.
  11. public KProcess Creator => _creator;
  12. private readonly KPageList _pageList;
  13. public ulong Address { get; private set; }
  14. public ulong Size { get; private set; }
  15. public KMemoryPermission Permission { get; private set; }
  16. private bool _hasBeenInitialized;
  17. private bool _isMapped;
  18. public KTransferMemory(KernelContext context) : base(context)
  19. {
  20. _pageList = new KPageList();
  21. }
  22. public KTransferMemory(KernelContext context, SharedMemoryStorage storage) : base(context)
  23. {
  24. _pageList = storage.GetPageList();
  25. Permission = KMemoryPermission.ReadAndWrite;
  26. _hasBeenInitialized = true;
  27. _isMapped = false;
  28. }
  29. public KernelResult Initialize(ulong address, ulong size, KMemoryPermission permission)
  30. {
  31. KProcess creator = KernelStatic.GetCurrentProcess();
  32. _creator = creator;
  33. KernelResult result = creator.MemoryManager.BorrowTransferMemory(_pageList, address, size, permission);
  34. if (result != KernelResult.Success)
  35. {
  36. return result;
  37. }
  38. creator.IncrementReferenceCount();
  39. Permission = permission;
  40. Address = address;
  41. Size = size;
  42. _hasBeenInitialized = true;
  43. _isMapped = false;
  44. return result;
  45. }
  46. public KernelResult MapIntoProcess(
  47. KPageTableBase memoryManager,
  48. ulong address,
  49. ulong size,
  50. KProcess process,
  51. KMemoryPermission permission)
  52. {
  53. if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
  54. {
  55. return KernelResult.InvalidSize;
  56. }
  57. if (permission != Permission || _isMapped)
  58. {
  59. return KernelResult.InvalidState;
  60. }
  61. MemoryState state = Permission == KMemoryPermission.None ? MemoryState.TransferMemoryIsolated : MemoryState.TransferMemory;
  62. KernelResult result = memoryManager.MapPages(address, _pageList, state, KMemoryPermission.ReadAndWrite);
  63. if (result == KernelResult.Success)
  64. {
  65. _isMapped = true;
  66. }
  67. return result;
  68. }
  69. public KernelResult UnmapFromProcess(
  70. KPageTableBase memoryManager,
  71. ulong address,
  72. ulong size,
  73. KProcess process)
  74. {
  75. if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
  76. {
  77. return KernelResult.InvalidSize;
  78. }
  79. MemoryState state = Permission == KMemoryPermission.None ? MemoryState.TransferMemoryIsolated : MemoryState.TransferMemory;
  80. KernelResult result = memoryManager.UnmapPages(address, _pageList, state);
  81. if (result == KernelResult.Success)
  82. {
  83. _isMapped = false;
  84. }
  85. return result;
  86. }
  87. protected override void Destroy()
  88. {
  89. if (_hasBeenInitialized)
  90. {
  91. if (!_isMapped && _creator.MemoryManager.UnborrowTransferMemory(Address, Size, _pageList) != KernelResult.Success)
  92. {
  93. throw new InvalidOperationException("Unexpected failure restoring transfer memory attributes.");
  94. }
  95. _creator.ResourceLimit?.Release(LimitableResource.TransferMemory, 1);
  96. _creator.DecrementReferenceCount();
  97. }
  98. }
  99. }
  100. }