KCodeMemory.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 using System.Diagnostics; 7 8 namespace Ryujinx.HLE.HOS.Kernel.Memory 9 { 10 class KCodeMemory : KAutoObject 11 { 12 public KProcess Owner { get; private set; } 13 private readonly KPageList _pageList; 14 private readonly object _lock; 15 private ulong _address; 16 private bool _isOwnerMapped; 17 private bool _isMapped; 18 19 public KCodeMemory(KernelContext context) : base(context) 20 { 21 _pageList = new KPageList(); 22 _lock = new object(); 23 } 24 25 public Result Initialize(ulong address, ulong size) 26 { 27 Owner = KernelStatic.GetCurrentProcess(); 28 29 Result result = Owner.MemoryManager.BorrowCodeMemory(_pageList, address, size); 30 31 if (result != Result.Success) 32 { 33 return result; 34 } 35 36 Owner.CpuMemory.Fill(address, size, 0xff); 37 Owner.IncrementReferenceCount(); 38 39 _address = address; 40 _isMapped = false; 41 _isOwnerMapped = false; 42 43 return Result.Success; 44 } 45 46 public Result Map(ulong address, ulong size, KMemoryPermission perm) 47 { 48 if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize)) 49 { 50 return KernelResult.InvalidSize; 51 } 52 53 lock (_lock) 54 { 55 if (_isMapped) 56 { 57 return KernelResult.InvalidState; 58 } 59 60 KProcess process = KernelStatic.GetCurrentProcess(); 61 62 Result result = process.MemoryManager.MapPages(address, _pageList, MemoryState.CodeWritable, KMemoryPermission.ReadAndWrite); 63 64 if (result != Result.Success) 65 { 66 return result; 67 } 68 69 _isMapped = true; 70 } 71 72 return Result.Success; 73 } 74 75 public Result MapToOwner(ulong address, ulong size, KMemoryPermission permission) 76 { 77 if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize)) 78 { 79 return KernelResult.InvalidSize; 80 } 81 82 lock (_lock) 83 { 84 if (_isOwnerMapped) 85 { 86 return KernelResult.InvalidState; 87 } 88 89 Debug.Assert(permission == KMemoryPermission.Read || permission == KMemoryPermission.ReadAndExecute); 90 91 Result result = Owner.MemoryManager.MapPages(address, _pageList, MemoryState.CodeReadOnly, permission); 92 93 if (result != Result.Success) 94 { 95 return result; 96 } 97 98 _isOwnerMapped = true; 99 } 100 101 return Result.Success; 102 } 103 104 public Result Unmap(ulong address, ulong size) 105 { 106 if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize)) 107 { 108 return KernelResult.InvalidSize; 109 } 110 111 lock (_lock) 112 { 113 KProcess process = KernelStatic.GetCurrentProcess(); 114 115 Result result = process.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeWritable); 116 117 if (result != Result.Success) 118 { 119 return result; 120 } 121 122 Debug.Assert(_isMapped); 123 124 _isMapped = false; 125 } 126 127 return Result.Success; 128 } 129 130 public Result UnmapFromOwner(ulong address, ulong size) 131 { 132 if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize)) 133 { 134 return KernelResult.InvalidSize; 135 } 136 137 lock (_lock) 138 { 139 Result result = Owner.MemoryManager.UnmapPages(address, _pageList, MemoryState.CodeReadOnly); 140 141 if (result != Result.Success) 142 { 143 return result; 144 } 145 146 Debug.Assert(_isOwnerMapped); 147 148 _isOwnerMapped = false; 149 } 150 151 return Result.Success; 152 } 153 154 protected override void Destroy() 155 { 156 if (!_isMapped && !_isOwnerMapped) 157 { 158 ulong size = _pageList.GetPagesCount() * KPageTableBase.PageSize; 159 160 if (Owner.MemoryManager.UnborrowCodeMemory(_address, size, _pageList) != Result.Success) 161 { 162 throw new InvalidOperationException("Unexpected failure restoring transfer memory attributes."); 163 } 164 } 165 166 Owner.DecrementReferenceCount(); 167 } 168 } 169 }