memory_manager.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <map>
  6. #include <optional>
  7. #include "common/common_types.h"
  8. #include "common/page_table.h"
  9. namespace Tegra {
  10. /**
  11. * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
  12. * with homogeneous attributes across its extents. In this particular implementation each VMA is
  13. * also backed by a single host memory allocation.
  14. */
  15. struct VirtualMemoryArea {
  16. enum class Type : u8 {
  17. Unmapped,
  18. Allocated,
  19. Mapped,
  20. };
  21. /// Virtual base address of the region.
  22. GPUVAddr base{};
  23. /// Size of the region.
  24. u64 size{};
  25. /// Memory area mapping type.
  26. Type type{Type::Unmapped};
  27. /// CPU memory mapped address corresponding to this memory area.
  28. VAddr backing_addr{};
  29. /// Offset into the backing_memory the mapping starts from.
  30. std::size_t offset{};
  31. /// Pointer backing this VMA.
  32. u8* backing_memory{};
  33. /// Tests if this area can be merged to the right with `next`.
  34. bool CanBeMergedWith(const VirtualMemoryArea& next) const;
  35. };
  36. class MemoryManager final {
  37. public:
  38. MemoryManager();
  39. GPUVAddr AllocateSpace(u64 size, u64 align);
  40. GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
  41. GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
  42. GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr addr, u64 size);
  43. GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size);
  44. std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
  45. template <typename T>
  46. T Read(GPUVAddr addr) const;
  47. template <typename T>
  48. void Write(GPUVAddr addr, T data);
  49. u8* GetPointer(GPUVAddr addr);
  50. const u8* GetPointer(GPUVAddr addr) const;
  51. void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
  52. void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
  53. void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
  54. private:
  55. using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>;
  56. using VMAHandle = VMAMap::const_iterator;
  57. using VMAIter = VMAMap::iterator;
  58. bool IsAddressValid(GPUVAddr addr) const;
  59. void MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
  60. VAddr backing_addr = 0);
  61. void MapMemoryRegion(GPUVAddr base, u64 size, u8* target, VAddr backing_addr);
  62. void UnmapRegion(GPUVAddr base, u64 size);
  63. /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
  64. VMAHandle FindVMA(GPUVAddr target) const;
  65. VMAHandle AllocateMemory(GPUVAddr target, std::size_t offset, u64 size);
  66. /**
  67. * Maps an unmanaged host memory pointer at a given address.
  68. *
  69. * @param target The guest address to start the mapping at.
  70. * @param memory The memory to be mapped.
  71. * @param size Size of the mapping.
  72. * @param state MemoryState tag to attach to the VMA.
  73. */
  74. VMAHandle MapBackingMemory(GPUVAddr target, u8* memory, u64 size, VAddr backing_addr);
  75. /// Unmaps a range of addresses, splitting VMAs as necessary.
  76. void UnmapRange(GPUVAddr target, u64 size);
  77. /// Converts a VMAHandle to a mutable VMAIter.
  78. VMAIter StripIterConstness(const VMAHandle& iter);
  79. /// Marks as the specfied VMA as allocated.
  80. VMAIter Allocate(VMAIter vma);
  81. /**
  82. * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
  83. * the appropriate error checking.
  84. */
  85. VMAIter CarveVMA(GPUVAddr base, u64 size);
  86. /**
  87. * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each
  88. * end of the range.
  89. */
  90. VMAIter CarveVMARange(GPUVAddr base, u64 size);
  91. /**
  92. * Splits a VMA in two, at the specified offset.
  93. * @returns the right side of the split, with the original iterator becoming the left side.
  94. */
  95. VMAIter SplitVMA(VMAIter vma, u64 offset_in_vma);
  96. /**
  97. * Checks for and merges the specified VMA with adjacent ones if possible.
  98. * @returns the merged VMA or the original if no merging was possible.
  99. */
  100. VMAIter MergeAdjacent(VMAIter vma);
  101. /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
  102. void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
  103. /// Finds a free (unmapped region) of the specified size starting at the specified address.
  104. GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size) const;
  105. private:
  106. static constexpr u64 page_bits{16};
  107. static constexpr u64 page_size{1 << page_bits};
  108. static constexpr u64 page_mask{page_size - 1};
  109. /// Address space in bits, this is fairly arbitrary but sufficiently large.
  110. static constexpr u32 address_space_width{39};
  111. /// Start address for mapping, this is fairly arbitrary but must be non-zero.
  112. static constexpr GPUVAddr address_space_base{0x100000};
  113. /// End of address space, based on address space in bits.
  114. static constexpr GPUVAddr address_space_end{1ULL << address_space_width};
  115. Common::PageTable page_table{page_bits};
  116. VMAMap vma_map;
  117. };
  118. } // namespace Tegra