k_page_group.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <list>
  5. #include "common/alignment.h"
  6. #include "common/assert.h"
  7. #include "common/common_types.h"
  8. #include "core/hle/kernel/memory_types.h"
  9. #include "core/hle/result.h"
  10. namespace Kernel {
  11. class KPageGroup;
  12. class KBlockInfo {
  13. private:
  14. friend class KPageGroup;
  15. public:
  16. constexpr KBlockInfo() = default;
  17. constexpr void Initialize(PAddr addr, size_t np) {
  18. ASSERT(Common::IsAligned(addr, PageSize));
  19. ASSERT(static_cast<u32>(np) == np);
  20. m_page_index = static_cast<u32>(addr) / PageSize;
  21. m_num_pages = static_cast<u32>(np);
  22. }
  23. constexpr PAddr GetAddress() const {
  24. return m_page_index * PageSize;
  25. }
  26. constexpr size_t GetNumPages() const {
  27. return m_num_pages;
  28. }
  29. constexpr size_t GetSize() const {
  30. return this->GetNumPages() * PageSize;
  31. }
  32. constexpr PAddr GetEndAddress() const {
  33. return (m_page_index + m_num_pages) * PageSize;
  34. }
  35. constexpr PAddr GetLastAddress() const {
  36. return this->GetEndAddress() - 1;
  37. }
  38. constexpr KBlockInfo* GetNext() const {
  39. return m_next;
  40. }
  41. constexpr bool IsEquivalentTo(const KBlockInfo& rhs) const {
  42. return m_page_index == rhs.m_page_index && m_num_pages == rhs.m_num_pages;
  43. }
  44. constexpr bool operator==(const KBlockInfo& rhs) const {
  45. return this->IsEquivalentTo(rhs);
  46. }
  47. constexpr bool operator!=(const KBlockInfo& rhs) const {
  48. return !(*this == rhs);
  49. }
  50. constexpr bool IsStrictlyBefore(PAddr addr) const {
  51. const PAddr end = this->GetEndAddress();
  52. if (m_page_index != 0 && end == 0) {
  53. return false;
  54. }
  55. return end < addr;
  56. }
  57. constexpr bool operator<(PAddr addr) const {
  58. return this->IsStrictlyBefore(addr);
  59. }
  60. constexpr bool TryConcatenate(PAddr addr, size_t np) {
  61. if (addr != 0 && addr == this->GetEndAddress()) {
  62. m_num_pages += static_cast<u32>(np);
  63. return true;
  64. }
  65. return false;
  66. }
  67. private:
  68. constexpr void SetNext(KBlockInfo* next) {
  69. m_next = next;
  70. }
  71. private:
  72. KBlockInfo* m_next{};
  73. u32 m_page_index{};
  74. u32 m_num_pages{};
  75. };
  76. static_assert(sizeof(KBlockInfo) <= 0x10);
  77. class KPageGroup final {
  78. public:
  79. class Node final {
  80. public:
  81. constexpr Node(u64 addr_, std::size_t num_pages_) : addr{addr_}, num_pages{num_pages_} {}
  82. constexpr u64 GetAddress() const {
  83. return addr;
  84. }
  85. constexpr std::size_t GetNumPages() const {
  86. return num_pages;
  87. }
  88. constexpr std::size_t GetSize() const {
  89. return GetNumPages() * PageSize;
  90. }
  91. private:
  92. u64 addr{};
  93. std::size_t num_pages{};
  94. };
  95. public:
  96. KPageGroup() = default;
  97. KPageGroup(u64 address, u64 num_pages) {
  98. ASSERT(AddBlock(address, num_pages).IsSuccess());
  99. }
  100. constexpr std::list<Node>& Nodes() {
  101. return nodes;
  102. }
  103. constexpr const std::list<Node>& Nodes() const {
  104. return nodes;
  105. }
  106. std::size_t GetNumPages() const {
  107. std::size_t num_pages = 0;
  108. for (const Node& node : nodes) {
  109. num_pages += node.GetNumPages();
  110. }
  111. return num_pages;
  112. }
  113. bool IsEqual(KPageGroup& other) const {
  114. auto this_node = nodes.begin();
  115. auto other_node = other.nodes.begin();
  116. while (this_node != nodes.end() && other_node != other.nodes.end()) {
  117. if (this_node->GetAddress() != other_node->GetAddress() ||
  118. this_node->GetNumPages() != other_node->GetNumPages()) {
  119. return false;
  120. }
  121. this_node = std::next(this_node);
  122. other_node = std::next(other_node);
  123. }
  124. return this_node == nodes.end() && other_node == other.nodes.end();
  125. }
  126. Result AddBlock(u64 address, u64 num_pages) {
  127. if (!num_pages) {
  128. return ResultSuccess;
  129. }
  130. if (!nodes.empty()) {
  131. const auto node = nodes.back();
  132. if (node.GetAddress() + node.GetNumPages() * PageSize == address) {
  133. address = node.GetAddress();
  134. num_pages += node.GetNumPages();
  135. nodes.pop_back();
  136. }
  137. }
  138. nodes.push_back({address, num_pages});
  139. return ResultSuccess;
  140. }
  141. bool Empty() const {
  142. return nodes.empty();
  143. }
  144. void Finalize() {}
  145. private:
  146. std::list<Node> nodes;
  147. };
  148. } // namespace Kernel