KTransferMemory.cs 3.9 KB

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