diff options
Diffstat (limited to 'src/core/memory.cpp')
| -rw-r--r-- | src/core/memory.cpp | 112 |
1 files changed, 75 insertions, 37 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 291bf066f..2afa0916d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -39,8 +39,8 @@ PageTable* GetCurrentPageTable() { | |||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { | 41 | static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { |
| 42 | LOG_DEBUG(HW_Memory, "Mapping %p onto %016" PRIX64 "-%016" PRIX64, memory, base * PAGE_SIZE, | 42 | NGLOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, |
| 43 | (base + size) * PAGE_SIZE); | 43 | (base + size) * PAGE_SIZE); |
| 44 | 44 | ||
| 45 | RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, | 45 | RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, |
| 46 | FlushMode::FlushAndInvalidate); | 46 | FlushMode::FlushAndInvalidate); |
| @@ -169,10 +169,10 @@ T Read(const VAddr vaddr) { | |||
| 169 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 169 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
| 170 | switch (type) { | 170 | switch (type) { |
| 171 | case PageType::Unmapped: | 171 | case PageType::Unmapped: |
| 172 | LOG_ERROR(HW_Memory, "unmapped Read%lu @ 0x%08X", sizeof(T) * 8, vaddr); | 172 | NGLOG_ERROR(HW_Memory, "Unmapped Read{} @ {:#010X}", sizeof(T) * 8, vaddr); |
| 173 | return 0; | 173 | return 0; |
| 174 | case PageType::Memory: | 174 | case PageType::Memory: |
| 175 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | 175 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %016" PRIX64, vaddr); |
| 176 | break; | 176 | break; |
| 177 | case PageType::RasterizerCachedMemory: { | 177 | case PageType::RasterizerCachedMemory: { |
| 178 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush); | 178 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Flush); |
| @@ -201,11 +201,11 @@ void Write(const VAddr vaddr, const T data) { | |||
| 201 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 201 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
| 202 | switch (type) { | 202 | switch (type) { |
| 203 | case PageType::Unmapped: | 203 | case PageType::Unmapped: |
| 204 | LOG_ERROR(HW_Memory, "unmapped Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, | 204 | NGLOG_ERROR(HW_Memory, "Unmapped Write{} {:#010X} @ {:#018X}", sizeof(data) * 8, (u32)data, |
| 205 | vaddr); | 205 | vaddr); |
| 206 | return; | 206 | return; |
| 207 | case PageType::Memory: | 207 | case PageType::Memory: |
| 208 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); | 208 | ASSERT_MSG(false, "Mapped memory page without a pointer @ %016" PRIX64, vaddr); |
| 209 | break; | 209 | break; |
| 210 | case PageType::RasterizerCachedMemory: { | 210 | case PageType::RasterizerCachedMemory: { |
| 211 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate); | 211 | RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate); |
| @@ -251,7 +251,7 @@ u8* GetPointer(const VAddr vaddr) { | |||
| 251 | return GetPointerFromVMA(vaddr); | 251 | return GetPointerFromVMA(vaddr); |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr); | 254 | NGLOG_ERROR(HW_Memory, "Unknown GetPointer @ {:#018X}", vaddr); |
| 255 | return nullptr; | 255 | return nullptr; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| @@ -288,13 +288,12 @@ u8* GetPhysicalPointer(PAddr address) { | |||
| 288 | }); | 288 | }); |
| 289 | 289 | ||
| 290 | if (area == std::end(memory_areas)) { | 290 | if (area == std::end(memory_areas)) { |
| 291 | LOG_ERROR(HW_Memory, "unknown GetPhysicalPointer @ 0x%016" PRIX64, address); | 291 | NGLOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#018X}", address); |
| 292 | return nullptr; | 292 | return nullptr; |
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | if (area->paddr_base == IO_AREA_PADDR) { | 295 | if (area->paddr_base == IO_AREA_PADDR) { |
| 296 | LOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr=0x%016" PRIX64, | 296 | NGLOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr={:018X}", address); |
| 297 | address); | ||
| 298 | return nullptr; | 297 | return nullptr; |
| 299 | } | 298 | } |
| 300 | 299 | ||
| @@ -325,15 +324,29 @@ u8* GetPhysicalPointer(PAddr address) { | |||
| 325 | return target_pointer; | 324 | return target_pointer; |
| 326 | } | 325 | } |
| 327 | 326 | ||
| 328 | void RasterizerMarkRegionCached(VAddr start, u64 size, bool cached) { | 327 | void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached) { |
| 329 | if (start == 0) { | 328 | if (gpu_addr == 0) { |
| 330 | return; | 329 | return; |
| 331 | } | 330 | } |
| 332 | 331 | ||
| 333 | u64 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; | 332 | // Iterate over a contiguous CPU address space, which corresponds to the specified GPU address |
| 334 | VAddr vaddr = start; | 333 | // space, marking the region as un/cached. The region is marked un/cached at a granularity of |
| 334 | // CPU pages, hence why we iterate on a CPU page basis (note: GPU page size is different). This | ||
| 335 | // assumes the specified GPU address region is contiguous as well. | ||
| 336 | |||
| 337 | u64 num_pages = ((gpu_addr + size - 1) >> PAGE_BITS) - (gpu_addr >> PAGE_BITS) + 1; | ||
| 338 | for (unsigned i = 0; i < num_pages; ++i, gpu_addr += PAGE_SIZE) { | ||
| 339 | boost::optional<VAddr> maybe_vaddr = | ||
| 340 | Core::System::GetInstance().GPU().memory_manager->GpuToCpuAddress(gpu_addr); | ||
| 341 | // The GPU <-> CPU virtual memory mapping is not 1:1 | ||
| 342 | if (!maybe_vaddr) { | ||
| 343 | NGLOG_ERROR(HW_Memory, | ||
| 344 | "Trying to flush a cached region to an invalid physical address {:016X}", | ||
| 345 | gpu_addr); | ||
| 346 | continue; | ||
| 347 | } | ||
| 348 | VAddr vaddr = *maybe_vaddr; | ||
| 335 | 349 | ||
| 336 | for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { | ||
| 337 | PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 350 | PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
| 338 | 351 | ||
| 339 | if (cached) { | 352 | if (cached) { |
| @@ -347,6 +360,10 @@ void RasterizerMarkRegionCached(VAddr start, u64 size, bool cached) { | |||
| 347 | page_type = PageType::RasterizerCachedMemory; | 360 | page_type = PageType::RasterizerCachedMemory; |
| 348 | current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; | 361 | current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; |
| 349 | break; | 362 | break; |
| 363 | case PageType::RasterizerCachedMemory: | ||
| 364 | // There can be more than one GPU region mapped per CPU region, so it's common that | ||
| 365 | // this area is already marked as cached. | ||
| 366 | break; | ||
| 350 | default: | 367 | default: |
| 351 | UNREACHABLE(); | 368 | UNREACHABLE(); |
| 352 | } | 369 | } |
| @@ -357,6 +374,10 @@ void RasterizerMarkRegionCached(VAddr start, u64 size, bool cached) { | |||
| 357 | // It is not necessary for a process to have this region mapped into its address | 374 | // It is not necessary for a process to have this region mapped into its address |
| 358 | // space, for example, a system module need not have a VRAM mapping. | 375 | // space, for example, a system module need not have a VRAM mapping. |
| 359 | break; | 376 | break; |
| 377 | case PageType::Memory: | ||
| 378 | // There can be more than one GPU region mapped per CPU region, so it's common that | ||
| 379 | // this area is already unmarked as cached. | ||
| 380 | break; | ||
| 360 | case PageType::RasterizerCachedMemory: { | 381 | case PageType::RasterizerCachedMemory: { |
| 361 | u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); | 382 | u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); |
| 362 | if (pointer == nullptr) { | 383 | if (pointer == nullptr) { |
| @@ -394,19 +415,29 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { | |||
| 394 | 415 | ||
| 395 | VAddr overlap_start = std::max(start, region_start); | 416 | VAddr overlap_start = std::max(start, region_start); |
| 396 | VAddr overlap_end = std::min(end, region_end); | 417 | VAddr overlap_end = std::min(end, region_end); |
| 418 | |||
| 419 | std::vector<Tegra::GPUVAddr> gpu_addresses = | ||
| 420 | Core::System::GetInstance().GPU().memory_manager->CpuToGpuAddress(overlap_start); | ||
| 421 | |||
| 422 | if (gpu_addresses.empty()) { | ||
| 423 | return; | ||
| 424 | } | ||
| 425 | |||
| 397 | u64 overlap_size = overlap_end - overlap_start; | 426 | u64 overlap_size = overlap_end - overlap_start; |
| 398 | 427 | ||
| 399 | auto* rasterizer = VideoCore::g_renderer->Rasterizer(); | 428 | for (const auto& gpu_address : gpu_addresses) { |
| 400 | switch (mode) { | 429 | auto* rasterizer = VideoCore::g_renderer->Rasterizer(); |
| 401 | case FlushMode::Flush: | 430 | switch (mode) { |
| 402 | rasterizer->FlushRegion(overlap_start, overlap_size); | 431 | case FlushMode::Flush: |
| 403 | break; | 432 | rasterizer->FlushRegion(gpu_address, overlap_size); |
| 404 | case FlushMode::Invalidate: | 433 | break; |
| 405 | rasterizer->InvalidateRegion(overlap_start, overlap_size); | 434 | case FlushMode::Invalidate: |
| 406 | break; | 435 | rasterizer->InvalidateRegion(gpu_address, overlap_size); |
| 407 | case FlushMode::FlushAndInvalidate: | 436 | break; |
| 408 | rasterizer->FlushAndInvalidateRegion(overlap_start, overlap_size); | 437 | case FlushMode::FlushAndInvalidate: |
| 409 | break; | 438 | rasterizer->FlushAndInvalidateRegion(gpu_address, overlap_size); |
| 439 | break; | ||
| 440 | } | ||
| 410 | } | 441 | } |
| 411 | }; | 442 | }; |
| 412 | 443 | ||
| @@ -445,8 +476,9 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_ | |||
| 445 | 476 | ||
| 446 | switch (page_table.attributes[page_index]) { | 477 | switch (page_table.attributes[page_index]) { |
| 447 | case PageType::Unmapped: { | 478 | case PageType::Unmapped: { |
| 448 | LOG_ERROR(HW_Memory, "unmapped ReadBlock @ 0x%08X (start address = 0x%08X, size = %zu)", | 479 | NGLOG_ERROR(HW_Memory, |
| 449 | current_vaddr, src_addr, size); | 480 | "Unmapped ReadBlock @ {:#018X} (start address = {:#018X}, size = {})", |
| 481 | current_vaddr, src_addr, size); | ||
| 450 | std::memset(dest_buffer, 0, copy_amount); | 482 | std::memset(dest_buffer, 0, copy_amount); |
| 451 | break; | 483 | break; |
| 452 | } | 484 | } |
| @@ -508,9 +540,9 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi | |||
| 508 | 540 | ||
| 509 | switch (page_table.attributes[page_index]) { | 541 | switch (page_table.attributes[page_index]) { |
| 510 | case PageType::Unmapped: { | 542 | case PageType::Unmapped: { |
| 511 | LOG_ERROR(HW_Memory, | 543 | NGLOG_ERROR(HW_Memory, |
| 512 | "unmapped WriteBlock @ 0x%08X (start address = 0x%08X, size = %zu)", | 544 | "Unmapped WriteBlock @ {:#018X} (start address = {:#018X}, size = {})", |
| 513 | current_vaddr, dest_addr, size); | 545 | current_vaddr, dest_addr, size); |
| 514 | break; | 546 | break; |
| 515 | } | 547 | } |
| 516 | case PageType::Memory: { | 548 | case PageType::Memory: { |
| @@ -556,8 +588,9 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const size | |||
| 556 | 588 | ||
| 557 | switch (page_table.attributes[page_index]) { | 589 | switch (page_table.attributes[page_index]) { |
| 558 | case PageType::Unmapped: { | 590 | case PageType::Unmapped: { |
| 559 | LOG_ERROR(HW_Memory, "unmapped ZeroBlock @ 0x%08X (start address = 0x%08X, size = %zu)", | 591 | NGLOG_ERROR(HW_Memory, |
| 560 | current_vaddr, dest_addr, size); | 592 | "Unmapped ZeroBlock @ {:#018X} (start address = {#:018X}, size = {})", |
| 593 | current_vaddr, dest_addr, size); | ||
| 561 | break; | 594 | break; |
| 562 | } | 595 | } |
| 563 | case PageType::Memory: { | 596 | case PageType::Memory: { |
| @@ -596,8 +629,9 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | |||
| 596 | 629 | ||
| 597 | switch (page_table.attributes[page_index]) { | 630 | switch (page_table.attributes[page_index]) { |
| 598 | case PageType::Unmapped: { | 631 | case PageType::Unmapped: { |
| 599 | LOG_ERROR(HW_Memory, "unmapped CopyBlock @ 0x%08X (start address = 0x%08X, size = %zu)", | 632 | NGLOG_ERROR(HW_Memory, |
| 600 | current_vaddr, src_addr, size); | 633 | "Unmapped CopyBlock @ {:#018X} (start address = {:#018X}, size = {})", |
| 634 | current_vaddr, src_addr, size); | ||
| 601 | ZeroBlock(process, dest_addr, copy_amount); | 635 | ZeroBlock(process, dest_addr, copy_amount); |
| 602 | break; | 636 | break; |
| 603 | } | 637 | } |
| @@ -625,6 +659,10 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | |||
| 625 | } | 659 | } |
| 626 | } | 660 | } |
| 627 | 661 | ||
| 662 | void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size) { | ||
| 663 | CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size); | ||
| 664 | } | ||
| 665 | |||
| 628 | boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { | 666 | boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { |
| 629 | if (addr == 0) { | 667 | if (addr == 0) { |
| 630 | return 0; | 668 | return 0; |
| @@ -646,7 +684,7 @@ boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { | |||
| 646 | PAddr VirtualToPhysicalAddress(const VAddr addr) { | 684 | PAddr VirtualToPhysicalAddress(const VAddr addr) { |
| 647 | auto paddr = TryVirtualToPhysicalAddress(addr); | 685 | auto paddr = TryVirtualToPhysicalAddress(addr); |
| 648 | if (!paddr) { | 686 | if (!paddr) { |
| 649 | LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%016" PRIX64, addr); | 687 | NGLOG_ERROR(HW_Memory, "Unknown virtual address @ {:#018X}", addr); |
| 650 | // To help with debugging, set bit on address so that it's obviously invalid. | 688 | // To help with debugging, set bit on address so that it's obviously invalid. |
| 651 | return addr | 0x80000000; | 689 | return addr | 0x80000000; |
| 652 | } | 690 | } |