vm_manager.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <map>
  6. #include <memory>
  7. #include <vector>
  8. #include "common/common_types.h"
  9. #include "core/hle/result.h"
  10. #include "core/memory.h"
  11. #include "core/mmio.h"
  12. namespace Kernel {
  13. enum class VMAType : u8 {
  14. /// VMA represents an unmapped region of the address space.
  15. Free,
  16. /// VMA is backed by a ref-counted allocate memory block.
  17. AllocatedMemoryBlock,
  18. /// VMA is backed by a raw, unmanaged pointer.
  19. BackingMemory,
  20. /// VMA is mapped to MMIO registers at a fixed PAddr.
  21. MMIO,
  22. // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP
  23. };
  24. /// Permissions for mapped memory blocks
  25. enum class VMAPermission : u8 {
  26. None = 0,
  27. Read = 1,
  28. Write = 2,
  29. Execute = 4,
  30. ReadWrite = Read | Write,
  31. ReadExecute = Read | Execute,
  32. WriteExecute = Write | Execute,
  33. ReadWriteExecute = Read | Write | Execute,
  34. };
  35. /// Set of values returned in MemoryInfo.state by svcQueryMemory.
  36. enum class MemoryState : u32 {
  37. Free = 0,
  38. IO = 1,
  39. Normal = 2,
  40. Code = 3,
  41. Static = 4,
  42. Heap = 5,
  43. Shared = 6,
  44. Mapped = 6,
  45. ThreadLocalStorage = 12,
  46. };
  47. /**
  48. * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
  49. * with homogeneous attributes across its extents. In this particular implementation each VMA is
  50. * also backed by a single host memory allocation.
  51. */
  52. struct VirtualMemoryArea {
  53. /// Virtual base address of the region.
  54. VAddr base = 0;
  55. /// Size of the region.
  56. u64 size = 0;
  57. VMAType type = VMAType::Free;
  58. VMAPermission permissions = VMAPermission::None;
  59. /// Tag returned by svcQueryMemory. Not otherwise used.
  60. MemoryState meminfo_state = MemoryState::Free;
  61. // Settings for type = AllocatedMemoryBlock
  62. /// Memory block backing this VMA.
  63. std::shared_ptr<std::vector<u8>> backing_block = nullptr;
  64. /// Offset into the backing_memory the mapping starts from.
  65. size_t offset = 0;
  66. // Settings for type = BackingMemory
  67. /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
  68. u8* backing_memory = nullptr;
  69. // Settings for type = MMIO
  70. /// Physical address of the register area this VMA maps to.
  71. PAddr paddr = 0;
  72. Memory::MMIORegionPointer mmio_handler = nullptr;
  73. /// Tests if this area can be merged to the right with `next`.
  74. bool CanBeMergedWith(const VirtualMemoryArea& next) const;
  75. };
  76. /**
  77. * Manages a process' virtual addressing space. This class maintains a list of allocated and free
  78. * regions in the address space, along with their attributes, and allows kernel clients to
  79. * manipulate it, adjusting the page table to match.
  80. *
  81. * This is similar in idea and purpose to the VM manager present in operating system kernels, with
  82. * the main difference being that it doesn't have to support swapping or memory mapping of files.
  83. * The implementation is also simplified by not having to allocate page frames. See these articles
  84. * about the Linux kernel for an explantion of the concept and implementation:
  85. * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
  86. * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
  87. */
  88. class VMManager final {
  89. public:
  90. /**
  91. * The maximum amount of address space managed by the kernel.
  92. * @todo This was selected arbitrarily, and should be verified for Switch OS.
  93. */
  94. static constexpr VAddr MAX_ADDRESS{0x1000000000ULL};
  95. /**
  96. * A map covering the entirety of the managed address space, keyed by the `base` field of each
  97. * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
  98. * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
  99. * merged when possible so that no two similar and adjacent regions exist that have not been
  100. * merged.
  101. */
  102. std::map<VAddr, VirtualMemoryArea> vma_map;
  103. using VMAHandle = decltype(vma_map)::const_iterator;
  104. VMManager();
  105. ~VMManager();
  106. /// Clears the address space map, re-initializing with a single free area.
  107. void Reset();
  108. /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
  109. VMAHandle FindVMA(VAddr target) const;
  110. // TODO(yuriks): Should these functions actually return the handle?
  111. /**
  112. * Maps part of a ref-counted block of memory at a given address.
  113. *
  114. * @param target The guest address to start the mapping at.
  115. * @param block The block to be mapped.
  116. * @param offset Offset into `block` to map from.
  117. * @param size Size of the mapping.
  118. * @param state MemoryState tag to attach to the VMA.
  119. */
  120. ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
  121. size_t offset, u64 size, MemoryState state);
  122. /**
  123. * Maps an unmanaged host memory pointer at a given address.
  124. *
  125. * @param target The guest address to start the mapping at.
  126. * @param memory The memory to be mapped.
  127. * @param size Size of the mapping.
  128. * @param state MemoryState tag to attach to the VMA.
  129. */
  130. ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state);
  131. /**
  132. * Maps a memory-mapped IO region at a given address.
  133. *
  134. * @param target The guest address to start the mapping at.
  135. * @param paddr The physical address where the registers are present.
  136. * @param size Size of the mapping.
  137. * @param state MemoryState tag to attach to the VMA.
  138. * @param mmio_handler The handler that will implement read and write for this MMIO region.
  139. */
  140. ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u64 size, MemoryState state,
  141. Memory::MMIORegionPointer mmio_handler);
  142. /// Unmaps a range of addresses, splitting VMAs as necessary.
  143. ResultCode UnmapRange(VAddr target, u64 size);
  144. /// Changes the permissions of the given VMA.
  145. VMAHandle Reprotect(VMAHandle vma, VMAPermission new_perms);
  146. /// Changes the permissions of a range of addresses, splitting VMAs as necessary.
  147. ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
  148. /**
  149. * Scans all VMAs and updates the page table range of any that use the given vector as backing
  150. * memory. This should be called after any operation that causes reallocation of the vector.
  151. */
  152. void RefreshMemoryBlockMappings(const std::vector<u8>* block);
  153. /// Dumps the address space layout to the log, for debugging
  154. void LogLayout(Log::Level log_level) const;
  155. /// Gets the total memory usage, used by svcGetInfo
  156. u64 GetTotalMemoryUsage();
  157. /// Gets the total heap usage, used by svcGetInfo
  158. u64 GetTotalHeapUsage();
  159. /// Gets the total address space base address, used by svcGetInfo
  160. VAddr GetAddressSpaceBaseAddr();
  161. /// Gets the total address space address size, used by svcGetInfo
  162. u64 GetAddressSpaceSize();
  163. /// Gets the map region base address, used by svcGetInfo
  164. VAddr GetMapRegionBaseAddr();
  165. /// Gets the base address for a new memory region, used by svcGetInfo
  166. VAddr GetNewMapRegionBaseAddr();
  167. /// Gets the size for a new memory region, used by svcGetInfo
  168. u64 GetNewMapRegionSize();
  169. /// Each VMManager has its own page table, which is set as the main one when the owning process
  170. /// is scheduled.
  171. Memory::PageTable page_table;
  172. private:
  173. using VMAIter = decltype(vma_map)::iterator;
  174. /// Converts a VMAHandle to a mutable VMAIter.
  175. VMAIter StripIterConstness(const VMAHandle& iter);
  176. /// Unmaps the given VMA.
  177. VMAIter Unmap(VMAIter vma);
  178. /**
  179. * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
  180. * the appropriate error checking.
  181. */
  182. ResultVal<VMAIter> CarveVMA(VAddr base, u64 size);
  183. /**
  184. * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each
  185. * end of the range.
  186. */
  187. ResultVal<VMAIter> CarveVMARange(VAddr base, u64 size);
  188. /**
  189. * Splits a VMA in two, at the specified offset.
  190. * @returns the right side of the split, with the original iterator becoming the left side.
  191. */
  192. VMAIter SplitVMA(VMAIter vma, u64 offset_in_vma);
  193. /**
  194. * Checks for and merges the specified VMA with adjacent ones if possible.
  195. * @returns the merged VMA or the original if no merging was possible.
  196. */
  197. VMAIter MergeAdjacent(VMAIter vma);
  198. /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
  199. void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
  200. };
  201. } // namespace Kernel