summaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp128
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
277bool IsValidPhysicalAddress(const PAddr paddr) { 268bool 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
281u8* GetPointer(const VAddr vaddr) { 273u8* GetPointer(const VAddr vaddr) {
@@ -308,7 +300,8 @@ std::string ReadCString(VAddr vaddr, std::size_t max_length) {
308 300
309u8* GetPhysicalPointer(PAddr address) { 301u8* 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
314void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { 307void 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
381void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) { 377void 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
385void 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
387u8 Read8(const VAddr addr) { 420u8 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
683PAddr VirtualToPhysicalAddress(const VAddr addr) { 701boost::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
721PAddr 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
705VAddr PhysicalToVirtualAddress(const PAddr addr) { 731boost::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