KPageTable.cs 6.0 KB

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