1 // Copyright 2014 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <array>
8 #include <cstddef>
9 #include <memory>
10 #include <string>
11 #include <vector>
12 #include <boost/serialization/array.hpp>
13 #include <boost/serialization/vector.hpp>
14 #include "common/common_types.h"
15 #include "common/memory_ref.h"
16 #include "core/mmio.h"
17 
18 class ARM_Interface;
19 
20 namespace Kernel {
21 class Process;
22 }
23 
24 namespace AudioCore {
25 class DspInterface;
26 }
27 
28 namespace Memory {
29 
30 // Are defined in a system header
31 #undef PAGE_SIZE
32 #undef PAGE_MASK
33 /**
34  * Page size used by the ARM architecture. This is the smallest granularity with which memory can
35  * be mapped.
36  */
37 const u32 PAGE_SIZE = 0x1000;
38 const u32 PAGE_MASK = PAGE_SIZE - 1;
39 const int PAGE_BITS = 12;
40 const std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - PAGE_BITS);
41 
42 enum class PageType {
43     /// Page is unmapped and should cause an access error.
44     Unmapped,
45     /// Page is mapped to regular memory. This is the only type you can get pointers to.
46     Memory,
47     /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
48     /// invalidation
49     RasterizerCachedMemory,
50     /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
51     Special,
52 };
53 
54 struct SpecialRegion {
55     VAddr base;
56     u32 size;
57     MMIORegionPointer handler;
58 
59 private:
60     template <class Archive>
serializeSpecialRegion61     void serialize(Archive& ar, const unsigned int file_version) {
62         ar& base;
63         ar& size;
64         ar& handler;
65     }
66     friend class boost::serialization::access;
67 };
68 
69 /**
70  * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely
71  * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and
72  * fetching requirements when accessing. In the usual case of an access to regular memory, it only
73  * requires an indexed fetch and a check for NULL.
74  */
75 struct PageTable {
76     /**
77      * Array of memory pointers backing each page. An entry can only be non-null if the
78      * corresponding entry in the `attributes` array is of type `Memory`.
79      */
80 
81     // The reason for this rigmarole is to keep the 'raw' and 'refs' arrays in sync.
82     // We need 'raw' for dynarmic and 'refs' for serialization
83     struct Pointers {
84 
85         struct Entry {
EntryPageTable::Pointers::Entry86             Entry(Pointers& pointers_, VAddr idx_) : pointers(pointers_), idx(idx_) {}
87 
88             Entry& operator=(MemoryRef value) {
89                 pointers.raw[idx] = value.GetPtr();
90                 pointers.refs[idx] = std::move(value);
91                 return *this;
92             }
93 
94             operator u8*() {
95                 return pointers.raw[idx];
96             }
97 
98         private:
99             Pointers& pointers;
100             VAddr idx;
101         };
102 
103         Entry operator[](std::size_t idx) {
104             return Entry(*this, static_cast<VAddr>(idx));
105         }
106 
107     private:
108         std::array<u8*, PAGE_TABLE_NUM_ENTRIES> raw;
109 
110         std::array<MemoryRef, PAGE_TABLE_NUM_ENTRIES> refs;
111 
112         friend struct PageTable;
113     };
114     Pointers pointers;
115 
116     /**
117      * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of
118      * type `Special`.
119      */
120     std::vector<SpecialRegion> special_regions;
121 
122     /**
123      * Array of fine grained page attributes. If it is set to any value other than `Memory`, then
124      * the corresponding entry in `pointers` MUST be set to null.
125      */
126     std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
127 
GetPointerArrayPageTable128     std::array<u8*, PAGE_TABLE_NUM_ENTRIES>& GetPointerArray() {
129         return pointers.raw;
130     }
131 
132     void Clear();
133 
134 private:
135     template <class Archive>
serializePageTable136     void serialize(Archive& ar, const unsigned int) {
137         ar& pointers.refs;
138         ar& special_regions;
139         ar& attributes;
140         for (std::size_t i = 0; i < PAGE_TABLE_NUM_ENTRIES; i++) {
141             pointers.raw[i] = pointers.refs[i].GetPtr();
142         }
143     }
144     friend class boost::serialization::access;
145 };
146 
147 /// Physical memory regions as seen from the ARM11
148 enum : PAddr {
149     /// IO register area
150     IO_AREA_PADDR = 0x10100000,
151     IO_AREA_SIZE = 0x00400000, ///< IO area size (4MB)
152     IO_AREA_PADDR_END = IO_AREA_PADDR + IO_AREA_SIZE,
153 
154     /// MPCore internal memory region
155     MPCORE_RAM_PADDR = 0x17E00000,
156     MPCORE_RAM_SIZE = 0x00002000, ///< MPCore internal memory size (8KB)
157     MPCORE_RAM_PADDR_END = MPCORE_RAM_PADDR + MPCORE_RAM_SIZE,
158 
159     /// Video memory
160     VRAM_PADDR = 0x18000000,
161     VRAM_SIZE = 0x00600000, ///< VRAM size (6MB)
162     VRAM_PADDR_END = VRAM_PADDR + VRAM_SIZE,
163 
164     /// New 3DS additional memory. Supposedly faster than regular FCRAM. Part of it can be used by
165     /// applications and system modules if mapped via the ExHeader.
166     N3DS_EXTRA_RAM_PADDR = 0x1F000000,
167     N3DS_EXTRA_RAM_SIZE = 0x00400000, ///< New 3DS additional memory size (4MB)
168     N3DS_EXTRA_RAM_PADDR_END = N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_SIZE,
169 
170     /// DSP memory
171     DSP_RAM_PADDR = 0x1FF00000,
172     DSP_RAM_SIZE = 0x00080000, ///< DSP memory size (512KB)
173     DSP_RAM_PADDR_END = DSP_RAM_PADDR + DSP_RAM_SIZE,
174 
175     /// AXI WRAM
176     AXI_WRAM_PADDR = 0x1FF80000,
177     AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size (512KB)
178     AXI_WRAM_PADDR_END = AXI_WRAM_PADDR + AXI_WRAM_SIZE,
179 
180     /// Main FCRAM
181     FCRAM_PADDR = 0x20000000,
182     FCRAM_SIZE = 0x08000000,      ///< FCRAM size on the Old 3DS (128MB)
183     FCRAM_N3DS_SIZE = 0x10000000, ///< FCRAM size on the New 3DS (256MB)
184     FCRAM_PADDR_END = FCRAM_PADDR + FCRAM_SIZE,
185     FCRAM_N3DS_PADDR_END = FCRAM_PADDR + FCRAM_N3DS_SIZE,
186 };
187 
188 enum class Region { FCRAM, VRAM, DSP, N3DS };
189 
190 /// Virtual user-space memory regions
191 enum : VAddr {
192     /// Where the application text, data and bss reside.
193     PROCESS_IMAGE_VADDR = 0x00100000,
194     PROCESS_IMAGE_MAX_SIZE = 0x03F00000,
195     PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
196 
197     /// Area where IPC buffers are mapped onto.
198     IPC_MAPPING_VADDR = 0x04000000,
199     IPC_MAPPING_SIZE = 0x04000000,
200     IPC_MAPPING_VADDR_END = IPC_MAPPING_VADDR + IPC_MAPPING_SIZE,
201 
202     /// Application heap (includes stack).
203     HEAP_VADDR = 0x08000000,
204     HEAP_SIZE = 0x08000000,
205     HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE,
206 
207     /// Area where shared memory buffers are mapped onto.
208     SHARED_MEMORY_VADDR = 0x10000000,
209     SHARED_MEMORY_SIZE = 0x04000000,
210     SHARED_MEMORY_VADDR_END = SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE,
211 
212     /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical
213     /// memory.
214     LINEAR_HEAP_VADDR = 0x14000000,
215     LINEAR_HEAP_SIZE = 0x08000000,
216     LINEAR_HEAP_VADDR_END = LINEAR_HEAP_VADDR + LINEAR_HEAP_SIZE,
217 
218     /// Maps 1:1 to New 3DS additional memory
219     N3DS_EXTRA_RAM_VADDR = 0x1E800000,
220     N3DS_EXTRA_RAM_VADDR_END = N3DS_EXTRA_RAM_VADDR + N3DS_EXTRA_RAM_SIZE,
221 
222     /// Maps 1:1 to the IO register area.
223     IO_AREA_VADDR = 0x1EC00000,
224     IO_AREA_VADDR_END = IO_AREA_VADDR + IO_AREA_SIZE,
225 
226     /// Maps 1:1 to VRAM.
227     VRAM_VADDR = 0x1F000000,
228     VRAM_VADDR_END = VRAM_VADDR + VRAM_SIZE,
229 
230     /// Maps 1:1 to DSP memory.
231     DSP_RAM_VADDR = 0x1FF00000,
232     DSP_RAM_VADDR_END = DSP_RAM_VADDR + DSP_RAM_SIZE,
233 
234     /// Read-only page containing kernel and system configuration values.
235     CONFIG_MEMORY_VADDR = 0x1FF80000,
236     CONFIG_MEMORY_SIZE = 0x00001000,
237     CONFIG_MEMORY_VADDR_END = CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE,
238 
239     /// Usually read-only page containing mostly values read from hardware.
240     SHARED_PAGE_VADDR = 0x1FF81000,
241     SHARED_PAGE_SIZE = 0x00001000,
242     SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
243 
244     /// Area where TLS (Thread-Local Storage) buffers are allocated.
245     TLS_AREA_VADDR = 0x1FF82000,
246     TLS_ENTRY_SIZE = 0x200,
247 
248     /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
249     NEW_LINEAR_HEAP_VADDR = 0x30000000,
250     NEW_LINEAR_HEAP_SIZE = 0x10000000,
251     NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
252 };
253 
254 /**
255  * Flushes any externally cached rasterizer resources touching the given region.
256  */
257 void RasterizerFlushRegion(PAddr start, u32 size);
258 
259 /**
260  * Invalidates any externally cached rasterizer resources touching the given region.
261  */
262 void RasterizerInvalidateRegion(PAddr start, u32 size);
263 
264 /**
265  * Flushes and invalidates any externally cached rasterizer resources touching the given region.
266  */
267 void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size);
268 
269 enum class FlushMode {
270     /// Write back modified surfaces to RAM
271     Flush,
272     /// Remove region from the cache
273     Invalidate,
274     /// Write back modified surfaces to RAM, and also remove them from the cache
275     FlushAndInvalidate,
276 };
277 
278 /**
279  * Flushes and invalidates all memory in the rasterizer cache and removes any leftover state
280  * If flush is true, the rasterizer should flush any cached resources to RAM before clearing
281  */
282 void RasterizerClearAll(bool flush);
283 
284 /**
285  * Flushes and invalidates any externally cached rasterizer resources touching the given virtual
286  * address region.
287  */
288 void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode);
289 
290 class MemorySystem {
291 public:
292     MemorySystem();
293     ~MemorySystem();
294 
295     /**
296      * Maps an allocated buffer onto a region of the emulated process address space.
297      *
298      * @param page_table The page table of the emulated process.
299      * @param base The address to start mapping at. Must be page-aligned.
300      * @param size The amount of bytes to map. Must be page-aligned.
301      * @param target Buffer with the memory backing the mapping. Must be of length at least `size`.
302      */
303     void MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target);
304 
305     /**
306      * Maps a region of the emulated process address space as a IO region.
307      * @param page_table The page table of the emulated process.
308      * @param base The address to start mapping at. Must be page-aligned.
309      * @param size The amount of bytes to map. Must be page-aligned.
310      * @param mmio_handler The handler that backs the mapping.
311      */
312     void MapIoRegion(PageTable& page_table, VAddr base, u32 size, MMIORegionPointer mmio_handler);
313 
314     void UnmapRegion(PageTable& page_table, VAddr base, u32 size);
315 
316     /// Currently active page table
317     void SetCurrentPageTable(std::shared_ptr<PageTable> page_table);
318     std::shared_ptr<PageTable> GetCurrentPageTable() const;
319 
320     u8 Read8(VAddr addr);
321     u16 Read16(VAddr addr);
322     u32 Read32(VAddr addr);
323     u64 Read64(VAddr addr);
324 
325     void Write8(VAddr addr, u8 data);
326     void Write16(VAddr addr, u16 data);
327     void Write32(VAddr addr, u32 data);
328     void Write64(VAddr addr, u64 data);
329 
330     void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
331                    std::size_t size);
332     void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
333                     std::size_t size);
334     void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size);
335     void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
336                    std::size_t size);
337     void CopyBlock(const Kernel::Process& dest_process, const Kernel::Process& src_process,
338                    VAddr dest_addr, VAddr src_addr, std::size_t size);
339 
340     std::string ReadCString(VAddr vaddr, std::size_t max_length);
341 
342     /// Gets a pointer to the memory region beginning at the specified physical address.
343     u8* GetPhysicalPointer(PAddr address);
344 
345     /// Gets a pointer to the memory region beginning at the specified physical address.
346     const u8* GetPhysicalPointer(PAddr address) const;
347 
348     MemoryRef GetPhysicalRef(PAddr address) const;
349 
350     u8* GetPointer(VAddr vaddr);
351     const u8* GetPointer(VAddr vaddr) const;
352 
353     bool IsValidPhysicalAddress(PAddr paddr) const;
354 
355     /// Gets offset in FCRAM from a pointer inside FCRAM range
356     u32 GetFCRAMOffset(const u8* pointer) const;
357 
358     /// Gets pointer in FCRAM with given offset
359     u8* GetFCRAMPointer(std::size_t offset);
360 
361     /// Gets pointer in FCRAM with given offset
362     const u8* GetFCRAMPointer(std::size_t offset) const;
363 
364     /// Gets a serializable ref to FCRAM with the given offset
365     MemoryRef GetFCRAMRef(std::size_t offset) const;
366 
367     /**
368      * Mark each page touching the region as cached.
369      */
370     void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached);
371 
372     /// Registers page table for rasterizer cache marking
373     void RegisterPageTable(std::shared_ptr<PageTable> page_table);
374 
375     /// Unregisters page table for rasterizer cache marking
376     void UnregisterPageTable(std::shared_ptr<PageTable> page_table);
377 
378     void SetDSP(AudioCore::DspInterface& dsp);
379 
380 private:
381     template <typename T>
382     T Read(const VAddr vaddr);
383 
384     template <typename T>
385     void Write(const VAddr vaddr, const T data);
386 
387     /**
388      * Gets the pointer for virtual memory where the page is marked as RasterizerCachedMemory.
389      * This is used to access the memory where the page pointer is nullptr due to rasterizer cache.
390      * Since the cache only happens on linear heap or VRAM, we know the exact physical address and
391      * pointer of such virtual address
392      */
393     MemoryRef GetPointerForRasterizerCache(VAddr addr) const;
394 
395     void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type);
396 
397     class Impl;
398 
399     std::unique_ptr<Impl> impl;
400 
401     friend class boost::serialization::access;
402     template <class Archive>
403     void serialize(Archive& ar, const unsigned int file_version);
404 
405 public:
406     template <Region R>
407     class BackingMemImpl;
408 };
409 
410 /// Determines if the given VAddr is valid for the specified process.
411 bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
412 
413 } // namespace Memory
414 
415 BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>)
416 BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::VRAM>)
417 BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::DSP>)
418 BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::N3DS>)
419