KCodeMemory.cs 4.8 KB

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