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 }