| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  | // Copyright 2018 yuzu emulator team
 | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  | #include <map>
 | 
					
						
							| 
									
										
										
										
											2018-10-30 05:03:25 +01:00
										 |  |  | #include <optional>
 | 
					
						
							| 
									
										
										
										
											2018-04-21 12:31:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | #include "common/common_types.h"
 | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  | #include "common/page_table.h"
 | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-15 17:47:15 -05:00
										 |  |  | namespace VideoCore { | 
					
						
							|  |  |  | class RasterizerInterface; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-08 23:17:44 -07:00
										 |  |  | namespace Core { | 
					
						
							|  |  |  | class System; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-11 23:44:12 -05:00
										 |  |  | namespace Tegra { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space | 
					
						
							|  |  |  |  * with homogeneous attributes across its extents. In this particular implementation each VMA is | 
					
						
							|  |  |  |  * also backed by a single host memory allocation. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct VirtualMemoryArea { | 
					
						
							|  |  |  |     enum class Type : u8 { | 
					
						
							|  |  |  |         Unmapped, | 
					
						
							|  |  |  |         Allocated, | 
					
						
							|  |  |  |         Mapped, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Virtual base address of the region.
 | 
					
						
							|  |  |  |     GPUVAddr base{}; | 
					
						
							|  |  |  |     /// Size of the region.
 | 
					
						
							|  |  |  |     u64 size{}; | 
					
						
							|  |  |  |     /// Memory area mapping type.
 | 
					
						
							|  |  |  |     Type type{Type::Unmapped}; | 
					
						
							|  |  |  |     /// CPU memory mapped address corresponding to this memory area.
 | 
					
						
							|  |  |  |     VAddr backing_addr{}; | 
					
						
							|  |  |  |     /// Offset into the backing_memory the mapping starts from.
 | 
					
						
							|  |  |  |     std::size_t offset{}; | 
					
						
							|  |  |  |     /// Pointer backing this VMA.
 | 
					
						
							|  |  |  |     u8* backing_memory{}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Tests if this area can be merged to the right with `next`.
 | 
					
						
							|  |  |  |     bool CanBeMergedWith(const VirtualMemoryArea& next) const; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | class MemoryManager final { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-02-15 17:47:15 -05:00
										 |  |  |     explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer); | 
					
						
							| 
									
										
										
										
											2019-05-09 19:04:41 -04:00
										 |  |  |     ~MemoryManager(); | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-21 11:16:21 -04:00
										 |  |  |     GPUVAddr AllocateSpace(u64 size, u64 align); | 
					
						
							| 
									
										
										
										
											2019-03-09 14:06:51 -05:00
										 |  |  |     GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align); | 
					
						
							| 
									
										
										
										
											2019-03-20 22:28:35 -04:00
										 |  |  |     GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size); | 
					
						
							|  |  |  |     GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr addr, u64 size); | 
					
						
							| 
									
										
										
										
											2019-03-09 14:06:51 -05:00
										 |  |  |     GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size); | 
					
						
							| 
									
										
										
										
											2019-04-05 20:18:27 -04:00
										 |  |  |     std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const; | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |     template <typename T> | 
					
						
							| 
									
										
										
										
											2019-04-05 20:30:46 -04:00
										 |  |  |     T Read(GPUVAddr addr) const; | 
					
						
							| 
									
										
										
										
											2019-02-24 00:15:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |     template <typename T> | 
					
						
							| 
									
										
										
										
											2019-03-09 14:06:51 -05:00
										 |  |  |     void Write(GPUVAddr addr, T data); | 
					
						
							| 
									
										
										
										
											2019-02-24 00:15:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-09 14:06:51 -05:00
										 |  |  |     u8* GetPointer(GPUVAddr addr); | 
					
						
							| 
									
										
										
										
											2019-04-05 20:25:25 -04:00
										 |  |  |     const u8* GetPointer(GPUVAddr addr) const; | 
					
						
							| 
									
										
										
										
											2019-02-24 00:15:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-09 19:13:14 -04:00
										 |  |  |     /// Returns true if the block is continuous in host memory, false otherwise
 | 
					
						
							|  |  |  |     bool IsBlockContinuous(GPUVAddr start, std::size_t size) const; | 
					
						
							| 
									
										
										
										
											2019-04-16 15:45:24 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							| 
									
										
										
										
											2019-04-16 10:11:35 -04:00
										 |  |  |      * ReadBlock and WriteBlock are full read and write operations over virtual | 
					
						
							| 
									
										
										
										
											2019-05-09 19:02:52 -04:00
										 |  |  |      * GPU Memory. It's important to use these when GPU memory may not be continuous | 
					
						
							| 
									
										
										
										
											2019-04-16 10:11:35 -04:00
										 |  |  |      * in the Host Memory counterpart. Note: This functions cause Host GPU Memory | 
					
						
							|  |  |  |      * Flushes and Invalidations, respectively to each operation. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-05-09 18:59:47 -04:00
										 |  |  |     void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const; | 
					
						
							|  |  |  |     void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size); | 
					
						
							|  |  |  |     void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size); | 
					
						
							| 
									
										
										
										
											2019-04-16 10:11:35 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 15:45:24 -04:00
										 |  |  |     /**
 | 
					
						
							| 
									
										
										
										
											2019-04-16 10:11:35 -04:00
										 |  |  |      * ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and | 
					
						
							|  |  |  |      * WriteBlock respectively. In this versions, no flushing or invalidation is actually | 
					
						
							|  |  |  |      * done and their performance is similar to a memcpy. This functions can be used | 
					
						
							|  |  |  |      * on either of this 2 scenarios instead of their safe counterpart: | 
					
						
							|  |  |  |      * - Memory which is sure to never be represented in the Host GPU. | 
					
						
							|  |  |  |      * - Memory Managed by a Cache Manager. Example: Texture Flushing should use | 
					
						
							|  |  |  |      * WriteBlockUnsafe instead of WriteBlock since it shouldn't invalidate the texture | 
					
						
							|  |  |  |      * being flushed. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-05-09 18:59:47 -04:00
										 |  |  |     void ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const; | 
					
						
							|  |  |  |     void WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer, std::size_t size); | 
					
						
							|  |  |  |     void CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size); | 
					
						
							| 
									
										
										
										
											2019-04-16 10:11:35 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |     using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>; | 
					
						
							|  |  |  |     using VMAHandle = VMAMap::const_iterator; | 
					
						
							|  |  |  |     using VMAIter = VMAMap::iterator; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-09 14:06:51 -05:00
										 |  |  |     bool IsAddressValid(GPUVAddr addr) const; | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |     void MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type, | 
					
						
							|  |  |  |                   VAddr backing_addr = 0); | 
					
						
							|  |  |  |     void MapMemoryRegion(GPUVAddr base, u64 size, u8* target, VAddr backing_addr); | 
					
						
							|  |  |  |     void UnmapRegion(GPUVAddr base, u64 size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
 | 
					
						
							|  |  |  |     VMAHandle FindVMA(GPUVAddr target) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMAHandle AllocateMemory(GPUVAddr target, std::size_t offset, u64 size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Maps an unmanaged host memory pointer at a given address. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-05-09 19:02:52 -04:00
										 |  |  |      * @param target       The guest address to start the mapping at. | 
					
						
							|  |  |  |      * @param memory       The memory to be mapped. | 
					
						
							|  |  |  |      * @param size         Size of the mapping in bytes. | 
					
						
							|  |  |  |      * @param backing_addr The base address of the range to back this mapping. | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |      */ | 
					
						
							|  |  |  |     VMAHandle MapBackingMemory(GPUVAddr target, u8* memory, u64 size, VAddr backing_addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Unmaps a range of addresses, splitting VMAs as necessary.
 | 
					
						
							|  |  |  |     void UnmapRange(GPUVAddr target, u64 size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Converts a VMAHandle to a mutable VMAIter.
 | 
					
						
							|  |  |  |     VMAIter StripIterConstness(const VMAHandle& iter); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-09 19:02:52 -04:00
										 |  |  |     /// Marks as the specified VMA as allocated.
 | 
					
						
							| 
									
										
										
										
											2019-03-20 22:28:35 -04:00
										 |  |  |     VMAIter Allocate(VMAIter vma); | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing | 
					
						
							|  |  |  |      * the appropriate error checking. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     VMAIter CarveVMA(GPUVAddr base, u64 size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each | 
					
						
							|  |  |  |      * end of the range. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     VMAIter CarveVMARange(GPUVAddr base, u64 size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Splits a VMA in two, at the specified offset. | 
					
						
							|  |  |  |      * @returns the right side of the split, with the original iterator becoming the left side. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     VMAIter SplitVMA(VMAIter vma, u64 offset_in_vma); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Checks for and merges the specified VMA with adjacent ones if possible. | 
					
						
							|  |  |  |      * @returns the merged VMA or the original if no merging was possible. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     VMAIter MergeAdjacent(VMAIter vma); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
 | 
					
						
							|  |  |  |     void UpdatePageTableForVMA(const VirtualMemoryArea& vma); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-20 23:12:28 -04:00
										 |  |  |     /// Finds a free (unmapped region) of the specified size starting at the specified address.
 | 
					
						
							| 
									
										
										
										
											2019-04-05 20:22:53 -04:00
										 |  |  |     GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size) const; | 
					
						
							| 
									
										
										
										
											2018-04-21 14:40:51 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  | private: | 
					
						
							|  |  |  |     static constexpr u64 page_bits{16}; | 
					
						
							|  |  |  |     static constexpr u64 page_size{1 << page_bits}; | 
					
						
							|  |  |  |     static constexpr u64 page_mask{page_size - 1}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-09 17:47:15 -04:00
										 |  |  |     /// Address space in bits, according to Tegra X1 TRM
 | 
					
						
							|  |  |  |     static constexpr u32 address_space_width{40}; | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |     /// Start address for mapping, this is fairly arbitrary but must be non-zero.
 | 
					
						
							| 
									
										
										
										
											2019-03-20 22:28:35 -04:00
										 |  |  |     static constexpr GPUVAddr address_space_base{0x100000}; | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |     /// End of address space, based on address space in bits.
 | 
					
						
							| 
									
										
										
										
											2019-03-20 22:28:35 -04:00
										 |  |  |     static constexpr GPUVAddr address_space_end{1ULL << address_space_width}; | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-13 16:33:47 -04:00
										 |  |  |     Common::BackingPageTable page_table{page_bits}; | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |     VMAMap vma_map; | 
					
						
							| 
									
										
										
										
											2020-02-15 17:47:15 -05:00
										 |  |  |     VideoCore::RasterizerInterface& rasterizer; | 
					
						
							| 
									
										
										
										
											2019-07-08 23:17:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Core::System& system; | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-11 23:44:12 -05:00
										 |  |  | } // namespace Tegra
 |