memory.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. // SPDX-FileCopyrightText: 2014 Citra Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <cstddef>
  5. #include <memory>
  6. #include <optional>
  7. #include <span>
  8. #include <string>
  9. #include <vector>
  10. #include "common/scratch_buffer.h"
  11. #include "common/typed_address.h"
  12. #include "core/hle/result.h"
  13. namespace Common {
  14. enum class MemoryPermission : u32;
  15. struct PageTable;
  16. } // namespace Common
  17. namespace Core {
  18. class System;
  19. class GPUDirtyMemoryManager;
  20. } // namespace Core
  21. namespace Kernel {
  22. class KProcess;
  23. } // namespace Kernel
  24. namespace Tegra {
  25. class MemoryManager;
  26. }
  27. namespace Core::Memory {
  28. /**
  29. * Page size used by the ARM architecture. This is the smallest granularity with which memory can
  30. * be mapped.
  31. */
  32. constexpr std::size_t YUZU_PAGEBITS = 12;
  33. constexpr u64 YUZU_PAGESIZE = 1ULL << YUZU_PAGEBITS;
  34. constexpr u64 YUZU_PAGEMASK = YUZU_PAGESIZE - 1;
  35. /// Virtual user-space memory regions
  36. enum : u64 {
  37. /// TLS (Thread-Local Storage) related.
  38. TLS_ENTRY_SIZE = 0x200,
  39. /// Application stack
  40. DEFAULT_STACK_SIZE = 0x100000,
  41. };
  42. /// Central class that handles all memory operations and state.
  43. class Memory {
  44. public:
  45. explicit Memory(Core::System& system);
  46. ~Memory();
  47. Memory(const Memory&) = delete;
  48. Memory& operator=(const Memory&) = delete;
  49. Memory(Memory&&) = default;
  50. Memory& operator=(Memory&&) = delete;
  51. /**
  52. * Resets the state of the Memory system.
  53. */
  54. void Reset();
  55. /**
  56. * Changes the currently active page table to that of the given process instance.
  57. *
  58. * @param process The process to use the page table of.
  59. */
  60. void SetCurrentPageTable(Kernel::KProcess& process);
  61. /**
  62. * Maps an allocated buffer onto a region of the emulated process address space.
  63. *
  64. * @param page_table The page table of the emulated process.
  65. * @param base The address to start mapping at. Must be page-aligned.
  66. * @param size The amount of bytes to map. Must be page-aligned.
  67. * @param target Buffer with the memory backing the mapping. Must be of length at least
  68. * `size`.
  69. * @param perms The permissions to map the memory with.
  70. */
  71. void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
  72. Common::PhysicalAddress target, Common::MemoryPermission perms);
  73. /**
  74. * Unmaps a region of the emulated process address space.
  75. *
  76. * @param page_table The page table of the emulated process.
  77. * @param base The address to begin unmapping at.
  78. * @param size The amount of bytes to unmap.
  79. */
  80. void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size);
  81. /**
  82. * Protects a region of the emulated process address space with the new permissions.
  83. *
  84. * @param page_table The page table of the emulated process.
  85. * @param base The start address to re-protect. Must be page-aligned.
  86. * @param size The amount of bytes to protect. Must be page-aligned.
  87. * @param perms The permissions the address range is mapped.
  88. */
  89. void ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
  90. Common::MemoryPermission perms);
  91. /**
  92. * Checks whether or not the supplied address is a valid virtual
  93. * address for the current process.
  94. *
  95. * @param vaddr The virtual address to check the validity of.
  96. *
  97. * @returns True if the given virtual address is valid, false otherwise.
  98. */
  99. [[nodiscard]] bool IsValidVirtualAddress(Common::ProcessAddress vaddr) const;
  100. /**
  101. * Checks whether or not the supplied range of addresses are all valid
  102. * virtual addresses for the current process.
  103. *
  104. * @param base The address to begin checking.
  105. * @param size The amount of bytes to check.
  106. *
  107. * @returns True if all bytes in the given range are valid, false otherwise.
  108. */
  109. [[nodiscard]] bool IsValidVirtualAddressRange(Common::ProcessAddress base, u64 size) const;
  110. /**
  111. * Gets a pointer to the given address.
  112. *
  113. * @param vaddr Virtual address to retrieve a pointer to.
  114. *
  115. * @returns The pointer to the given address, if the address is valid.
  116. * If the address is not valid, nullptr will be returned.
  117. */
  118. u8* GetPointer(Common::ProcessAddress vaddr);
  119. u8* GetPointerSilent(Common::ProcessAddress vaddr);
  120. template <typename T>
  121. T* GetPointer(Common::ProcessAddress vaddr) {
  122. return reinterpret_cast<T*>(GetPointer(vaddr));
  123. }
  124. /**
  125. * Gets a pointer to the given address.
  126. *
  127. * @param vaddr Virtual address to retrieve a pointer to.
  128. *
  129. * @returns The pointer to the given address, if the address is valid.
  130. * If the address is not valid, nullptr will be returned.
  131. */
  132. [[nodiscard]] const u8* GetPointer(Common::ProcessAddress vaddr) const;
  133. template <typename T>
  134. const T* GetPointer(Common::ProcessAddress vaddr) const {
  135. return reinterpret_cast<T*>(GetPointer(vaddr));
  136. }
  137. /**
  138. * Reads an 8-bit unsigned value from the current process' address space
  139. * at the given virtual address.
  140. *
  141. * @param addr The virtual address to read the 8-bit value from.
  142. *
  143. * @returns the read 8-bit unsigned value.
  144. */
  145. u8 Read8(Common::ProcessAddress addr);
  146. /**
  147. * Reads a 16-bit unsigned value from the current process' address space
  148. * at the given virtual address.
  149. *
  150. * @param addr The virtual address to read the 16-bit value from.
  151. *
  152. * @returns the read 16-bit unsigned value.
  153. */
  154. u16 Read16(Common::ProcessAddress addr);
  155. /**
  156. * Reads a 32-bit unsigned value from the current process' address space
  157. * at the given virtual address.
  158. *
  159. * @param addr The virtual address to read the 32-bit value from.
  160. *
  161. * @returns the read 32-bit unsigned value.
  162. */
  163. u32 Read32(Common::ProcessAddress addr);
  164. /**
  165. * Reads a 64-bit unsigned value from the current process' address space
  166. * at the given virtual address.
  167. *
  168. * @param addr The virtual address to read the 64-bit value from.
  169. *
  170. * @returns the read 64-bit value.
  171. */
  172. u64 Read64(Common::ProcessAddress addr);
  173. /**
  174. * Writes an 8-bit unsigned integer to the given virtual address in
  175. * the current process' address space.
  176. *
  177. * @param addr The virtual address to write the 8-bit unsigned integer to.
  178. * @param data The 8-bit unsigned integer to write to the given virtual address.
  179. *
  180. * @post The memory at the given virtual address contains the specified data value.
  181. */
  182. void Write8(Common::ProcessAddress addr, u8 data);
  183. /**
  184. * Writes a 16-bit unsigned integer to the given virtual address in
  185. * the current process' address space.
  186. *
  187. * @param addr The virtual address to write the 16-bit unsigned integer to.
  188. * @param data The 16-bit unsigned integer to write to the given virtual address.
  189. *
  190. * @post The memory range [addr, sizeof(data)) contains the given data value.
  191. */
  192. void Write16(Common::ProcessAddress addr, u16 data);
  193. /**
  194. * Writes a 32-bit unsigned integer to the given virtual address in
  195. * the current process' address space.
  196. *
  197. * @param addr The virtual address to write the 32-bit unsigned integer to.
  198. * @param data The 32-bit unsigned integer to write to the given virtual address.
  199. *
  200. * @post The memory range [addr, sizeof(data)) contains the given data value.
  201. */
  202. void Write32(Common::ProcessAddress addr, u32 data);
  203. /**
  204. * Writes a 64-bit unsigned integer to the given virtual address in
  205. * the current process' address space.
  206. *
  207. * @param addr The virtual address to write the 64-bit unsigned integer to.
  208. * @param data The 64-bit unsigned integer to write to the given virtual address.
  209. *
  210. * @post The memory range [addr, sizeof(data)) contains the given data value.
  211. */
  212. void Write64(Common::ProcessAddress addr, u64 data);
  213. /**
  214. * Writes a 8-bit unsigned integer to the given virtual address in
  215. * the current process' address space if and only if the address contains
  216. * the expected value. This operation is atomic.
  217. *
  218. * @param addr The virtual address to write the 8-bit unsigned integer to.
  219. * @param data The 8-bit unsigned integer to write to the given virtual address.
  220. * @param expected The 8-bit unsigned integer to check against the given virtual address.
  221. *
  222. * @post The memory range [addr, sizeof(data)) contains the given data value.
  223. */
  224. bool WriteExclusive8(Common::ProcessAddress addr, u8 data, u8 expected);
  225. /**
  226. * Writes a 16-bit unsigned integer to the given virtual address in
  227. * the current process' address space if and only if the address contains
  228. * the expected value. This operation is atomic.
  229. *
  230. * @param addr The virtual address to write the 16-bit unsigned integer to.
  231. * @param data The 16-bit unsigned integer to write to the given virtual address.
  232. * @param expected The 16-bit unsigned integer to check against the given virtual address.
  233. *
  234. * @post The memory range [addr, sizeof(data)) contains the given data value.
  235. */
  236. bool WriteExclusive16(Common::ProcessAddress addr, u16 data, u16 expected);
  237. /**
  238. * Writes a 32-bit unsigned integer to the given virtual address in
  239. * the current process' address space if and only if the address contains
  240. * the expected value. This operation is atomic.
  241. *
  242. * @param addr The virtual address to write the 32-bit unsigned integer to.
  243. * @param data The 32-bit unsigned integer to write to the given virtual address.
  244. * @param expected The 32-bit unsigned integer to check against the given virtual address.
  245. *
  246. * @post The memory range [addr, sizeof(data)) contains the given data value.
  247. */
  248. bool WriteExclusive32(Common::ProcessAddress addr, u32 data, u32 expected);
  249. /**
  250. * Writes a 64-bit unsigned integer to the given virtual address in
  251. * the current process' address space if and only if the address contains
  252. * the expected value. This operation is atomic.
  253. *
  254. * @param addr The virtual address to write the 64-bit unsigned integer to.
  255. * @param data The 64-bit unsigned integer to write to the given virtual address.
  256. * @param expected The 64-bit unsigned integer to check against the given virtual address.
  257. *
  258. * @post The memory range [addr, sizeof(data)) contains the given data value.
  259. */
  260. bool WriteExclusive64(Common::ProcessAddress addr, u64 data, u64 expected);
  261. /**
  262. * Writes a 128-bit unsigned integer to the given virtual address in
  263. * the current process' address space if and only if the address contains
  264. * the expected value. This operation is atomic.
  265. *
  266. * @param addr The virtual address to write the 128-bit unsigned integer to.
  267. * @param data The 128-bit unsigned integer to write to the given virtual address.
  268. * @param expected The 128-bit unsigned integer to check against the given virtual address.
  269. *
  270. * @post The memory range [addr, sizeof(data)) contains the given data value.
  271. */
  272. bool WriteExclusive128(Common::ProcessAddress addr, u128 data, u128 expected);
  273. /**
  274. * Reads a null-terminated string from the given virtual address.
  275. * This function will continually read characters until either:
  276. *
  277. * - A null character ('\0') is reached.
  278. * - max_length characters have been read.
  279. *
  280. * @note The final null-terminating character (if found) is not included
  281. * in the returned string.
  282. *
  283. * @param vaddr The address to begin reading the string from.
  284. * @param max_length The maximum length of the string to read in characters.
  285. *
  286. * @returns The read string.
  287. */
  288. std::string ReadCString(Common::ProcessAddress vaddr, std::size_t max_length);
  289. /**
  290. * Reads a contiguous block of bytes from the current process' address space.
  291. *
  292. * @param src_addr The virtual address to begin reading from.
  293. * @param dest_buffer The buffer to place the read bytes into.
  294. * @param size The amount of data to read, in bytes.
  295. *
  296. * @note If a size of 0 is specified, then this function reads nothing and
  297. * no attempts to access memory are made at all.
  298. *
  299. * @pre dest_buffer must be at least size bytes in length, otherwise a
  300. * buffer overrun will occur.
  301. *
  302. * @post The range [dest_buffer, size) contains the read bytes from the
  303. * current process' address space.
  304. */
  305. bool ReadBlock(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size);
  306. /**
  307. * Reads a contiguous block of bytes from the current process' address space.
  308. * This unsafe version does not trigger GPU flushing.
  309. *
  310. * @param src_addr The virtual address to begin reading from.
  311. * @param dest_buffer The buffer to place the read bytes into.
  312. * @param size The amount of data to read, in bytes.
  313. *
  314. * @note If a size of 0 is specified, then this function reads nothing and
  315. * no attempts to access memory are made at all.
  316. *
  317. * @pre dest_buffer must be at least size bytes in length, otherwise a
  318. * buffer overrun will occur.
  319. *
  320. * @post The range [dest_buffer, size) contains the read bytes from the
  321. * current process' address space.
  322. */
  323. bool ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size);
  324. const u8* GetSpan(const VAddr src_addr, const std::size_t size) const;
  325. u8* GetSpan(const VAddr src_addr, const std::size_t size);
  326. /**
  327. * Writes a range of bytes into the current process' address space at the specified
  328. * virtual address.
  329. *
  330. * @param dest_addr The destination virtual address to begin writing the data at.
  331. * @param src_buffer The data to write into the current process' address space.
  332. * @param size The size of the data to write, in bytes.
  333. *
  334. * @post The address range [dest_addr, size) in the current process' address space
  335. * contains the data that was within src_buffer.
  336. *
  337. * @post If an attempt is made to write into an unmapped region of memory, the writes
  338. * will be ignored and an error will be logged.
  339. *
  340. * @post If a write is performed into a region of memory that is considered cached
  341. * rasterizer memory, will cause the currently active rasterizer to be notified
  342. * and will mark that region as invalidated to caches that the active
  343. * graphics backend may be maintaining over the course of execution.
  344. */
  345. bool WriteBlock(Common::ProcessAddress dest_addr, const void* src_buffer, std::size_t size);
  346. /**
  347. * Writes a range of bytes into the current process' address space at the specified
  348. * virtual address.
  349. * This unsafe version does not invalidate GPU Memory.
  350. *
  351. * @param dest_addr The destination virtual address to begin writing the data at.
  352. * @param src_buffer The data to write into the current process' address space.
  353. * @param size The size of the data to write, in bytes.
  354. *
  355. * @post The address range [dest_addr, size) in the current process' address space
  356. * contains the data that was within src_buffer.
  357. *
  358. * @post If an attempt is made to write into an unmapped region of memory, the writes
  359. * will be ignored and an error will be logged.
  360. *
  361. */
  362. bool WriteBlockUnsafe(Common::ProcessAddress dest_addr, const void* src_buffer,
  363. std::size_t size);
  364. /**
  365. * Copies data within a process' address space to another location within the
  366. * same address space.
  367. *
  368. * @param dest_addr The destination virtual address to begin copying the data into.
  369. * @param src_addr The source virtual address to begin copying the data from.
  370. * @param size The size of the data to copy, in bytes.
  371. *
  372. * @post The range [dest_addr, size) within the process' address space contains the
  373. * same data within the range [src_addr, size).
  374. */
  375. bool CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr,
  376. std::size_t size);
  377. /**
  378. * Zeros a range of bytes within the current process' address space at the specified
  379. * virtual address.
  380. *
  381. * @param dest_addr The destination virtual address to zero the data from.
  382. * @param size The size of the range to zero out, in bytes.
  383. *
  384. * @post The range [dest_addr, size) within the process' address space contains the
  385. * value 0.
  386. */
  387. bool ZeroBlock(Common::ProcessAddress dest_addr, std::size_t size);
  388. /**
  389. * Invalidates a range of bytes within the current process' address space at the specified
  390. * virtual address.
  391. *
  392. * @param dest_addr The destination virtual address to invalidate the data from.
  393. * @param size The size of the range to invalidate, in bytes.
  394. *
  395. */
  396. Result InvalidateDataCache(Common::ProcessAddress dest_addr, std::size_t size);
  397. /**
  398. * Stores a range of bytes within the current process' address space at the specified
  399. * virtual address.
  400. *
  401. * @param dest_addr The destination virtual address to store the data from.
  402. * @param size The size of the range to store, in bytes.
  403. *
  404. */
  405. Result StoreDataCache(Common::ProcessAddress dest_addr, std::size_t size);
  406. /**
  407. * Flushes a range of bytes within the current process' address space at the specified
  408. * virtual address.
  409. *
  410. * @param dest_addr The destination virtual address to flush the data from.
  411. * @param size The size of the range to flush, in bytes.
  412. *
  413. */
  414. Result FlushDataCache(Common::ProcessAddress dest_addr, std::size_t size);
  415. /**
  416. * Marks each page within the specified address range as cached or uncached.
  417. *
  418. * @param vaddr The virtual address indicating the start of the address range.
  419. * @param size The size of the address range in bytes.
  420. * @param cached Whether or not any pages within the address range should be
  421. * marked as cached or uncached.
  422. */
  423. void RasterizerMarkRegionCached(Common::ProcessAddress vaddr, u64 size, bool cached);
  424. /**
  425. * Marks each page within the specified address range as debug or non-debug.
  426. * Debug addresses are not accessible from fastmem pointers.
  427. *
  428. * @param vaddr The virtual address indicating the start of the address range.
  429. * @param size The size of the address range in bytes.
  430. * @param debug Whether or not any pages within the address range should be
  431. * marked as debug or non-debug.
  432. */
  433. void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug);
  434. void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
  435. void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size);
  436. bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
  437. void FlushRegion(Common::ProcessAddress dest_addr, size_t size);
  438. private:
  439. Core::System& system;
  440. struct Impl;
  441. std::unique_ptr<Impl> impl;
  442. };
  443. enum GuestMemoryFlags : u32 {
  444. Read = 1 << 0,
  445. Write = 1 << 1,
  446. Safe = 1 << 2,
  447. Cached = 1 << 3,
  448. SafeRead = Read | Safe,
  449. SafeWrite = Write | Safe,
  450. SafeReadWrite = SafeRead | SafeWrite,
  451. SafeReadCachedWrite = SafeReadWrite | Cached,
  452. UnsafeRead = Read,
  453. UnsafeWrite = Write,
  454. UnsafeReadWrite = UnsafeRead | UnsafeWrite,
  455. UnsafeReadCachedWrite = UnsafeReadWrite | Cached,
  456. };
  457. namespace {
  458. template <typename M, typename T, GuestMemoryFlags FLAGS>
  459. class GuestMemory {
  460. using iterator = T*;
  461. using const_iterator = const T*;
  462. using value_type = T;
  463. using element_type = T;
  464. using iterator_category = std::contiguous_iterator_tag;
  465. public:
  466. GuestMemory() = delete;
  467. explicit GuestMemory(M& memory, u64 addr, std::size_t size,
  468. Common::ScratchBuffer<T>* backup = nullptr)
  469. : m_memory{memory}, m_addr{addr}, m_size{size} {
  470. static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
  471. if constexpr (FLAGS & GuestMemoryFlags::Read) {
  472. Read(addr, size, backup);
  473. }
  474. }
  475. ~GuestMemory() = default;
  476. T* data() noexcept {
  477. return m_data_span.data();
  478. }
  479. const T* data() const noexcept {
  480. return m_data_span.data();
  481. }
  482. size_t size() const noexcept {
  483. return m_size;
  484. }
  485. size_t size_bytes() const noexcept {
  486. return this->size() * sizeof(T);
  487. }
  488. [[nodiscard]] T* begin() noexcept {
  489. return this->data();
  490. }
  491. [[nodiscard]] const T* begin() const noexcept {
  492. return this->data();
  493. }
  494. [[nodiscard]] T* end() noexcept {
  495. return this->data() + this->size();
  496. }
  497. [[nodiscard]] const T* end() const noexcept {
  498. return this->data() + this->size();
  499. }
  500. T& operator[](size_t index) noexcept {
  501. return m_data_span[index];
  502. }
  503. const T& operator[](size_t index) const noexcept {
  504. return m_data_span[index];
  505. }
  506. void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
  507. m_addr = addr;
  508. m_size = size;
  509. m_addr_changed = true;
  510. }
  511. std::span<T> Read(u64 addr, std::size_t size,
  512. Common::ScratchBuffer<T>* backup = nullptr) noexcept {
  513. m_addr = addr;
  514. m_size = size;
  515. if (m_size == 0) {
  516. m_is_data_copy = true;
  517. return {};
  518. }
  519. if (this->TrySetSpan()) {
  520. if constexpr (FLAGS & GuestMemoryFlags::Safe) {
  521. m_memory.FlushRegion(m_addr, this->size_bytes());
  522. }
  523. } else {
  524. if (backup) {
  525. backup->resize_destructive(this->size());
  526. m_data_span = *backup;
  527. } else {
  528. m_data_copy.resize(this->size());
  529. m_data_span = std::span(m_data_copy);
  530. }
  531. m_is_data_copy = true;
  532. m_span_valid = true;
  533. if constexpr (FLAGS & GuestMemoryFlags::Safe) {
  534. m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
  535. } else {
  536. m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
  537. }
  538. }
  539. return m_data_span;
  540. }
  541. void Write(std::span<T> write_data) noexcept {
  542. if constexpr (FLAGS & GuestMemoryFlags::Cached) {
  543. m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
  544. } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
  545. m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
  546. } else {
  547. m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
  548. }
  549. }
  550. bool TrySetSpan() noexcept {
  551. if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
  552. m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
  553. m_span_valid = true;
  554. return true;
  555. }
  556. return false;
  557. }
  558. protected:
  559. bool IsDataCopy() const noexcept {
  560. return m_is_data_copy;
  561. }
  562. bool AddressChanged() const noexcept {
  563. return m_addr_changed;
  564. }
  565. M& m_memory;
  566. u64 m_addr{};
  567. size_t m_size{};
  568. std::span<T> m_data_span{};
  569. std::vector<T> m_data_copy{};
  570. bool m_span_valid{false};
  571. bool m_is_data_copy{false};
  572. bool m_addr_changed{false};
  573. };
  574. template <typename M, typename T, GuestMemoryFlags FLAGS>
  575. class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
  576. public:
  577. GuestMemoryScoped() = delete;
  578. explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
  579. Common::ScratchBuffer<T>* backup = nullptr)
  580. : GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
  581. if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
  582. if (!this->TrySetSpan()) {
  583. if (backup) {
  584. this->m_data_span = *backup;
  585. this->m_span_valid = true;
  586. this->m_is_data_copy = true;
  587. }
  588. }
  589. }
  590. }
  591. ~GuestMemoryScoped() {
  592. if constexpr (FLAGS & GuestMemoryFlags::Write) {
  593. if (this->size() == 0) [[unlikely]] {
  594. return;
  595. }
  596. if (this->AddressChanged() || this->IsDataCopy()) {
  597. ASSERT(this->m_span_valid);
  598. if constexpr (FLAGS & GuestMemoryFlags::Cached) {
  599. this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
  600. } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
  601. this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
  602. } else {
  603. this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
  604. }
  605. } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || (FLAGS & GuestMemoryFlags::Cached)) {
  606. this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
  607. }
  608. }
  609. }
  610. };
  611. } // namespace
  612. template <typename T, GuestMemoryFlags FLAGS>
  613. using CpuGuestMemory = GuestMemory<Memory, T, FLAGS>;
  614. template <typename T, GuestMemoryFlags FLAGS>
  615. using CpuGuestMemoryScoped = GuestMemoryScoped<Memory, T, FLAGS>;
  616. template <typename T, GuestMemoryFlags FLAGS>
  617. using GpuGuestMemory = GuestMemory<Tegra::MemoryManager, T, FLAGS>;
  618. template <typename T, GuestMemoryFlags FLAGS>
  619. using GpuGuestMemoryScoped = GuestMemoryScoped<Tegra::MemoryManager, T, FLAGS>;
  620. } // namespace Core::Memory