KPageTable.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using Ryujinx.Horizon.Common;
  2. using Ryujinx.Memory;
  3. using Ryujinx.Memory.Range;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. namespace Ryujinx.HLE.HOS.Kernel.Memory
  8. {
  9. class KPageTable : KPageTableBase
  10. {
  11. private readonly IVirtualMemoryManager _cpuMemory;
  12. protected override bool Supports4KBPages => _cpuMemory.Supports4KBPages;
  13. public KPageTable(KernelContext context, IVirtualMemoryManager cpuMemory) : base(context)
  14. {
  15. _cpuMemory = cpuMemory;
  16. }
  17. /// <inheritdoc/>
  18. protected override IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size)
  19. {
  20. return _cpuMemory.GetHostRegions(va, size);
  21. }
  22. /// <inheritdoc/>
  23. protected override void GetPhysicalRegions(ulong va, ulong size, KPageList pageList)
  24. {
  25. var ranges = _cpuMemory.GetPhysicalRegions(va, size);
  26. foreach (var range in ranges)
  27. {
  28. pageList.AddRange(range.Address + DramMemoryMap.DramBase, range.Size / PageSize);
  29. }
  30. }
  31. /// <inheritdoc/>
  32. protected override ReadOnlySpan<byte> GetSpan(ulong va, int size)
  33. {
  34. return _cpuMemory.GetSpan(va, size);
  35. }
  36. /// <inheritdoc/>
  37. protected override Result MapMemory(ulong src, ulong dst, ulong pagesCount, KMemoryPermission oldSrcPermission, KMemoryPermission newDstPermission)
  38. {
  39. KPageList pageList = new KPageList();
  40. GetPhysicalRegions(src, pagesCount * PageSize, pageList);
  41. Result result = Reprotect(src, pagesCount, KMemoryPermission.None);
  42. if (result != Result.Success)
  43. {
  44. return result;
  45. }
  46. result = MapPages(dst, pageList, newDstPermission, MemoryMapFlags.Private, false, 0);
  47. if (result != Result.Success)
  48. {
  49. Result reprotectResult = Reprotect(src, pagesCount, oldSrcPermission);
  50. Debug.Assert(reprotectResult == Result.Success);
  51. }
  52. return result;
  53. }
  54. /// <inheritdoc/>
  55. protected override Result UnmapMemory(ulong dst, ulong src, ulong pagesCount, KMemoryPermission oldDstPermission, KMemoryPermission newSrcPermission)
  56. {
  57. ulong size = pagesCount * PageSize;
  58. KPageList srcPageList = new KPageList();
  59. KPageList dstPageList = new KPageList();
  60. GetPhysicalRegions(src, size, srcPageList);
  61. GetPhysicalRegions(dst, size, dstPageList);
  62. if (!dstPageList.IsEqual(srcPageList))
  63. {
  64. return KernelResult.InvalidMemRange;
  65. }
  66. Result result = Unmap(dst, pagesCount);
  67. if (result != Result.Success)
  68. {
  69. return result;
  70. }
  71. result = Reprotect(src, pagesCount, newSrcPermission);
  72. if (result != Result.Success)
  73. {
  74. Result mapResult = MapPages(dst, dstPageList, oldDstPermission, MemoryMapFlags.Private, false, 0);
  75. Debug.Assert(mapResult == Result.Success);
  76. }
  77. return result;
  78. }
  79. /// <inheritdoc/>
  80. protected override Result MapPages(
  81. ulong dstVa,
  82. ulong pagesCount,
  83. ulong srcPa,
  84. KMemoryPermission permission,
  85. MemoryMapFlags flags,
  86. bool shouldFillPages,
  87. byte fillValue)
  88. {
  89. ulong size = pagesCount * PageSize;
  90. Context.CommitMemory(srcPa - DramMemoryMap.DramBase, size);
  91. _cpuMemory.Map(dstVa, srcPa - DramMemoryMap.DramBase, size, flags);
  92. if (DramMemoryMap.IsHeapPhysicalAddress(srcPa))
  93. {
  94. Context.MemoryManager.IncrementPagesReferenceCount(srcPa, pagesCount);
  95. }
  96. if (shouldFillPages)
  97. {
  98. _cpuMemory.Fill(dstVa, size, fillValue);
  99. }
  100. return Result.Success;
  101. }
  102. /// <inheritdoc/>
  103. protected override Result MapPages(
  104. ulong address,
  105. KPageList pageList,
  106. KMemoryPermission permission,
  107. MemoryMapFlags flags,
  108. bool shouldFillPages,
  109. byte fillValue)
  110. {
  111. using var scopedPageList = new KScopedPageList(Context.MemoryManager, pageList);
  112. ulong currentVa = address;
  113. foreach (var pageNode in pageList)
  114. {
  115. ulong addr = pageNode.Address - DramMemoryMap.DramBase;
  116. ulong size = pageNode.PagesCount * PageSize;
  117. Context.CommitMemory(addr, size);
  118. _cpuMemory.Map(currentVa, addr, size, flags);
  119. if (shouldFillPages)
  120. {
  121. _cpuMemory.Fill(currentVa, size, fillValue);
  122. }
  123. currentVa += size;
  124. }
  125. scopedPageList.SignalSuccess();
  126. return Result.Success;
  127. }
  128. /// <inheritdoc/>
  129. protected override Result MapForeign(IEnumerable<HostMemoryRange> regions, ulong va, ulong size)
  130. {
  131. ulong offset = 0;
  132. foreach (var region in regions)
  133. {
  134. _cpuMemory.MapForeign(va + offset, region.Address, region.Size);
  135. offset += region.Size;
  136. }
  137. return Result.Success;
  138. }
  139. /// <inheritdoc/>
  140. protected override Result Unmap(ulong address, ulong pagesCount)
  141. {
  142. KPageList pagesToClose = new KPageList();
  143. var regions = _cpuMemory.GetPhysicalRegions(address, pagesCount * PageSize);
  144. foreach (var region in regions)
  145. {
  146. ulong pa = region.Address + DramMemoryMap.DramBase;
  147. if (DramMemoryMap.IsHeapPhysicalAddress(pa))
  148. {
  149. pagesToClose.AddRange(pa, region.Size / PageSize);
  150. }
  151. }
  152. _cpuMemory.Unmap(address, pagesCount * PageSize);
  153. pagesToClose.DecrementPagesReferenceCount(Context.MemoryManager);
  154. return Result.Success;
  155. }
  156. /// <inheritdoc/>
  157. protected override Result Reprotect(ulong address, ulong pagesCount, KMemoryPermission permission)
  158. {
  159. // TODO.
  160. return Result.Success;
  161. }
  162. /// <inheritdoc/>
  163. protected override Result ReprotectWithAttributes(ulong address, ulong pagesCount, KMemoryPermission permission)
  164. {
  165. // TODO.
  166. return Result.Success;
  167. }
  168. /// <inheritdoc/>
  169. protected override void SignalMemoryTracking(ulong va, ulong size, bool write)
  170. {
  171. _cpuMemory.SignalMemoryTracking(va, size, write);
  172. }
  173. /// <inheritdoc/>
  174. protected override void Write(ulong va, ReadOnlySpan<byte> data)
  175. {
  176. _cpuMemory.Write(va, data);
  177. }
  178. }
  179. }