| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | // Copyright 2014 Citra Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 12:42:32 -07:00
										 |  |  | #include <array>
 | 
					
						
							| 
									
										
										
										
											2015-06-21 13:12:49 +01:00
										 |  |  | #include <cstddef>
 | 
					
						
							| 
									
										
										
										
											2016-06-27 20:42:42 +03:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2018-01-27 15:16:39 +00:00
										 |  |  | #include <tuple>
 | 
					
						
							|  |  |  | #include <boost/icl/interval_map.hpp>
 | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | #include "common/common_types.h"
 | 
					
						
							| 
									
										
										
										
											2018-01-27 15:16:39 +00:00
										 |  |  | #include "core/memory_hook.h"
 | 
					
						
							| 
									
										
										
										
											2018-04-24 00:19:36 -04:00
										 |  |  | #include "video_core/memory_manager.h"
 | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-26 17:27:44 -05:00
										 |  |  | namespace Kernel { | 
					
						
							|  |  |  | class Process; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Memory { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-12 23:38:56 -03:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Page size used by the ARM architecture. This is the smallest granularity with which memory can | 
					
						
							|  |  |  |  * be mapped. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-02-12 21:53:32 +00:00
										 |  |  | constexpr size_t PAGE_BITS = 12; | 
					
						
							|  |  |  | constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; | 
					
						
							|  |  |  | constexpr u64 PAGE_MASK = PAGE_SIZE - 1; | 
					
						
							|  |  |  | constexpr size_t ADDRESS_SPACE_BITS = 36; | 
					
						
							|  |  |  | constexpr size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS); | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-27 15:16:39 +00:00
										 |  |  | enum class PageType : u8 { | 
					
						
							| 
									
										
										
										
											2017-07-21 21:17:57 -05:00
										 |  |  |     /// Page is unmapped and should cause an access error.
 | 
					
						
							|  |  |  |     Unmapped, | 
					
						
							|  |  |  |     /// Page is mapped to regular memory. This is the only type you can get pointers to.
 | 
					
						
							|  |  |  |     Memory, | 
					
						
							| 
									
										
										
										
											2018-03-22 22:56:41 -04:00
										 |  |  |     /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
 | 
					
						
							|  |  |  |     /// invalidation
 | 
					
						
							|  |  |  |     RasterizerCachedMemory, | 
					
						
							|  |  |  |     /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
 | 
					
						
							| 
									
										
										
										
											2017-07-21 21:17:57 -05:00
										 |  |  |     Special, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct SpecialRegion { | 
					
						
							| 
									
										
										
										
											2018-01-27 15:16:39 +00:00
										 |  |  |     enum class Type { | 
					
						
							|  |  |  |         DebugHook, | 
					
						
							|  |  |  |         IODevice, | 
					
						
							|  |  |  |     } type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MemoryHookPointer handler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool operator<(const SpecialRegion& other) const { | 
					
						
							|  |  |  |         return std::tie(type, handler) < std::tie(other.type, other.handler); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool operator==(const SpecialRegion& other) const { | 
					
						
							|  |  |  |         return std::tie(type, handler) == std::tie(other.type, other.handler); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-21 21:17:57 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely | 
					
						
							| 
									
										
										
										
											2018-01-27 15:16:39 +00:00
										 |  |  |  * mimics the way a real CPU page table works. | 
					
						
							| 
									
										
										
										
											2017-07-21 21:17:57 -05:00
										 |  |  |  */ | 
					
						
							|  |  |  | struct PageTable { | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Array of memory pointers backing each page. An entry can only be non-null if the | 
					
						
							|  |  |  |      * corresponding entry in the `attributes` array is of type `Memory`. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     std::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of | 
					
						
							|  |  |  |      * type `Special`. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2018-01-27 15:16:39 +00:00
										 |  |  |     boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions; | 
					
						
							| 
									
										
										
										
											2017-07-21 21:17:57 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Array of fine grained page attributes. If it is set to any value other than `Memory`, then | 
					
						
							|  |  |  |      * the corresponding entry in `pointers` MUST be set to null. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | /// Virtual user-space memory regions
 | 
					
						
							|  |  |  | enum : VAddr { | 
					
						
							|  |  |  |     /// Where the application text, data and bss reside.
 | 
					
						
							| 
									
										
										
										
											2017-10-09 21:39:32 -04:00
										 |  |  |     PROCESS_IMAGE_VADDR = 0x08000000, | 
					
						
							|  |  |  |     PROCESS_IMAGE_MAX_SIZE = 0x08000000, | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  |     PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Read-only page containing kernel and system configuration values.
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     CONFIG_MEMORY_VADDR = 0x1FF80000, | 
					
						
							|  |  |  |     CONFIG_MEMORY_SIZE = 0x00001000, | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  |     CONFIG_MEMORY_VADDR_END = CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Usually read-only page containing mostly values read from hardware.
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     SHARED_PAGE_VADDR = 0x1FF81000, | 
					
						
							|  |  |  |     SHARED_PAGE_SIZE = 0x00001000, | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  |     SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 22:06:57 -04:00
										 |  |  |     /// Area where TLS (Thread-Local Storage) buffers are allocated.
 | 
					
						
							| 
									
										
										
										
											2018-08-02 23:37:44 -04:00
										 |  |  |     TLS_AREA_VADDR = 0x40000000, | 
					
						
							| 
									
										
										
										
											2018-03-14 22:06:57 -04:00
										 |  |  |     TLS_ENTRY_SIZE = 0x200, | 
					
						
							|  |  |  |     TLS_AREA_SIZE = 0x10000000, | 
					
						
							| 
									
										
										
										
											2018-03-31 15:03:28 -04:00
										 |  |  |     TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, | 
					
						
							| 
									
										
										
										
											2018-03-14 22:06:57 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Application stack
 | 
					
						
							| 
									
										
										
										
											2018-03-31 15:03:28 -04:00
										 |  |  |     STACK_AREA_VADDR = TLS_AREA_VADDR_END, | 
					
						
							|  |  |  |     STACK_AREA_SIZE = 0x10000000, | 
					
						
							|  |  |  |     STACK_AREA_VADDR_END = STACK_AREA_VADDR + STACK_AREA_SIZE, | 
					
						
							|  |  |  |     DEFAULT_STACK_SIZE = 0x100000, | 
					
						
							| 
									
										
										
										
											2018-03-14 22:06:57 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Application heap
 | 
					
						
							|  |  |  |     /// Size is confirmed to be a static value on fw 3.0.0
 | 
					
						
							|  |  |  |     HEAP_VADDR = 0x108000000, | 
					
						
							|  |  |  |     HEAP_SIZE = 0x180000000, | 
					
						
							|  |  |  |     HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// New map region
 | 
					
						
							|  |  |  |     /// Size is confirmed to be a static value on fw 3.0.0
 | 
					
						
							|  |  |  |     NEW_MAP_REGION_VADDR = HEAP_VADDR_END, | 
					
						
							|  |  |  |     NEW_MAP_REGION_SIZE = 0x80000000, | 
					
						
							|  |  |  |     NEW_MAP_REGION_VADDR_END = NEW_MAP_REGION_VADDR + NEW_MAP_REGION_SIZE, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Map region
 | 
					
						
							|  |  |  |     /// Size is confirmed to be a static value on fw 3.0.0
 | 
					
						
							|  |  |  |     MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END, | 
					
						
							|  |  |  |     MAP_REGION_SIZE = 0x1000000000, | 
					
						
							|  |  |  |     MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE, | 
					
						
							| 
									
										
										
										
											2018-06-22 00:47:59 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Kernel Virtual Address Range
 | 
					
						
							|  |  |  |     KERNEL_REGION_VADDR = 0xFFFFFF8000000000, | 
					
						
							|  |  |  |     KERNEL_REGION_SIZE = 0x7FFFE00000, | 
					
						
							|  |  |  |     KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-21 21:17:57 -05:00
										 |  |  | /// Currently active page table
 | 
					
						
							| 
									
										
										
										
											2017-09-24 22:42:42 +01:00
										 |  |  | void SetCurrentPageTable(PageTable* page_table); | 
					
						
							|  |  |  | PageTable* GetCurrentPageTable(); | 
					
						
							| 
									
										
										
										
											2017-07-21 21:17:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-26 17:27:44 -05:00
										 |  |  | /// Determines if the given VAddr is valid for the specified process.
 | 
					
						
							|  |  |  | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr); | 
					
						
							| 
									
										
										
										
											2016-04-16 08:46:11 +01:00
										 |  |  | bool IsValidVirtualAddress(const VAddr addr); | 
					
						
							| 
									
										
										
										
											2018-06-22 00:47:59 -06:00
										 |  |  | /// Determines if the given VAddr is a kernel address
 | 
					
						
							|  |  |  | bool IsKernelVirtualAddress(const VAddr addr); | 
					
						
							| 
									
										
										
										
											2017-09-26 17:27:44 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | u8 Read8(VAddr addr); | 
					
						
							|  |  |  | u16 Read16(VAddr addr); | 
					
						
							|  |  |  | u32 Read32(VAddr addr); | 
					
						
							|  |  |  | u64 Read64(VAddr addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Write8(VAddr addr, u8 data); | 
					
						
							|  |  |  | void Write16(VAddr addr, u16 data); | 
					
						
							|  |  |  | void Write32(VAddr addr, u32 data); | 
					
						
							|  |  |  | void Write64(VAddr addr, u64 data); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-29 19:38:54 -05:00
										 |  |  | void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, | 
					
						
							|  |  |  |                size_t size); | 
					
						
							| 
									
										
										
										
											2016-04-19 14:08:02 -05:00
										 |  |  | void ReadBlock(const VAddr src_addr, void* dest_buffer, size_t size); | 
					
						
							| 
									
										
										
										
											2017-09-29 22:42:25 -05:00
										 |  |  | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, | 
					
						
							|  |  |  |                 size_t size); | 
					
						
							| 
									
										
										
										
											2016-04-19 14:08:02 -05:00
										 |  |  | void WriteBlock(const VAddr dest_addr, const void* src_buffer, size_t size); | 
					
						
							| 
									
										
										
										
											2016-04-16 10:21:41 +01:00
										 |  |  | void ZeroBlock(const VAddr dest_addr, const size_t size); | 
					
						
							| 
									
										
										
										
											2016-04-16 15:22:45 +01:00
										 |  |  | void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size); | 
					
						
							| 
									
										
										
										
											2015-05-12 22:38:29 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | u8* GetPointer(VAddr virtual_address); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-27 20:42:42 +03:00
										 |  |  | std::string ReadCString(VAddr virtual_address, std::size_t max_length); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-22 22:56:41 -04:00
										 |  |  | enum class FlushMode { | 
					
						
							|  |  |  |     /// Write back modified surfaces to RAM
 | 
					
						
							|  |  |  |     Flush, | 
					
						
							|  |  |  |     /// Remove region from the cache
 | 
					
						
							|  |  |  |     Invalidate, | 
					
						
							|  |  |  |     /// Write back modified surfaces to RAM, and also remove them from the cache
 | 
					
						
							|  |  |  |     FlushAndInvalidate, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-24 22:21:14 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Mark each page touching the region as cached. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-04-24 00:19:36 -04:00
										 |  |  | void RasterizerMarkRegionCached(Tegra::GPUVAddr start, u64 size, bool cached); | 
					
						
							| 
									
										
										
										
											2018-03-24 22:21:14 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-22 22:56:41 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Flushes and invalidates any externally cached rasterizer resources touching the given virtual | 
					
						
							|  |  |  |  * address region. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-23 15:01:45 -04:00
										 |  |  | void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode); | 
					
						
							| 
									
										
										
										
											2018-03-22 22:56:41 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-21 21:17:57 -05:00
										 |  |  | } // namespace Memory
 |