address_space.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // SPDX-FileCopyrightText: 2021 Skyline Team and Contributors
  2. // SPDX-License-Identifier: GPL-3.0-or-later
  3. #pragma once
  4. #include <concepts>
  5. #include <functional>
  6. #include <mutex>
  7. #include <vector>
  8. #include "common/common_types.h"
  9. namespace Common {
  10. template <typename VaType, size_t AddressSpaceBits>
  11. concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >=
  12. AddressSpaceBits;
  13. struct EmptyStruct {};
  14. /**
  15. * @brief FlatAddressSpaceMap provides a generic VA->PA mapping implementation using a sorted vector
  16. */
  17. template <typename VaType, VaType UnmappedVa, typename PaType, PaType UnmappedPa,
  18. bool PaContigSplit, size_t AddressSpaceBits, typename ExtraBlockInfo = EmptyStruct>
  19. requires AddressSpaceValid<VaType, AddressSpaceBits>
  20. class FlatAddressSpaceMap {
  21. public:
  22. /// The maximum VA that this AS can technically reach
  23. static constexpr VaType VaMaximum{(1ULL << (AddressSpaceBits - 1)) +
  24. ((1ULL << (AddressSpaceBits - 1)) - 1)};
  25. explicit FlatAddressSpaceMap(VaType va_limit,
  26. std::function<void(VaType, VaType)> unmap_callback = {});
  27. FlatAddressSpaceMap() = default;
  28. void Map(VaType virt, PaType phys, VaType size, ExtraBlockInfo extra_info = {}) {
  29. std::scoped_lock lock(block_mutex);
  30. MapLocked(virt, phys, size, extra_info);
  31. }
  32. void Unmap(VaType virt, VaType size) {
  33. std::scoped_lock lock(block_mutex);
  34. UnmapLocked(virt, size);
  35. }
  36. VaType GetVALimit() const {
  37. return va_limit;
  38. }
  39. protected:
  40. /**
  41. * @brief Represents a block of memory in the AS, the physical mapping is contiguous until
  42. * another block with a different phys address is hit
  43. */
  44. struct Block {
  45. /// VA of the block
  46. VaType virt{UnmappedVa};
  47. /// PA of the block, will increase 1-1 with VA until a new block is encountered
  48. PaType phys{UnmappedPa};
  49. [[no_unique_address]] ExtraBlockInfo extra_info;
  50. Block() = default;
  51. Block(VaType virt_, PaType phys_, ExtraBlockInfo extra_info_)
  52. : virt(virt_), phys(phys_), extra_info(extra_info_) {}
  53. bool Valid() const {
  54. return virt != UnmappedVa;
  55. }
  56. bool Mapped() const {
  57. return phys != UnmappedPa;
  58. }
  59. bool Unmapped() const {
  60. return phys == UnmappedPa;
  61. }
  62. bool operator<(const VaType& p_virt) const {
  63. return virt < p_virt;
  64. }
  65. };
  66. /**
  67. * @brief Maps a PA range into the given AS region
  68. * @note block_mutex MUST be locked when calling this
  69. */
  70. void MapLocked(VaType virt, PaType phys, VaType size, ExtraBlockInfo extra_info);
  71. /**
  72. * @brief Unmaps the given range and merges it with other unmapped regions
  73. * @note block_mutex MUST be locked when calling this
  74. */
  75. void UnmapLocked(VaType virt, VaType size);
  76. std::mutex block_mutex;
  77. std::vector<Block> blocks{Block{}};
  78. /// a soft limit on the maximum VA of the AS
  79. VaType va_limit{VaMaximum};
  80. private:
  81. /// Callback called when the mappings in an region have changed
  82. std::function<void(VaType, VaType)> unmap_callback{};
  83. };
  84. /**
  85. * @brief FlatMemoryManager specialises FlatAddressSpaceMap to work as an allocator, with an
  86. * initial, fast linear pass and a subsequent slower pass that iterates until it finds a free block
  87. */
  88. template <typename VaType, VaType UnmappedVa, size_t AddressSpaceBits>
  89. requires AddressSpaceValid<VaType, AddressSpaceBits>
  90. class FlatAllocator
  91. : public FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits> {
  92. private:
  93. using Base = FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits>;
  94. public:
  95. explicit FlatAllocator(VaType virt_start, VaType va_limit = Base::VaMaximum);
  96. /**
  97. * @brief Allocates a region in the AS of the given size and returns its address
  98. */
  99. VaType Allocate(VaType size);
  100. /**
  101. * @brief Marks the given region in the AS as allocated
  102. */
  103. void AllocateFixed(VaType virt, VaType size);
  104. /**
  105. * @brief Frees an AS region so it can be used again
  106. */
  107. void Free(VaType virt, VaType size);
  108. VaType GetVAStart() const {
  109. return virt_start;
  110. }
  111. private:
  112. /// The base VA of the allocator, no allocations will be below this
  113. VaType virt_start;
  114. /**
  115. * The end address for the initial linear allocation pass
  116. * Once this reaches the AS limit the slower allocation path will be used
  117. */
  118. VaType current_linear_alloc_end;
  119. };
  120. } // namespace Common