diff options
| author | 2019-11-26 17:39:57 -0500 | |
|---|---|---|
| committer | 2019-11-26 21:55:39 -0500 | |
| commit | e4c381b8850db96f162cfcf2cbe28b0e7c1f76f1 (patch) | |
| tree | 14b95ea207543f3884558ebdf8673a511bf64dc3 /src/core/memory.cpp | |
| parent | core/memory: Migrate over Read{8, 16, 32, 64, Block} to the Memory class (diff) | |
| download | yuzu-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.cpp | 220 |
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) { | |||
| 58 | u8* GetPointerFromVMA(VAddr vaddr) { | 58 | u8* GetPointerFromVMA(VAddr vaddr) { |
| 59 | return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); | 59 | return ::Memory::GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); |
| 60 | } | 60 | } |
| 61 | |||
| 62 | template <typename T> | ||
| 63 | void 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 | ||
| 639 | void Memory::Write8(VAddr addr, u8 data) { | ||
| 640 | impl->Write8(addr, data); | ||
| 641 | } | ||
| 642 | |||
| 643 | void Memory::Write16(VAddr addr, u16 data) { | ||
| 644 | impl->Write16(addr, data); | ||
| 645 | } | ||
| 646 | |||
| 647 | void Memory::Write32(VAddr addr, u32 data) { | ||
| 648 | impl->Write32(addr, data); | ||
| 649 | } | ||
| 650 | |||
| 651 | void Memory::Write64(VAddr addr, u64 data) { | ||
| 652 | impl->Write64(addr, data); | ||
| 653 | } | ||
| 654 | |||
| 565 | std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { | 655 | std::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 | ||
| 668 | void 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 | |||
| 673 | void 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 | |||
| 578 | void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { | 677 | void 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 | ||
| 615 | void Write8(const VAddr addr, const u8 data) { | ||
| 616 | Write<u8>(addr, data); | ||
| 617 | } | ||
| 618 | |||
| 619 | void Write16(const VAddr addr, const u16 data) { | ||
| 620 | Write<u16_le>(addr, data); | ||
| 621 | } | ||
| 622 | |||
| 623 | void Write32(const VAddr addr, const u32 data) { | ||
| 624 | Write<u32_le>(addr, data); | ||
| 625 | } | ||
| 626 | |||
| 627 | void Write64(const VAddr addr, const u64 data) { | ||
| 628 | Write<u64_le>(addr, data); | ||
| 629 | } | ||
| 630 | |||
| 631 | void 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 | |||
| 674 | void 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 |