address_space.h 4.5 KB

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