summaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
authorGravatar Lioncash2019-11-26 17:39:57 -0500
committerGravatar Lioncash2019-11-26 21:55:39 -0500
commite4c381b8850db96f162cfcf2cbe28b0e7c1f76f1 (patch)
tree14b95ea207543f3884558ebdf8673a511bf64dc3 /src/core/memory.cpp
parentcore/memory: Migrate over Read{8, 16, 32, 64, Block} to the Memory class (diff)
downloadyuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.gz
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.tar.xz
yuzu-e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1.zip
core/memory: Migrate over Write{8, 16, 32, 64, Block} to the Memory class
The Write functions are used slightly less than the Read functions, which make these a bit nicer to move over. The only adjustments we really need to make here are to Dynarmic's exclusive monitor instance. We need to keep a reference to the currently active memory instance to perform exclusive read/write operations.
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp220
1 files changed, 128 insertions, 92 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 699c48107..5c940a82e 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -58,35 +58,6 @@ u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
58u8* GetPointerFromVMA(VAddr vaddr) { 58u8* GetPointerFromVMA(VAddr vaddr) {
59 return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); 59 return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr);
60} 60}
61
62template <typename T>
63void Write(const VAddr vaddr, const T data) {
64 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 std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
68 return;
69 }
70
71 Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
72 switch (type) {
73 case Common::PageType::Unmapped:
74 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
75 static_cast<u32>(data), vaddr);
76 return;
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 u8* const host_ptr{GetPointerFromVMA(vaddr)};
82 Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
83 std::memcpy(host_ptr, &data, sizeof(T));
84 break;
85 }
86 default:
87 UNREACHABLE();
88 }
89}
90} // Anonymous namespace 61} // Anonymous namespace
91 62
92// Implementation class used to keep the specifics of the memory subsystem hidden 63// Implementation class used to keep the specifics of the memory subsystem hidden
@@ -195,6 +166,22 @@ struct Memory::Impl {
195 return Read<u64_le>(addr); 166 return Read<u64_le>(addr);
196 } 167 }
197 168
169 void Write8(const VAddr addr, const u8 data) {
170 Write<u8>(addr, data);
171 }
172
173 void Write16(const VAddr addr, const u16 data) {
174 Write<u16_le>(addr, data);
175 }
176
177 void Write32(const VAddr addr, const u32 data) {
178 Write<u32_le>(addr, data);
179 }
180
181 void Write64(const VAddr addr, const u64 data) {
182 Write<u64_le>(addr, data);
183 }
184
198 std::string ReadCString(VAddr vaddr, std::size_t max_length) { 185 std::string ReadCString(VAddr vaddr, std::size_t max_length) {
199 std::string string; 186 std::string string;
200 string.reserve(max_length); 187 string.reserve(max_length);
@@ -259,6 +246,53 @@ struct Memory::Impl {
259 ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); 246 ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size);
260 } 247 }
261 248
249 void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
250 const std::size_t size) {
251 const auto& page_table = process.VMManager().page_table;
252 std::size_t remaining_size = size;
253 std::size_t page_index = dest_addr >> PAGE_BITS;
254 std::size_t page_offset = dest_addr & PAGE_MASK;
255
256 while (remaining_size > 0) {
257 const std::size_t copy_amount =
258 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
259 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
260
261 switch (page_table.attributes[page_index]) {
262 case Common::PageType::Unmapped: {
263 LOG_ERROR(HW_Memory,
264 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
265 current_vaddr, dest_addr, size);
266 break;
267 }
268 case Common::PageType::Memory: {
269 DEBUG_ASSERT(page_table.pointers[page_index]);
270
271 u8* const dest_ptr = page_table.pointers[page_index] + page_offset;
272 std::memcpy(dest_ptr, src_buffer, copy_amount);
273 break;
274 }
275 case Common::PageType::RasterizerCachedMemory: {
276 u8* const host_ptr = GetPointerFromVMA(process, current_vaddr);
277 system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
278 std::memcpy(host_ptr, src_buffer, copy_amount);
279 break;
280 }
281 default:
282 UNREACHABLE();
283 }
284
285 page_index++;
286 page_offset = 0;
287 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
288 remaining_size -= copy_amount;
289 }
290 }
291
292 void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
293 WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size);
294 }
295
262 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 296 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
263 const auto& page_table = process.VMManager().page_table; 297 const auto& page_table = process.VMManager().page_table;
264 std::size_t remaining_size = size; 298 std::size_t remaining_size = size;
@@ -501,6 +535,46 @@ struct Memory::Impl {
501 return {}; 535 return {};
502 } 536 }
503 537
538 /**
539 * Writes a particular data type to memory at the given virtual address.
540 *
541 * @param vaddr The virtual address to write the data type to.
542 *
543 * @tparam T The data type to write to memory. This type *must* be
544 * trivially copyable, otherwise the behavior of this function
545 * is undefined.
546 *
547 * @returns The instance of T write to the specified virtual address.
548 */
549 template <typename T>
550 void Write(const VAddr vaddr, const T data) {
551 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
552 if (page_pointer != nullptr) {
553 // NOTE: Avoid adding any extra logic to this fast-path block
554 std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
555 return;
556 }
557
558 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
559 switch (type) {
560 case Common::PageType::Unmapped:
561 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
562 static_cast<u32>(data), vaddr);
563 return;
564 case Common::PageType::Memory:
565 ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
566 break;
567 case Common::PageType::RasterizerCachedMemory: {
568 u8* const host_ptr{GetPointerFromVMA(vaddr)};
569 system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
570 std::memcpy(host_ptr, &data, sizeof(T));
571 break;
572 }
573 default:
574 UNREACHABLE();
575 }
576 }
577
504 Core::System& system; 578 Core::System& system;
505}; 579};
506 580
@@ -562,6 +636,22 @@ u64 Memory::Read64(const VAddr addr) {
562 return impl->Read64(addr); 636 return impl->Read64(addr);
563} 637}
564 638
639void Memory::Write8(VAddr addr, u8 data) {
640 impl->Write8(addr, data);
641}
642
643void Memory::Write16(VAddr addr, u16 data) {
644 impl->Write16(addr, data);
645}
646
647void Memory::Write32(VAddr addr, u32 data) {
648 impl->Write32(addr, data);
649}
650
651void Memory::Write64(VAddr addr, u64 data) {
652 impl->Write64(addr, data);
653}
654
565std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { 655std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
566 return impl->ReadCString(vaddr, max_length); 656 return impl->ReadCString(vaddr, max_length);
567} 657}
@@ -575,6 +665,15 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_
575 impl->ReadBlock(src_addr, dest_buffer, size); 665 impl->ReadBlock(src_addr, dest_buffer, size);
576} 666}
577 667
668void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
669 std::size_t size) {
670 impl->WriteBlock(process, dest_addr, src_buffer, size);
671}
672
673void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
674 impl->WriteBlock(dest_addr, src_buffer, size);
675}
676
578void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { 677void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
579 impl->ZeroBlock(process, dest_addr, size); 678 impl->ZeroBlock(process, dest_addr, size);
580} 679}
@@ -612,67 +711,4 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
612 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; 711 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
613} 712}
614 713
615void Write8(const VAddr addr, const u8 data) {
616 Write<u8>(addr, data);
617}
618
619void Write16(const VAddr addr, const u16 data) {
620 Write<u16_le>(addr, data);
621}
622
623void Write32(const VAddr addr, const u32 data) {
624 Write<u32_le>(addr, data);
625}
626
627void Write64(const VAddr addr, const u64 data) {
628 Write<u64_le>(addr, data);
629}
630
631void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
632 const std::size_t size) {
633 const auto& page_table = process.VMManager().page_table;
634 std::size_t remaining_size = size;
635 std::size_t page_index = dest_addr >> PAGE_BITS;
636 std::size_t page_offset = dest_addr & PAGE_MASK;
637
638 while (remaining_size > 0) {
639 const std::size_t copy_amount =
640 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
641 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
642
643 switch (page_table.attributes[page_index]) {
644 case Common::PageType::Unmapped: {
645 LOG_ERROR(HW_Memory,
646 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
647 current_vaddr, dest_addr, size);
648 break;
649 }
650 case Common::PageType::Memory: {
651 DEBUG_ASSERT(page_table.pointers[page_index]);
652
653 u8* dest_ptr = page_table.pointers[page_index] + page_offset;
654 std::memcpy(dest_ptr, src_buffer, copy_amount);
655 break;
656 }
657 case Common::PageType::RasterizerCachedMemory: {
658 const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)};
659 Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount);
660 std::memcpy(host_ptr, src_buffer, copy_amount);
661 break;
662 }
663 default:
664 UNREACHABLE();
665 }
666
667 page_index++;
668 page_offset = 0;
669 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
670 remaining_size -= copy_amount;
671 }
672}
673
674void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
675 WriteBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_buffer, size);
676}
677
678} // namespace Memory 714} // namespace Memory