diff options
| author | 2019-11-28 11:43:17 -0500 | |
|---|---|---|
| committer | 2019-11-28 11:43:17 -0500 | |
| commit | e3ee017e91ef4d713f1af8cb60c5157e40d43f18 (patch) | |
| tree | e0a5b47cac1d548599b8ceba7f71b40746fe6b48 /src/core/memory.h | |
| parent | Merge pull request #3171 from lioncash/internal-link (diff) | |
| parent | core/memory; Migrate over SetCurrentPageTable() to the Memory class (diff) | |
| download | yuzu-e3ee017e91ef4d713f1af8cb60c5157e40d43f18.tar.gz yuzu-e3ee017e91ef4d713f1af8cb60c5157e40d43f18.tar.xz yuzu-e3ee017e91ef4d713f1af8cb60c5157e40d43f18.zip | |
Merge pull request #3169 from lioncash/memory
core/memory: Deglobalize memory management code
Diffstat (limited to 'src/core/memory.h')
| -rw-r--r-- | src/core/memory.h | 396 |
1 files changed, 367 insertions, 29 deletions
diff --git a/src/core/memory.h b/src/core/memory.h index 09008e1dd..1428a6d60 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -5,8 +5,18 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <memory> | ||
| 8 | #include <string> | 9 | #include <string> |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/memory_hook.h" | ||
| 12 | |||
| 13 | namespace Common { | ||
| 14 | struct PageTable; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 10 | 20 | ||
| 11 | namespace Kernel { | 21 | namespace Kernel { |
| 12 | class Process; | 22 | class Process; |
| @@ -36,41 +46,369 @@ enum : VAddr { | |||
| 36 | KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, | 46 | KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, |
| 37 | }; | 47 | }; |
| 38 | 48 | ||
| 39 | /// Changes the currently active page table to that of | 49 | /// Central class that handles all memory operations and state. |
| 40 | /// the given process instance. | 50 | class Memory { |
| 41 | void SetCurrentPageTable(Kernel::Process& process); | 51 | public: |
| 52 | explicit Memory(Core::System& system); | ||
| 53 | ~Memory(); | ||
| 42 | 54 | ||
| 43 | /// Determines if the given VAddr is valid for the specified process. | 55 | Memory(const Memory&) = delete; |
| 44 | bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); | 56 | Memory& operator=(const Memory&) = delete; |
| 45 | bool IsValidVirtualAddress(VAddr vaddr); | ||
| 46 | /// Determines if the given VAddr is a kernel address | ||
| 47 | bool IsKernelVirtualAddress(VAddr vaddr); | ||
| 48 | 57 | ||
| 49 | u8 Read8(VAddr addr); | 58 | Memory(Memory&&) = default; |
| 50 | u16 Read16(VAddr addr); | 59 | Memory& operator=(Memory&&) = default; |
| 51 | u32 Read32(VAddr addr); | ||
| 52 | u64 Read64(VAddr addr); | ||
| 53 | 60 | ||
| 54 | void Write8(VAddr addr, u8 data); | 61 | /** |
| 55 | void Write16(VAddr addr, u16 data); | 62 | * Changes the currently active page table to that of the given process instance. |
| 56 | void Write32(VAddr addr, u32 data); | 63 | * |
| 57 | void Write64(VAddr addr, u64 data); | 64 | * @param process The process to use the page table of. |
| 65 | */ | ||
| 66 | void SetCurrentPageTable(Kernel::Process& process); | ||
| 58 | 67 | ||
| 59 | void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size); | 68 | /** |
| 60 | void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); | 69 | * Maps an allocated buffer onto a region of the emulated process address space. |
| 61 | void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, | 70 | * |
| 62 | std::size_t size); | 71 | * @param page_table The page table of the emulated process. |
| 63 | void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); | 72 | * @param base The address to start mapping at. Must be page-aligned. |
| 64 | void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); | 73 | * @param size The amount of bytes to map. Must be page-aligned. |
| 65 | void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size); | 74 | * @param target Buffer with the memory backing the mapping. Must be of length at least |
| 75 | * `size`. | ||
| 76 | */ | ||
| 77 | void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target); | ||
| 66 | 78 | ||
| 67 | u8* GetPointer(VAddr vaddr); | 79 | /** |
| 80 | * Maps a region of the emulated process address space as a IO region. | ||
| 81 | * | ||
| 82 | * @param page_table The page table of the emulated process. | ||
| 83 | * @param base The address to start mapping at. Must be page-aligned. | ||
| 84 | * @param size The amount of bytes to map. Must be page-aligned. | ||
| 85 | * @param mmio_handler The handler that backs the mapping. | ||
| 86 | */ | ||
| 87 | void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 88 | Common::MemoryHookPointer mmio_handler); | ||
| 68 | 89 | ||
| 69 | std::string ReadCString(VAddr vaddr, std::size_t max_length); | 90 | /** |
| 91 | * Unmaps a region of the emulated process address space. | ||
| 92 | * | ||
| 93 | * @param page_table The page table of the emulated process. | ||
| 94 | * @param base The address to begin unmapping at. | ||
| 95 | * @param size The amount of bytes to unmap. | ||
| 96 | */ | ||
| 97 | void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size); | ||
| 70 | 98 | ||
| 71 | /** | 99 | /** |
| 72 | * Mark each page touching the region as cached. | 100 | * Adds a memory hook to intercept reads and writes to given region of memory. |
| 73 | */ | 101 | * |
| 74 | void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached); | 102 | * @param page_table The page table of the emulated process |
| 103 | * @param base The starting address to apply the hook to. | ||
| 104 | * @param size The size of the memory region to apply the hook to, in bytes. | ||
| 105 | * @param hook The hook to apply to the region of memory. | ||
| 106 | */ | ||
| 107 | void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 108 | Common::MemoryHookPointer hook); | ||
| 109 | |||
| 110 | /** | ||
| 111 | * Removes a memory hook from a given range of memory. | ||
| 112 | * | ||
| 113 | * @param page_table The page table of the emulated process. | ||
| 114 | * @param base The starting address to remove the hook from. | ||
| 115 | * @param size The size of the memory region to remove the hook from, in bytes. | ||
| 116 | * @param hook The hook to remove from the specified region of memory. | ||
| 117 | */ | ||
| 118 | void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 119 | Common::MemoryHookPointer hook); | ||
| 120 | |||
| 121 | /** | ||
| 122 | * Checks whether or not the supplied address is a valid virtual | ||
| 123 | * address for the given process. | ||
| 124 | * | ||
| 125 | * @param process The emulated process to check the address against. | ||
| 126 | * @param vaddr The virtual address to check the validity of. | ||
| 127 | * | ||
| 128 | * @returns True if the given virtual address is valid, false otherwise. | ||
| 129 | */ | ||
| 130 | bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr) const; | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Checks whether or not the supplied address is a valid virtual | ||
| 134 | * address for the current process. | ||
| 135 | * | ||
| 136 | * @param vaddr The virtual address to check the validity of. | ||
| 137 | * | ||
| 138 | * @returns True if the given virtual address is valid, false otherwise. | ||
| 139 | */ | ||
| 140 | bool IsValidVirtualAddress(VAddr vaddr) const; | ||
| 141 | |||
| 142 | /** | ||
| 143 | * Gets a pointer to the given address. | ||
| 144 | * | ||
| 145 | * @param vaddr Virtual address to retrieve a pointer to. | ||
| 146 | * | ||
| 147 | * @returns The pointer to the given address, if the address is valid. | ||
| 148 | * If the address is not valid, nullptr will be returned. | ||
| 149 | */ | ||
| 150 | u8* GetPointer(VAddr vaddr); | ||
| 151 | |||
| 152 | /** | ||
| 153 | * Gets a pointer to the given address. | ||
| 154 | * | ||
| 155 | * @param vaddr Virtual address to retrieve a pointer to. | ||
| 156 | * | ||
| 157 | * @returns The pointer to the given address, if the address is valid. | ||
| 158 | * If the address is not valid, nullptr will be returned. | ||
| 159 | */ | ||
| 160 | const u8* GetPointer(VAddr vaddr) const; | ||
| 161 | |||
| 162 | /** | ||
| 163 | * Reads an 8-bit unsigned value from the current process' address space | ||
| 164 | * at the given virtual address. | ||
| 165 | * | ||
| 166 | * @param addr The virtual address to read the 8-bit value from. | ||
| 167 | * | ||
| 168 | * @returns the read 8-bit unsigned value. | ||
| 169 | */ | ||
| 170 | u8 Read8(VAddr addr); | ||
| 171 | |||
| 172 | /** | ||
| 173 | * Reads a 16-bit unsigned value from the current process' address space | ||
| 174 | * at the given virtual address. | ||
| 175 | * | ||
| 176 | * @param addr The virtual address to read the 16-bit value from. | ||
| 177 | * | ||
| 178 | * @returns the read 16-bit unsigned value. | ||
| 179 | */ | ||
| 180 | u16 Read16(VAddr addr); | ||
| 181 | |||
| 182 | /** | ||
| 183 | * Reads a 32-bit unsigned value from the current process' address space | ||
| 184 | * at the given virtual address. | ||
| 185 | * | ||
| 186 | * @param addr The virtual address to read the 32-bit value from. | ||
| 187 | * | ||
| 188 | * @returns the read 32-bit unsigned value. | ||
| 189 | */ | ||
| 190 | u32 Read32(VAddr addr); | ||
| 191 | |||
| 192 | /** | ||
| 193 | * Reads a 64-bit unsigned value from the current process' address space | ||
| 194 | * at the given virtual address. | ||
| 195 | * | ||
| 196 | * @param addr The virtual address to read the 64-bit value from. | ||
| 197 | * | ||
| 198 | * @returns the read 64-bit value. | ||
| 199 | */ | ||
| 200 | u64 Read64(VAddr addr); | ||
| 201 | |||
| 202 | /** | ||
| 203 | * Writes an 8-bit unsigned integer to the given virtual address in | ||
| 204 | * the current process' address space. | ||
| 205 | * | ||
| 206 | * @param addr The virtual address to write the 8-bit unsigned integer to. | ||
| 207 | * @param data The 8-bit unsigned integer to write to the given virtual address. | ||
| 208 | * | ||
| 209 | * @post The memory at the given virtual address contains the specified data value. | ||
| 210 | */ | ||
| 211 | void Write8(VAddr addr, u8 data); | ||
| 212 | |||
| 213 | /** | ||
| 214 | * Writes a 16-bit unsigned integer to the given virtual address in | ||
| 215 | * the current process' address space. | ||
| 216 | * | ||
| 217 | * @param addr The virtual address to write the 16-bit unsigned integer to. | ||
| 218 | * @param data The 16-bit unsigned integer to write to the given virtual address. | ||
| 219 | * | ||
| 220 | * @post The memory range [addr, sizeof(data)) contains the given data value. | ||
| 221 | */ | ||
| 222 | void Write16(VAddr addr, u16 data); | ||
| 223 | |||
| 224 | /** | ||
| 225 | * Writes a 32-bit unsigned integer to the given virtual address in | ||
| 226 | * the current process' address space. | ||
| 227 | * | ||
| 228 | * @param addr The virtual address to write the 32-bit unsigned integer to. | ||
| 229 | * @param data The 32-bit unsigned integer to write to the given virtual address. | ||
| 230 | * | ||
| 231 | * @post The memory range [addr, sizeof(data)) contains the given data value. | ||
| 232 | */ | ||
| 233 | void Write32(VAddr addr, u32 data); | ||
| 234 | |||
| 235 | /** | ||
| 236 | * Writes a 64-bit unsigned integer to the given virtual address in | ||
| 237 | * the current process' address space. | ||
| 238 | * | ||
| 239 | * @param addr The virtual address to write the 64-bit unsigned integer to. | ||
| 240 | * @param data The 64-bit unsigned integer to write to the given virtual address. | ||
| 241 | * | ||
| 242 | * @post The memory range [addr, sizeof(data)) contains the given data value. | ||
| 243 | */ | ||
| 244 | void Write64(VAddr addr, u64 data); | ||
| 245 | |||
| 246 | /** | ||
| 247 | * Reads a null-terminated string from the given virtual address. | ||
| 248 | * This function will continually read characters until either: | ||
| 249 | * | ||
| 250 | * - A null character ('\0') is reached. | ||
| 251 | * - max_length characters have been read. | ||
| 252 | * | ||
| 253 | * @note The final null-terminating character (if found) is not included | ||
| 254 | * in the returned string. | ||
| 255 | * | ||
| 256 | * @param vaddr The address to begin reading the string from. | ||
| 257 | * @param max_length The maximum length of the string to read in characters. | ||
| 258 | * | ||
| 259 | * @returns The read string. | ||
| 260 | */ | ||
| 261 | std::string ReadCString(VAddr vaddr, std::size_t max_length); | ||
| 262 | |||
| 263 | /** | ||
| 264 | * Reads a contiguous block of bytes from a specified process' address space. | ||
| 265 | * | ||
| 266 | * @param process The process to read the data from. | ||
| 267 | * @param src_addr The virtual address to begin reading from. | ||
| 268 | * @param dest_buffer The buffer to place the read bytes into. | ||
| 269 | * @param size The amount of data to read, in bytes. | ||
| 270 | * | ||
| 271 | * @note If a size of 0 is specified, then this function reads nothing and | ||
| 272 | * no attempts to access memory are made at all. | ||
| 273 | * | ||
| 274 | * @pre dest_buffer must be at least size bytes in length, otherwise a | ||
| 275 | * buffer overrun will occur. | ||
| 276 | * | ||
| 277 | * @post The range [dest_buffer, size) contains the read bytes from the | ||
| 278 | * process' address space. | ||
| 279 | */ | ||
| 280 | void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, | ||
| 281 | std::size_t size); | ||
| 282 | |||
| 283 | /** | ||
| 284 | * Reads a contiguous block of bytes from the current process' address space. | ||
| 285 | * | ||
| 286 | * @param src_addr The virtual address to begin reading from. | ||
| 287 | * @param dest_buffer The buffer to place the read bytes into. | ||
| 288 | * @param size The amount of data to read, in bytes. | ||
| 289 | * | ||
| 290 | * @note If a size of 0 is specified, then this function reads nothing and | ||
| 291 | * no attempts to access memory are made at all. | ||
| 292 | * | ||
| 293 | * @pre dest_buffer must be at least size bytes in length, otherwise a | ||
| 294 | * buffer overrun will occur. | ||
| 295 | * | ||
| 296 | * @post The range [dest_buffer, size) contains the read bytes from the | ||
| 297 | * current process' address space. | ||
| 298 | */ | ||
| 299 | void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); | ||
| 300 | |||
| 301 | /** | ||
| 302 | * Writes a range of bytes into a given process' address space at the specified | ||
| 303 | * virtual address. | ||
| 304 | * | ||
| 305 | * @param process The process to write data into the address space of. | ||
| 306 | * @param dest_addr The destination virtual address to begin writing the data at. | ||
| 307 | * @param src_buffer The data to write into the process' address space. | ||
| 308 | * @param size The size of the data to write, in bytes. | ||
| 309 | * | ||
| 310 | * @post The address range [dest_addr, size) in the process' address space | ||
| 311 | * contains the data that was within src_buffer. | ||
| 312 | * | ||
| 313 | * @post If an attempt is made to write into an unmapped region of memory, the writes | ||
| 314 | * will be ignored and an error will be logged. | ||
| 315 | * | ||
| 316 | * @post If a write is performed into a region of memory that is considered cached | ||
| 317 | * rasterizer memory, will cause the currently active rasterizer to be notified | ||
| 318 | * and will mark that region as invalidated to caches that the active | ||
| 319 | * graphics backend may be maintaining over the course of execution. | ||
| 320 | */ | ||
| 321 | void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, | ||
| 322 | std::size_t size); | ||
| 323 | |||
| 324 | /** | ||
| 325 | * Writes a range of bytes into the current process' address space at the specified | ||
| 326 | * virtual address. | ||
| 327 | * | ||
| 328 | * @param dest_addr The destination virtual address to begin writing the data at. | ||
| 329 | * @param src_buffer The data to write into the current process' address space. | ||
| 330 | * @param size The size of the data to write, in bytes. | ||
| 331 | * | ||
| 332 | * @post The address range [dest_addr, size) in the current process' address space | ||
| 333 | * contains the data that was within src_buffer. | ||
| 334 | * | ||
| 335 | * @post If an attempt is made to write into an unmapped region of memory, the writes | ||
| 336 | * will be ignored and an error will be logged. | ||
| 337 | * | ||
| 338 | * @post If a write is performed into a region of memory that is considered cached | ||
| 339 | * rasterizer memory, will cause the currently active rasterizer to be notified | ||
| 340 | * and will mark that region as invalidated to caches that the active | ||
| 341 | * graphics backend may be maintaining over the course of execution. | ||
| 342 | */ | ||
| 343 | void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); | ||
| 344 | |||
| 345 | /** | ||
| 346 | * Fills the specified address range within a process' address space with zeroes. | ||
| 347 | * | ||
| 348 | * @param process The process that will have a portion of its memory zeroed out. | ||
| 349 | * @param dest_addr The starting virtual address of the range to zero out. | ||
| 350 | * @param size The size of the address range to zero out, in bytes. | ||
| 351 | * | ||
| 352 | * @post The range [dest_addr, size) within the process' address space is | ||
| 353 | * filled with zeroes. | ||
| 354 | */ | ||
| 355 | void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); | ||
| 356 | |||
| 357 | /** | ||
| 358 | * Fills the specified address range within the current process' address space with zeroes. | ||
| 359 | * | ||
| 360 | * @param dest_addr The starting virtual address of the range to zero out. | ||
| 361 | * @param size The size of the address range to zero out, in bytes. | ||
| 362 | * | ||
| 363 | * @post The range [dest_addr, size) within the current process' address space is | ||
| 364 | * filled with zeroes. | ||
| 365 | */ | ||
| 366 | void ZeroBlock(VAddr dest_addr, std::size_t size); | ||
| 367 | |||
| 368 | /** | ||
| 369 | * Copies data within a process' address space to another location within the | ||
| 370 | * same address space. | ||
| 371 | * | ||
| 372 | * @param process The process that will have data copied within its address space. | ||
| 373 | * @param dest_addr The destination virtual address to begin copying the data into. | ||
| 374 | * @param src_addr The source virtual address to begin copying the data from. | ||
| 375 | * @param size The size of the data to copy, in bytes. | ||
| 376 | * | ||
| 377 | * @post The range [dest_addr, size) within the process' address space contains the | ||
| 378 | * same data within the range [src_addr, size). | ||
| 379 | */ | ||
| 380 | void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | ||
| 381 | std::size_t size); | ||
| 382 | |||
| 383 | /** | ||
| 384 | * Copies data within the current process' address space to another location within the | ||
| 385 | * same address space. | ||
| 386 | * | ||
| 387 | * @param dest_addr The destination virtual address to begin copying the data into. | ||
| 388 | * @param src_addr The source virtual address to begin copying the data from. | ||
| 389 | * @param size The size of the data to copy, in bytes. | ||
| 390 | * | ||
| 391 | * @post The range [dest_addr, size) within the current process' address space | ||
| 392 | * contains the same data within the range [src_addr, size). | ||
| 393 | */ | ||
| 394 | void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size); | ||
| 395 | |||
| 396 | /** | ||
| 397 | * Marks each page within the specified address range as cached or uncached. | ||
| 398 | * | ||
| 399 | * @param vaddr The virtual address indicating the start of the address range. | ||
| 400 | * @param size The size of the address range in bytes. | ||
| 401 | * @param cached Whether or not any pages within the address range should be | ||
| 402 | * marked as cached or uncached. | ||
| 403 | */ | ||
| 404 | void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached); | ||
| 405 | |||
| 406 | private: | ||
| 407 | struct Impl; | ||
| 408 | std::unique_ptr<Impl> impl; | ||
| 409 | }; | ||
| 410 | |||
| 411 | /// Determines if the given VAddr is a kernel address | ||
| 412 | bool IsKernelVirtualAddress(VAddr vaddr); | ||
| 75 | 413 | ||
| 76 | } // namespace Memory | 414 | } // namespace Memory |