vm_manager.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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/memory_hook.h"
  12. namespace FileSys {
  13. enum class ProgramAddressSpaceType : u8;
  14. }
  15. namespace Kernel {
  16. enum class VMAType : u8 {
  17. /// VMA represents an unmapped region of the address space.
  18. Free,
  19. /// VMA is backed by a ref-counted allocate memory block.
  20. AllocatedMemoryBlock,
  21. /// VMA is backed by a raw, unmanaged pointer.
  22. BackingMemory,
  23. /// VMA is mapped to MMIO registers at a fixed PAddr.
  24. MMIO,
  25. // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP
  26. };
  27. /// Permissions for mapped memory blocks
  28. enum class VMAPermission : u8 {
  29. None = 0,
  30. Read = 1,
  31. Write = 2,
  32. Execute = 4,
  33. ReadWrite = Read | Write,
  34. ReadExecute = Read | Execute,
  35. WriteExecute = Write | Execute,
  36. ReadWriteExecute = Read | Write | Execute,
  37. };
  38. /// Set of values returned in MemoryInfo.state by svcQueryMemory.
  39. enum class MemoryState : u32 {
  40. Unmapped = 0x0,
  41. Io = 0x1,
  42. Normal = 0x2,
  43. CodeStatic = 0x3,
  44. CodeMutable = 0x4,
  45. Heap = 0x5,
  46. Shared = 0x6,
  47. ModuleCodeStatic = 0x8,
  48. ModuleCodeMutable = 0x9,
  49. IpcBuffer0 = 0xA,
  50. Mapped = 0xB,
  51. ThreadLocal = 0xC,
  52. TransferMemoryIsolated = 0xD,
  53. TransferMemory = 0xE,
  54. ProcessMemory = 0xF,
  55. IpcBuffer1 = 0x11,
  56. IpcBuffer3 = 0x12,
  57. KernelStack = 0x13,
  58. };
  59. /**
  60. * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
  61. * with homogeneous attributes across its extents. In this particular implementation each VMA is
  62. * also backed by a single host memory allocation.
  63. */
  64. struct VirtualMemoryArea {
  65. /// Virtual base address of the region.
  66. VAddr base = 0;
  67. /// Size of the region.
  68. u64 size = 0;
  69. VMAType type = VMAType::Free;
  70. VMAPermission permissions = VMAPermission::None;
  71. /// Tag returned by svcQueryMemory. Not otherwise used.
  72. MemoryState meminfo_state = MemoryState::Unmapped;
  73. // Settings for type = AllocatedMemoryBlock
  74. /// Memory block backing this VMA.
  75. std::shared_ptr<std::vector<u8>> backing_block = nullptr;
  76. /// Offset into the backing_memory the mapping starts from.
  77. std::size_t offset = 0;
  78. // Settings for type = BackingMemory
  79. /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
  80. u8* backing_memory = nullptr;
  81. // Settings for type = MMIO
  82. /// Physical address of the register area this VMA maps to.
  83. PAddr paddr = 0;
  84. Memory::MemoryHookPointer mmio_handler = nullptr;
  85. /// Tests if this area can be merged to the right with `next`.
  86. bool CanBeMergedWith(const VirtualMemoryArea& next) const;
  87. };
  88. /**
  89. * Manages a process' virtual addressing space. This class maintains a list of allocated and free
  90. * regions in the address space, along with their attributes, and allows kernel clients to
  91. * manipulate it, adjusting the page table to match.
  92. *
  93. * This is similar in idea and purpose to the VM manager present in operating system kernels, with
  94. * the main difference being that it doesn't have to support swapping or memory mapping of files.
  95. * The implementation is also simplified by not having to allocate page frames. See these articles
  96. * about the Linux kernel for an explantion of the concept and implementation:
  97. * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
  98. * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
  99. */
  100. class VMManager final {
  101. public:
  102. /**
  103. * A map covering the entirety of the managed address space, keyed by the `base` field of each
  104. * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
  105. * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
  106. * merged when possible so that no two similar and adjacent regions exist that have not been
  107. * merged.
  108. */
  109. std::map<VAddr, VirtualMemoryArea> vma_map;
  110. using VMAHandle = decltype(vma_map)::const_iterator;
  111. VMManager();
  112. ~VMManager();
  113. /// Clears the address space map, re-initializing with a single free area.
  114. void Reset(FileSys::ProgramAddressSpaceType type);
  115. /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
  116. VMAHandle FindVMA(VAddr target) const;
  117. // TODO(yuriks): Should these functions actually return the handle?
  118. /**
  119. * Maps part of a ref-counted block of memory at a given address.
  120. *
  121. * @param target The guest address to start the mapping at.
  122. * @param block The block to be mapped.
  123. * @param offset Offset into `block` to map from.
  124. * @param size Size of the mapping.
  125. * @param state MemoryState tag to attach to the VMA.
  126. */
  127. ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
  128. std::size_t offset, u64 size, MemoryState state);
  129. /**
  130. * Maps an unmanaged host memory pointer at a given address.
  131. *
  132. * @param target The guest address to start the mapping at.
  133. * @param memory The memory to be mapped.
  134. * @param size Size of the mapping.
  135. * @param state MemoryState tag to attach to the VMA.
  136. */
  137. ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state);
  138. /**
  139. * Finds the first free address that can hold a region of the desired size.
  140. *
  141. * @param size Size of the desired region.
  142. * @return The found free address.
  143. */
  144. ResultVal<VAddr> FindFreeRegion(u64 size) const;
  145. /**
  146. * Maps a memory-mapped IO region at a given address.
  147. *
  148. * @param target The guest address to start the mapping at.
  149. * @param paddr The physical address where the registers are present.
  150. * @param size Size of the mapping.
  151. * @param state MemoryState tag to attach to the VMA.
  152. * @param mmio_handler The handler that will implement read and write for this MMIO region.
  153. */
  154. ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u64 size, MemoryState state,
  155. Memory::MemoryHookPointer mmio_handler);
  156. /// Unmaps a range of addresses, splitting VMAs as necessary.
  157. ResultCode UnmapRange(VAddr target, u64 size);
  158. /// Changes the permissions of the given VMA.
  159. VMAHandle Reprotect(VMAHandle vma, VMAPermission new_perms);
  160. /// Changes the permissions of a range of addresses, splitting VMAs as necessary.
  161. ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
  162. ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
  163. ResultCode HeapFree(VAddr target, u64 size);
  164. ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size,
  165. MemoryState state = MemoryState::Mapped);
  166. /**
  167. * Scans all VMAs and updates the page table range of any that use the given vector as backing
  168. * memory. This should be called after any operation that causes reallocation of the vector.
  169. */
  170. void RefreshMemoryBlockMappings(const std::vector<u8>* block);
  171. /// Dumps the address space layout to the log, for debugging
  172. void LogLayout() const;
  173. /// Gets the total memory usage, used by svcGetInfo
  174. u64 GetTotalMemoryUsage() const;
  175. /// Gets the total heap usage, used by svcGetInfo
  176. u64 GetTotalHeapUsage() const;
  177. /// Gets the address space base address
  178. VAddr GetAddressSpaceBaseAddress() const;
  179. /// Gets the address space end address
  180. VAddr GetAddressSpaceEndAddress() const;
  181. /// Gets the total address space address size in bytes
  182. u64 GetAddressSpaceSize() const;
  183. /// Gets the address space width in bits.
  184. u64 GetAddressSpaceWidth() const;
  185. /// Gets the base address of the ASLR region.
  186. VAddr GetASLRRegionBaseAddress() const;
  187. /// Gets the end address of the ASLR region.
  188. VAddr GetASLRRegionEndAddress() const;
  189. /// Determines whether or not the specified address range is within the ASLR region.
  190. bool IsWithinASLRRegion(VAddr address, u64 size) const;
  191. /// Gets the size of the ASLR region
  192. u64 GetASLRRegionSize() const;
  193. /// Gets the base address of the code region.
  194. VAddr GetCodeRegionBaseAddress() const;
  195. /// Gets the end address of the code region.
  196. VAddr GetCodeRegionEndAddress() const;
  197. /// Gets the total size of the code region in bytes.
  198. u64 GetCodeRegionSize() const;
  199. /// Gets the base address of the heap region.
  200. VAddr GetHeapRegionBaseAddress() const;
  201. /// Gets the end address of the heap region;
  202. VAddr GetHeapRegionEndAddress() const;
  203. /// Gets the total size of the heap region in bytes.
  204. u64 GetHeapRegionSize() const;
  205. /// Gets the base address of the map region.
  206. VAddr GetMapRegionBaseAddress() const;
  207. /// Gets the end address of the map region.
  208. VAddr GetMapRegionEndAddress() const;
  209. /// Gets the total size of the map region in bytes.
  210. u64 GetMapRegionSize() const;
  211. /// Gets the base address of the new map region.
  212. VAddr GetNewMapRegionBaseAddress() const;
  213. /// Gets the end address of the new map region.
  214. VAddr GetNewMapRegionEndAddress() const;
  215. /// Gets the total size of the new map region in bytes.
  216. u64 GetNewMapRegionSize() const;
  217. /// Gets the base address of the TLS IO region.
  218. VAddr GetTLSIORegionBaseAddress() const;
  219. /// Gets the end address of the TLS IO region.
  220. VAddr GetTLSIORegionEndAddress() const;
  221. /// Gets the total size of the TLS IO region in bytes.
  222. u64 GetTLSIORegionSize() const;
  223. /// Each VMManager has its own page table, which is set as the main one when the owning process
  224. /// is scheduled.
  225. Memory::PageTable page_table;
  226. private:
  227. using VMAIter = decltype(vma_map)::iterator;
  228. /// Converts a VMAHandle to a mutable VMAIter.
  229. VMAIter StripIterConstness(const VMAHandle& iter);
  230. /// Unmaps the given VMA.
  231. VMAIter Unmap(VMAIter vma);
  232. /**
  233. * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
  234. * the appropriate error checking.
  235. */
  236. ResultVal<VMAIter> CarveVMA(VAddr base, u64 size);
  237. /**
  238. * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each
  239. * end of the range.
  240. */
  241. ResultVal<VMAIter> CarveVMARange(VAddr base, u64 size);
  242. /**
  243. * Splits a VMA in two, at the specified offset.
  244. * @returns the right side of the split, with the original iterator becoming the left side.
  245. */
  246. VMAIter SplitVMA(VMAIter vma, u64 offset_in_vma);
  247. /**
  248. * Checks for and merges the specified VMA with adjacent ones if possible.
  249. * @returns the merged VMA or the original if no merging was possible.
  250. */
  251. VMAIter MergeAdjacent(VMAIter vma);
  252. /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
  253. void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
  254. /// Initializes memory region ranges to adhere to a given address space type.
  255. void InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type);
  256. /// Clears the underlying map and page table.
  257. void Clear();
  258. /// Clears out the VMA map, unmapping any previously mapped ranges.
  259. void ClearVMAMap();
  260. /// Clears out the page table
  261. void ClearPageTable();
  262. u32 address_space_width = 0;
  263. VAddr address_space_base = 0;
  264. VAddr address_space_end = 0;
  265. VAddr aslr_region_base = 0;
  266. VAddr aslr_region_end = 0;
  267. VAddr code_region_base = 0;
  268. VAddr code_region_end = 0;
  269. VAddr heap_region_base = 0;
  270. VAddr heap_region_end = 0;
  271. VAddr map_region_base = 0;
  272. VAddr map_region_end = 0;
  273. VAddr new_map_region_base = 0;
  274. VAddr new_map_region_end = 0;
  275. VAddr tls_io_region_base = 0;
  276. VAddr tls_io_region_end = 0;
  277. // Memory used to back the allocations in the regular heap. A single vector is used to cover
  278. // the entire virtual address space extents that bound the allocations, including any holes.
  279. // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
  280. // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
  281. std::shared_ptr<std::vector<u8>> heap_memory;
  282. // The left/right bounds of the address space covered by heap_memory.
  283. VAddr heap_start = 0;
  284. VAddr heap_end = 0;
  285. u64 heap_used = 0;
  286. };
  287. } // namespace Kernel