diff options
Diffstat (limited to 'src/core/memory.cpp')
| -rw-r--r-- | src/core/memory.cpp | 128 |
1 files changed, 76 insertions, 52 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 9024f4922..65649d9d7 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -83,19 +83,13 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { | |||
| 83 | LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, | 83 | LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, |
| 84 | (base + size) * PAGE_SIZE); | 84 | (base + size) * PAGE_SIZE); |
| 85 | 85 | ||
| 86 | u32 end = base + size; | 86 | RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, |
| 87 | FlushMode::FlushAndInvalidate); | ||
| 87 | 88 | ||
| 89 | u32 end = base + size; | ||
| 88 | while (base != end) { | 90 | while (base != end) { |
| 89 | ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base); | 91 | ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base); |
| 90 | 92 | ||
| 91 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be | ||
| 92 | // null here | ||
| 93 | if (current_page_table->attributes[base] == PageType::RasterizerCachedMemory || | ||
| 94 | current_page_table->attributes[base] == PageType::RasterizerCachedSpecial) { | ||
| 95 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(base << PAGE_BITS), | ||
| 96 | PAGE_SIZE); | ||
| 97 | } | ||
| 98 | |||
| 99 | current_page_table->attributes[base] = type; | 93 | current_page_table->attributes[base] = type; |
| 100 | current_page_table->pointers[base] = memory; | 94 | current_page_table->pointers[base] = memory; |
| 101 | current_page_table->cached_res_count[base] = 0; | 95 | current_page_table->cached_res_count[base] = 0; |
| @@ -196,7 +190,7 @@ T Read(const VAddr vaddr) { | |||
| 196 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | 190 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); |
| 197 | break; | 191 | break; |
| 198 | case PageType::RasterizerCachedMemory: { | 192 | case PageType::RasterizerCachedMemory: { |
| 199 | RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | 193 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush); |
| 200 | 194 | ||
| 201 | T value; | 195 | T value; |
| 202 | std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T)); | 196 | std::memcpy(&value, GetPointerFromVMA(vaddr), sizeof(T)); |
| @@ -205,8 +199,7 @@ T Read(const VAddr vaddr) { | |||
| 205 | case PageType::Special: | 199 | case PageType::Special: |
| 206 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); | 200 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); |
| 207 | case PageType::RasterizerCachedSpecial: { | 201 | case PageType::RasterizerCachedSpecial: { |
| 208 | RasterizerFlushRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | 202 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush); |
| 209 | |||
| 210 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); | 203 | return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr); |
| 211 | } | 204 | } |
| 212 | default: | 205 | default: |
| @@ -236,8 +229,7 @@ void Write(const VAddr vaddr, const T data) { | |||
| 236 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | 229 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); |
| 237 | break; | 230 | break; |
| 238 | case PageType::RasterizerCachedMemory: { | 231 | case PageType::RasterizerCachedMemory: { |
| 239 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | 232 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::FlushAndInvalidate); |
| 240 | |||
| 241 | std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T)); | 233 | std::memcpy(GetPointerFromVMA(vaddr), &data, sizeof(T)); |
| 242 | break; | 234 | break; |
| 243 | } | 235 | } |
| @@ -245,8 +237,7 @@ void Write(const VAddr vaddr, const T data) { | |||
| 245 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); | 237 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); |
| 246 | break; | 238 | break; |
| 247 | case PageType::RasterizerCachedSpecial: { | 239 | case PageType::RasterizerCachedSpecial: { |
| 248 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(vaddr), sizeof(T)); | 240 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::FlushAndInvalidate); |
| 249 | |||
| 250 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); | 241 | WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data); |
| 251 | break; | 242 | break; |
| 252 | } | 243 | } |
| @@ -275,7 +266,8 @@ bool IsValidVirtualAddress(const VAddr vaddr) { | |||
| 275 | } | 266 | } |
| 276 | 267 | ||
| 277 | bool IsValidPhysicalAddress(const PAddr paddr) { | 268 | bool IsValidPhysicalAddress(const PAddr paddr) { |
| 278 | return IsValidVirtualAddress(PhysicalToVirtualAddress(paddr)); | 269 | boost::optional<VAddr> vaddr = PhysicalToVirtualAddress(paddr); |
| 270 | return vaddr && IsValidVirtualAddress(*vaddr); | ||
| 279 | } | 271 | } |
| 280 | 272 | ||
| 281 | u8* GetPointer(const VAddr vaddr) { | 273 | u8* GetPointer(const VAddr vaddr) { |
| @@ -308,7 +300,8 @@ std::string ReadCString(VAddr vaddr, std::size_t max_length) { | |||
| 308 | 300 | ||
| 309 | u8* GetPhysicalPointer(PAddr address) { | 301 | u8* GetPhysicalPointer(PAddr address) { |
| 310 | // TODO(Subv): This call should not go through the application's memory mapping. | 302 | // TODO(Subv): This call should not go through the application's memory mapping. |
| 311 | return GetPointer(PhysicalToVirtualAddress(address)); | 303 | boost::optional<VAddr> vaddr = PhysicalToVirtualAddress(address); |
| 304 | return vaddr ? GetPointer(*vaddr) : nullptr; | ||
| 312 | } | 305 | } |
| 313 | 306 | ||
| 314 | void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { | 307 | void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { |
| @@ -319,8 +312,12 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { | |||
| 319 | u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; | 312 | u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; |
| 320 | PAddr paddr = start; | 313 | PAddr paddr = start; |
| 321 | 314 | ||
| 322 | for (unsigned i = 0; i < num_pages; ++i) { | 315 | for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) { |
| 323 | VAddr vaddr = PhysicalToVirtualAddress(paddr); | 316 | boost::optional<VAddr> maybe_vaddr = PhysicalToVirtualAddress(paddr); |
| 317 | if (!maybe_vaddr) | ||
| 318 | continue; | ||
| 319 | VAddr vaddr = *maybe_vaddr; | ||
| 320 | |||
| 324 | u8& res_count = current_page_table->cached_res_count[vaddr >> PAGE_BITS]; | 321 | u8& res_count = current_page_table->cached_res_count[vaddr >> PAGE_BITS]; |
| 325 | ASSERT_MSG(count_delta <= UINT8_MAX - res_count, | 322 | ASSERT_MSG(count_delta <= UINT8_MAX - res_count, |
| 326 | "Rasterizer resource cache counter overflow!"); | 323 | "Rasterizer resource cache counter overflow!"); |
| @@ -368,7 +365,6 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { | |||
| 368 | UNREACHABLE(); | 365 | UNREACHABLE(); |
| 369 | } | 366 | } |
| 370 | } | 367 | } |
| 371 | paddr += PAGE_SIZE; | ||
| 372 | } | 368 | } |
| 373 | } | 369 | } |
| 374 | 370 | ||
| @@ -379,11 +375,48 @@ void RasterizerFlushRegion(PAddr start, u32 size) { | |||
| 379 | } | 375 | } |
| 380 | 376 | ||
| 381 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) { | 377 | void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) { |
| 378 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be | ||
| 379 | // null here | ||
| 382 | if (VideoCore::g_renderer != nullptr) { | 380 | if (VideoCore::g_renderer != nullptr) { |
| 383 | VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size); | 381 | VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size); |
| 384 | } | 382 | } |
| 385 | } | 383 | } |
| 386 | 384 | ||
| 385 | void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) { | ||
| 386 | // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be | ||
| 387 | // null here | ||
| 388 | if (VideoCore::g_renderer != nullptr) { | ||
| 389 | VAddr end = start + size; | ||
| 390 | |||
| 391 | auto CheckRegion = [&](VAddr region_start, VAddr region_end) { | ||
| 392 | if (start >= region_end || end <= region_start) { | ||
| 393 | // No overlap with region | ||
| 394 | return; | ||
| 395 | } | ||
| 396 | |||
| 397 | VAddr overlap_start = std::max(start, region_start); | ||
| 398 | VAddr overlap_end = std::min(end, region_end); | ||
| 399 | |||
| 400 | PAddr physical_start = TryVirtualToPhysicalAddress(overlap_start).value(); | ||
| 401 | u32 overlap_size = overlap_end - overlap_start; | ||
| 402 | |||
| 403 | auto* rasterizer = VideoCore::g_renderer->Rasterizer(); | ||
| 404 | switch (mode) { | ||
| 405 | case FlushMode::Flush: | ||
| 406 | rasterizer->FlushRegion(physical_start, overlap_size); | ||
| 407 | break; | ||
| 408 | case FlushMode::FlushAndInvalidate: | ||
| 409 | rasterizer->FlushAndInvalidateRegion(physical_start, overlap_size); | ||
| 410 | break; | ||
| 411 | } | ||
| 412 | }; | ||
| 413 | |||
| 414 | CheckRegion(LINEAR_HEAP_VADDR, LINEAR_HEAP_VADDR_END); | ||
| 415 | CheckRegion(NEW_LINEAR_HEAP_VADDR, NEW_LINEAR_HEAP_VADDR_END); | ||
| 416 | CheckRegion(VRAM_VADDR, VRAM_VADDR_END); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 387 | u8 Read8(const VAddr addr) { | 420 | u8 Read8(const VAddr addr) { |
| 388 | return Read<u8>(addr); | 421 | return Read<u8>(addr); |
| 389 | } | 422 | } |
| @@ -430,16 +463,13 @@ void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { | |||
| 430 | break; | 463 | break; |
| 431 | } | 464 | } |
| 432 | case PageType::RasterizerCachedMemory: { | 465 | case PageType::RasterizerCachedMemory: { |
| 433 | RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); | 466 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); |
| 434 | |||
| 435 | std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount); | 467 | std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount); |
| 436 | break; | 468 | break; |
| 437 | } | 469 | } |
| 438 | case PageType::RasterizerCachedSpecial: { | 470 | case PageType::RasterizerCachedSpecial: { |
| 439 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); | 471 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); |
| 440 | 472 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); | |
| 441 | RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); | ||
| 442 | |||
| 443 | GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); | 473 | GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); |
| 444 | break; | 474 | break; |
| 445 | } | 475 | } |
| @@ -500,18 +530,13 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size | |||
| 500 | break; | 530 | break; |
| 501 | } | 531 | } |
| 502 | case PageType::RasterizerCachedMemory: { | 532 | case PageType::RasterizerCachedMemory: { |
| 503 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), | 533 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); |
| 504 | copy_amount); | ||
| 505 | |||
| 506 | std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount); | 534 | std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount); |
| 507 | break; | 535 | break; |
| 508 | } | 536 | } |
| 509 | case PageType::RasterizerCachedSpecial: { | 537 | case PageType::RasterizerCachedSpecial: { |
| 510 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); | 538 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); |
| 511 | 539 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); | |
| 512 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), | ||
| 513 | copy_amount); | ||
| 514 | |||
| 515 | GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); | 540 | GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); |
| 516 | break; | 541 | break; |
| 517 | } | 542 | } |
| @@ -557,18 +582,13 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) { | |||
| 557 | break; | 582 | break; |
| 558 | } | 583 | } |
| 559 | case PageType::RasterizerCachedMemory: { | 584 | case PageType::RasterizerCachedMemory: { |
| 560 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), | 585 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); |
| 561 | copy_amount); | ||
| 562 | |||
| 563 | std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount); | 586 | std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount); |
| 564 | break; | 587 | break; |
| 565 | } | 588 | } |
| 566 | case PageType::RasterizerCachedSpecial: { | 589 | case PageType::RasterizerCachedSpecial: { |
| 567 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); | 590 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); |
| 568 | 591 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); | |
| 569 | RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), | ||
| 570 | copy_amount); | ||
| 571 | |||
| 572 | GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount); | 592 | GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount); |
| 573 | break; | 593 | break; |
| 574 | } | 594 | } |
| @@ -613,15 +633,13 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { | |||
| 613 | break; | 633 | break; |
| 614 | } | 634 | } |
| 615 | case PageType::RasterizerCachedMemory: { | 635 | case PageType::RasterizerCachedMemory: { |
| 616 | RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); | 636 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); |
| 617 | |||
| 618 | WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount); | 637 | WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount); |
| 619 | break; | 638 | break; |
| 620 | } | 639 | } |
| 621 | case PageType::RasterizerCachedSpecial: { | 640 | case PageType::RasterizerCachedSpecial: { |
| 622 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); | 641 | DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); |
| 623 | 642 | RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); | |
| 624 | RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); | ||
| 625 | 643 | ||
| 626 | std::vector<u8> buffer(copy_amount); | 644 | std::vector<u8> buffer(copy_amount); |
| 627 | GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size()); | 645 | GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size()); |
| @@ -680,7 +698,7 @@ void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data) | |||
| 680 | mmio_handler->Write64(addr, data); | 698 | mmio_handler->Write64(addr, data); |
| 681 | } | 699 | } |
| 682 | 700 | ||
| 683 | PAddr VirtualToPhysicalAddress(const VAddr addr) { | 701 | boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { |
| 684 | if (addr == 0) { | 702 | if (addr == 0) { |
| 685 | return 0; | 703 | return 0; |
| 686 | } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { | 704 | } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { |
| @@ -697,12 +715,20 @@ PAddr VirtualToPhysicalAddress(const VAddr addr) { | |||
| 697 | return addr - N3DS_EXTRA_RAM_VADDR + N3DS_EXTRA_RAM_PADDR; | 715 | return addr - N3DS_EXTRA_RAM_VADDR + N3DS_EXTRA_RAM_PADDR; |
| 698 | } | 716 | } |
| 699 | 717 | ||
| 700 | LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08X", addr); | 718 | return boost::none; |
| 701 | // To help with debugging, set bit on address so that it's obviously invalid. | 719 | } |
| 702 | return addr | 0x80000000; | 720 | |
| 721 | PAddr VirtualToPhysicalAddress(const VAddr addr) { | ||
| 722 | auto paddr = TryVirtualToPhysicalAddress(addr); | ||
| 723 | if (!paddr) { | ||
| 724 | LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08X", addr); | ||
| 725 | // To help with debugging, set bit on address so that it's obviously invalid. | ||
| 726 | return addr | 0x80000000; | ||
| 727 | } | ||
| 728 | return *paddr; | ||
| 703 | } | 729 | } |
| 704 | 730 | ||
| 705 | VAddr PhysicalToVirtualAddress(const PAddr addr) { | 731 | boost::optional<VAddr> PhysicalToVirtualAddress(const PAddr addr) { |
| 706 | if (addr == 0) { | 732 | if (addr == 0) { |
| 707 | return 0; | 733 | return 0; |
| 708 | } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { | 734 | } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { |
| @@ -717,9 +743,7 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) { | |||
| 717 | return addr - N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_VADDR; | 743 | return addr - N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_VADDR; |
| 718 | } | 744 | } |
| 719 | 745 | ||
| 720 | LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08X", addr); | 746 | return boost::none; |
| 721 | // To help with debugging, set bit on address so that it's obviously invalid. | ||
| 722 | return addr | 0x80000000; | ||
| 723 | } | 747 | } |
| 724 | 748 | ||
| 725 | } // namespace | 749 | } // namespace |