| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-28 21:58:28 -04:00
										 |  |  | namespace VideoCore { | 
					
						
							|  |  |  | class RasterizerInterface; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2019-03-28 21:58:28 -04:00
										 |  |  |     MemoryManager(VideoCore::RasterizerInterface& rasterizer); | 
					
						
							| 
									
										
										
										
											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-04-05 20:27:57 -04:00
										 |  |  |     void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const; | 
					
						
							| 
									
										
										
										
											2019-02-24 00:15:35 -05:00
										 |  |  |     void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size); | 
					
						
							| 
									
										
										
										
											2019-04-15 23:01:35 -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); | 
					
						
							| 
									
										
										
										
											2019-03-03 23:54:16 -05:00
										 |  |  |     void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size); | 
					
						
							| 
									
										
										
										
											2019-02-24 00:15:35 -05: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. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param target The guest address to start the mapping at. | 
					
						
							|  |  |  |      * @param memory The memory to be mapped. | 
					
						
							|  |  |  |      * @param size Size of the mapping. | 
					
						
							|  |  |  |      * @param state MemoryState tag to attach to the VMA. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     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-03-20 22:28:35 -04:00
										 |  |  |     /// Marks as the specfied VMA as allocated.
 | 
					
						
							|  |  |  |     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}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Address space in bits, this is fairly arbitrary but sufficiently large.
 | 
					
						
							| 
									
										
										
										
											2019-03-20 22:28:35 -04:00
										 |  |  |     static constexpr u32 address_space_width{39}; | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  |     Common::PageTable page_table{page_bits}; | 
					
						
							|  |  |  |     VMAMap vma_map; | 
					
						
							| 
									
										
										
										
											2019-03-28 21:58:28 -04:00
										 |  |  |     VideoCore::RasterizerInterface& rasterizer; | 
					
						
							| 
									
										
										
										
											2018-02-07 21:54:35 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-11 23:44:12 -05:00
										 |  |  | } // namespace Tegra
 |