diff options
Diffstat (limited to 'src/core/memory.cpp')
| -rw-r--r-- | src/core/memory.cpp | 228 |
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 | ||
| 62 | template <typename T> | 62 | template <typename T> |
| 63 | T 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 | |||
| 93 | template <typename T> | ||
| 94 | void Write(const VAddr vaddr, const T data) { | 63 | void 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 | ||
| 549 | u8 Memory::Read8(const VAddr addr) { | ||
| 550 | return impl->Read8(addr); | ||
| 551 | } | ||
| 552 | |||
| 553 | u16 Memory::Read16(const VAddr addr) { | ||
| 554 | return impl->Read16(addr); | ||
| 555 | } | ||
| 556 | |||
| 557 | u32 Memory::Read32(const VAddr addr) { | ||
| 558 | return impl->Read32(addr); | ||
| 559 | } | ||
| 560 | |||
| 561 | u64 Memory::Read64(const VAddr addr) { | ||
| 562 | return impl->Read64(addr); | ||
| 563 | } | ||
| 564 | |||
| 473 | std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { | 565 | std::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 | ||
| 569 | void 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 | |||
| 574 | void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { | ||
| 575 | impl->ReadBlock(src_addr, dest_buffer, size); | ||
| 576 | } | ||
| 577 | |||
| 477 | void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { | 578 | void 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 | ||
| 514 | u8 Read8(const VAddr addr) { | ||
| 515 | return Read<u8>(addr); | ||
| 516 | } | ||
| 517 | |||
| 518 | u16 Read16(const VAddr addr) { | ||
| 519 | return Read<u16_le>(addr); | ||
| 520 | } | ||
| 521 | |||
| 522 | u32 Read32(const VAddr addr) { | ||
| 523 | return Read<u32_le>(addr); | ||
| 524 | } | ||
| 525 | |||
| 526 | u64 Read64(const VAddr addr) { | ||
| 527 | return Read<u64_le>(addr); | ||
| 528 | } | ||
| 529 | |||
| 530 | void 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 | |||
| 575 | void 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 | |||
| 579 | void Write8(const VAddr addr, const u8 data) { | 615 | void Write8(const VAddr addr, const u8 data) { |
| 580 | Write<u8>(addr, data); | 616 | Write<u8>(addr, data); |
| 581 | } | 617 | } |