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