summaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp228
1 files changed, 132 insertions, 96 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index c939e980d..699c48107 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -60,37 +60,6 @@ u8* GetPointerFromVMA(VAddr vaddr) {
60} 60}
61 61
62template <typename T> 62template <typename T>
63T Read(const VAddr vaddr) {
64 const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
65 if (page_pointer != nullptr) {
66 // NOTE: Avoid adding any extra logic to this fast-path block
67 T value;
68 std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
69 return value;
70 }
71
72 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
73 switch (type) {
74 case Common::PageType::Unmapped:
75 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
76 return 0;
77 case Common::PageType::Memory:
78 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
79 break;
80 case Common::PageType::RasterizerCachedMemory: {
81 const u8* const host_ptr{GetPointerFromVMA(vaddr)};
82 Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
83 T value;
84 std::memcpy(&value, host_ptr, sizeof(T));
85 return value;
86 }
87 default:
88 UNREACHABLE();
89 }
90 return {};
91}
92
93template <typename T>
94void Write(const VAddr vaddr, const T data) { 63void Write(const VAddr vaddr, const T data) {
95 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 64 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
96 if (page_pointer != nullptr) { 65 if (page_pointer != nullptr) {
@@ -210,6 +179,22 @@ struct Memory::Impl {
210 return nullptr; 179 return nullptr;
211 } 180 }
212 181
182 u8 Read8(const VAddr addr) {
183 return Read<u8>(addr);
184 }
185
186 u16 Read16(const VAddr addr) {
187 return Read<u16_le>(addr);
188 }
189
190 u32 Read32(const VAddr addr) {
191 return Read<u32_le>(addr);
192 }
193
194 u64 Read64(const VAddr addr) {
195 return Read<u64_le>(addr);
196 }
197
213 std::string ReadCString(VAddr vaddr, std::size_t max_length) { 198 std::string ReadCString(VAddr vaddr, std::size_t max_length) {
214 std::string string; 199 std::string string;
215 string.reserve(max_length); 200 string.reserve(max_length);
@@ -225,6 +210,55 @@ struct Memory::Impl {
225 return string; 210 return string;
226 } 211 }
227 212
213 void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
214 const std::size_t size) {
215 const auto& page_table = process.VMManager().page_table;
216
217 std::size_t remaining_size = size;
218 std::size_t page_index = src_addr >> PAGE_BITS;
219 std::size_t page_offset = src_addr & PAGE_MASK;
220
221 while (remaining_size > 0) {
222 const std::size_t copy_amount =
223 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
224 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
225
226 switch (page_table.attributes[page_index]) {
227 case Common::PageType::Unmapped: {
228 LOG_ERROR(HW_Memory,
229 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
230 current_vaddr, src_addr, size);
231 std::memset(dest_buffer, 0, copy_amount);
232 break;
233 }
234 case Common::PageType::Memory: {
235 DEBUG_ASSERT(page_table.pointers[page_index]);
236
237 const u8* const src_ptr = page_table.pointers[page_index] + page_offset;
238 std::memcpy(dest_buffer, src_ptr, copy_amount);
239 break;
240 }
241 case Common::PageType::RasterizerCachedMemory: {
242 const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
243 system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
244 std::memcpy(dest_buffer, host_ptr, copy_amount);
245 break;
246 }
247 default:
248 UNREACHABLE();
249 }
250
251 page_index++;
252 page_offset = 0;
253 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
254 remaining_size -= copy_amount;
255 }
256 }
257
258 void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
259 ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size);
260 }
261
228 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 262 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
229 const auto& page_table = process.VMManager().page_table; 263 const auto& page_table = process.VMManager().page_table;
230 std::size_t remaining_size = size; 264 std::size_t remaining_size = size;
@@ -425,6 +459,48 @@ struct Memory::Impl {
425 } 459 }
426 } 460 }
427 461
462 /**
463 * Reads a particular data type out of memory at the given virtual address.
464 *
465 * @param vaddr The virtual address to read the data type from.
466 *
467 * @tparam T The data type to read out of memory. This type *must* be
468 * trivially copyable, otherwise the behavior of this function
469 * is undefined.
470 *
471 * @returns The instance of T read from the specified virtual address.
472 */
473 template <typename T>
474 T Read(const VAddr vaddr) {
475 const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
476 if (page_pointer != nullptr) {
477 // NOTE: Avoid adding any extra logic to this fast-path block
478 T value;
479 std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
480 return value;
481 }
482
483 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
484 switch (type) {
485 case Common::PageType::Unmapped:
486 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
487 return 0;
488 case Common::PageType::Memory:
489 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
490 break;
491 case Common::PageType::RasterizerCachedMemory: {
492 const u8* const host_ptr = GetPointerFromVMA(vaddr);
493 system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T));
494 T value;
495 std::memcpy(&value, host_ptr, sizeof(T));
496 return value;
497 }
498 default:
499 UNREACHABLE();
500 }
501 return {};
502 }
503
428 Core::System& system; 504 Core::System& system;
429}; 505};
430 506
@@ -470,10 +546,35 @@ const u8* Memory::GetPointer(VAddr vaddr) const {
470 return impl->GetPointer(vaddr); 546 return impl->GetPointer(vaddr);
471} 547}
472 548
549u8 Memory::Read8(const VAddr addr) {
550 return impl->Read8(addr);
551}
552
553u16 Memory::Read16(const VAddr addr) {
554 return impl->Read16(addr);
555}
556
557u32 Memory::Read32(const VAddr addr) {
558 return impl->Read32(addr);
559}
560
561u64 Memory::Read64(const VAddr addr) {
562 return impl->Read64(addr);
563}
564
473std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { 565std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
474 return impl->ReadCString(vaddr, max_length); 566 return impl->ReadCString(vaddr, max_length);
475} 567}
476 568
569void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
570 const std::size_t size) {
571 impl->ReadBlock(process, src_addr, dest_buffer, size);
572}
573
574void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
575 impl->ReadBlock(src_addr, dest_buffer, size);
576}
577
477void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { 578void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
478 impl->ZeroBlock(process, dest_addr, size); 579 impl->ZeroBlock(process, dest_addr, size);
479} 580}
@@ -511,71 +612,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
511 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; 612 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
512} 613}
513 614
514u8 Read8(const VAddr addr) {
515 return Read<u8>(addr);
516}
517
518u16 Read16(const VAddr addr) {
519 return Read<u16_le>(addr);
520}
521
522u32 Read32(const VAddr addr) {
523 return Read<u32_le>(addr);
524}
525
526u64 Read64(const VAddr addr) {
527 return Read<u64_le>(addr);
528}
529
530void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
531 const std::size_t size) {
532 const auto& page_table = process.VMManager().page_table;
533
534 std::size_t remaining_size = size;
535 std::size_t page_index = src_addr >> PAGE_BITS;
536 std::size_t page_offset = src_addr & PAGE_MASK;
537
538 while (remaining_size > 0) {
539 const std::size_t copy_amount =
540 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
541 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
542
543 switch (page_table.attributes[page_index]) {
544 case Common::PageType::Unmapped: {
545 LOG_ERROR(HW_Memory,
546 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
547 current_vaddr, src_addr, size);
548 std::memset(dest_buffer, 0, copy_amount);
549 break;
550 }
551 case Common::PageType::Memory: {
552 DEBUG_ASSERT(page_table.pointers[page_index]);
553
554 const u8* src_ptr = page_table.pointers[page_index] + page_offset;
555 std::memcpy(dest_buffer, src_ptr, copy_amount);
556 break;
557 }
558 case Common::PageType::RasterizerCachedMemory: {
559 const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
560 Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount);
561 std::memcpy(dest_buffer, host_ptr, copy_amount);
562 break;
563 }
564 default:
565 UNREACHABLE();
566 }
567
568 page_index++;
569 page_offset = 0;
570 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
571 remaining_size -= copy_amount;
572 }
573}
574
575void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
576 ReadBlock(*Core::System::GetInstance().CurrentProcess(), src_addr, dest_buffer, size);
577}
578
579void Write8(const VAddr addr, const u8 data) { 615void Write8(const VAddr addr, const u8 data) {
580 Write<u8>(addr, data); 616 Write<u8>(addr, data);
581} 617}