diff options
Diffstat (limited to 'src/core/memory.cpp')
| -rw-r--r-- | src/core/memory.cpp | 160 |
1 files changed, 113 insertions, 47 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 68a6b1ac2..7f58be6de 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -9,6 +9,8 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/swap.h" +#include "core/arm/arm_interface.h" +#include "core/core.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/process.h" #include "core/hle/lock.h" @@ -22,10 +24,17 @@ namespace Memory { static std::array<u8, Memory::VRAM_SIZE> vram; static std::array<u8, Memory::N3DS_EXTRA_RAM_SIZE> n3ds_extra_ram; -PageTable* current_page_table = nullptr; +static PageTable* current_page_table = nullptr; -std::array<u8*, PAGE_TABLE_NUM_ENTRIES>* GetCurrentPageTablePointers() { - return ¤t_page_table->pointers; +void SetCurrentPageTable(PageTable* page_table) { + current_page_table = page_table; + if (Core::System::GetInstance().IsPoweredOn()) { + Core::CPU().PageTableChanged(); + } +} + +PageTable* GetCurrentPageTable() { + return current_page_table; } static void MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type) { @@ -73,10 +82,10 @@ void UnmapRegion(PageTable& page_table, VAddr base, u32 size) { * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) * using a VMA from the current process */ -static u8* GetPointerFromVMA(VAddr vaddr) { +static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { u8* direct_pointer = nullptr; - auto& vm_manager = Kernel::g_current_process->vm_manager; + auto& vm_manager = process.vm_manager; auto it = vm_manager.FindVMA(vaddr); ASSERT(it != vm_manager.vma_map.end()); @@ -99,10 +108,18 @@ static u8* GetPointerFromVMA(VAddr vaddr) { } /** + * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) + * using a VMA from the current process. + */ +static u8* GetPointerFromVMA(VAddr vaddr) { + return GetPointerFromVMA(*Kernel::g_current_process, vaddr); +} + +/** * This function should only be called for virtual addreses with attribute `PageType::Special`. */ -static MMIORegionPointer GetMMIOHandler(VAddr vaddr) { - for (const auto& region : current_page_table->special_regions) { +static MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr) { + for (const auto& region : page_table.special_regions) { if (vaddr >= region.base && vaddr < (region.base + region.size)) { return region.handler; } @@ -111,6 +128,11 @@ static MMIORegionPointer GetMMIOHandler(VAddr vaddr) { return nullptr; // Should never happen } +static MMIORegionPointer GetMMIOHandler(VAddr vaddr) { + const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; + return GetMMIOHandler(page_table, vaddr); +} + template <typename T> T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr); @@ -195,18 +217,20 @@ void Write(const VAddr vaddr, const T data) { } } -bool IsValidVirtualAddress(const VAddr vaddr) { - const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; +bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { + auto& page_table = process.vm_manager.page_table; + + const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; if (page_pointer) return true; - if (current_page_table->attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) + if (page_table.attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) return true; - if (current_page_table->attributes[vaddr >> PAGE_BITS] != PageType::Special) + if (page_table.attributes[vaddr >> PAGE_BITS] != PageType::Special) return false; - MMIORegionPointer mmio_region = GetMMIOHandler(vaddr); + MMIORegionPointer mmio_region = GetMMIOHandler(page_table, vaddr); if (mmio_region) { return mmio_region->IsValidAddress(vaddr); } @@ -214,6 +238,10 @@ bool IsValidVirtualAddress(const VAddr vaddr) { return false; } +bool IsValidVirtualAddress(const VAddr vaddr) { + return IsValidVirtualAddress(*Kernel::g_current_process, vaddr); +} + bool IsValidPhysicalAddress(const PAddr paddr) { return GetPhysicalPointer(paddr) != nullptr; } @@ -316,8 +344,15 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) { boost::optional<VAddr> maybe_vaddr = PhysicalToVirtualAddress(paddr); - if (!maybe_vaddr) + // While the physical <-> virtual mapping is 1:1 for the regions supported by the cache, + // some games (like Pokemon Super Mystery Dungeon) will try to use textures that go beyond + // the end address of VRAM, causing the Virtual->Physical translation to fail when flushing + // parts of the texture. + if (!maybe_vaddr) { + LOG_ERROR(HW_Memory, + "Trying to flush a cached region to an invalid physical address %08X", paddr); continue; + } VAddr vaddr = *maybe_vaddr; u8& res_count = current_page_table->cached_res_count[vaddr >> PAGE_BITS]; @@ -329,6 +364,10 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { if (res_count == 0) { PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; switch (page_type) { + case PageType::Unmapped: + // It is not necessary for a process to have this region mapped into its address + // space, for example, a system module need not have a VRAM mapping. + break; case PageType::Memory: page_type = PageType::RasterizerCachedMemory; current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; @@ -347,6 +386,10 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) { if (res_count == 0) { PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; switch (page_type) { + case PageType::Unmapped: + // It is not necessary for a process to have this region mapped into its address + // space, for example, a system module need not have a VRAM mapping. + break; case PageType::RasterizerCachedMemory: { u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); if (pointer == nullptr) { @@ -435,16 +478,19 @@ u64 Read64(const VAddr addr) { return Read<u64_le>(addr); } -void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { +void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, + const size_t size) { + auto& page_table = process.vm_manager.page_table; + size_t remaining_size = size; size_t page_index = src_addr >> PAGE_BITS; size_t page_offset = src_addr & PAGE_MASK; while (remaining_size > 0) { const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); - const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset; + const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); - switch (current_page_table->attributes[page_index]) { + switch (page_table.attributes[page_index]) { case PageType::Unmapped: { LOG_ERROR(HW_Memory, "unmapped ReadBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, src_addr, size); @@ -452,27 +498,30 @@ void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { break; } case PageType::Memory: { - DEBUG_ASSERT(current_page_table->pointers[page_index]); + DEBUG_ASSERT(page_table.pointers[page_index]); - const u8* src_ptr = current_page_table->pointers[page_index] + page_offset; + const u8* src_ptr = page_table.pointers[page_index] + page_offset; std::memcpy(dest_buffer, src_ptr, copy_amount); break; } case PageType::Special: { - DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); - - GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); + MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); + DEBUG_ASSERT(handler); + handler->ReadBlock(current_vaddr, dest_buffer, copy_amount); break; } case PageType::RasterizerCachedMemory: { - RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); - std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount); + RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), + FlushMode::Flush); + std::memcpy(dest_buffer, GetPointerFromVMA(process, current_vaddr), copy_amount); break; } case PageType::RasterizerCachedSpecial: { - DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); - RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); - GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); + MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); + DEBUG_ASSERT(handler); + RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), + FlushMode::Flush); + handler->ReadBlock(current_vaddr, dest_buffer, copy_amount); break; } default: @@ -486,6 +535,10 @@ void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { } } +void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { + ReadBlock(*Kernel::g_current_process, src_addr, dest_buffer, size); +} + void Write8(const VAddr addr, const u8 data) { Write<u8>(addr, data); } @@ -502,16 +555,18 @@ void Write64(const VAddr addr, const u64 data) { Write<u64_le>(addr, data); } -void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) { +void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, + const size_t size) { + auto& page_table = process.vm_manager.page_table; size_t remaining_size = size; size_t page_index = dest_addr >> PAGE_BITS; size_t page_offset = dest_addr & PAGE_MASK; while (remaining_size > 0) { const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); - const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset; + const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); - switch (current_page_table->attributes[page_index]) { + switch (page_table.attributes[page_index]) { case PageType::Unmapped: { LOG_ERROR(HW_Memory, "unmapped WriteBlock @ 0x%08X (start address = 0x%08X, size = %zu)", @@ -519,27 +574,30 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size break; } case PageType::Memory: { - DEBUG_ASSERT(current_page_table->pointers[page_index]); + DEBUG_ASSERT(page_table.pointers[page_index]); - u8* dest_ptr = current_page_table->pointers[page_index] + page_offset; + u8* dest_ptr = page_table.pointers[page_index] + page_offset; std::memcpy(dest_ptr, src_buffer, copy_amount); break; } case PageType::Special: { - DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); - - GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); + MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); + DEBUG_ASSERT(handler); + handler->WriteBlock(current_vaddr, src_buffer, copy_amount); break; } case PageType::RasterizerCachedMemory: { - RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); - std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount); + RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), + FlushMode::FlushAndInvalidate); + std::memcpy(GetPointerFromVMA(process, current_vaddr), src_buffer, copy_amount); break; } case PageType::RasterizerCachedSpecial: { - DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); - RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); - GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); + MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); + DEBUG_ASSERT(handler); + RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), + FlushMode::FlushAndInvalidate); + handler->WriteBlock(current_vaddr, src_buffer, copy_amount); break; } default: @@ -553,6 +611,10 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size } } +void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) { + WriteBlock(*Kernel::g_current_process, dest_addr, src_buffer, size); +} + void ZeroBlock(const VAddr dest_addr, const size_t size) { size_t remaining_size = size; size_t page_index = dest_addr >> PAGE_BITS; @@ -562,7 +624,7 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) { while (remaining_size > 0) { const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); - const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset; + const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); switch (current_page_table->attributes[page_index]) { case PageType::Unmapped: { @@ -584,13 +646,15 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) { break; } case PageType::RasterizerCachedMemory: { - RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); + RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), + FlushMode::FlushAndInvalidate); std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount); break; } case PageType::RasterizerCachedSpecial: { DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); - RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::FlushAndInvalidate); + RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), + FlushMode::FlushAndInvalidate); GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount); break; } @@ -611,7 +675,7 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { while (remaining_size > 0) { const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); - const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset; + const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); switch (current_page_table->attributes[page_index]) { case PageType::Unmapped: { @@ -635,13 +699,15 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { break; } case PageType::RasterizerCachedMemory: { - RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); + RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), + FlushMode::Flush); WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount); break; } case PageType::RasterizerCachedSpecial: { DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); - RasterizerFlushVirtualRegion(current_vaddr, copy_amount, FlushMode::Flush); + RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), + FlushMode::Flush); std::vector<u8> buffer(copy_amount); GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size()); @@ -654,8 +720,8 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { page_index++; page_offset = 0; - dest_addr += copy_amount; - src_addr += copy_amount; + dest_addr += static_cast<VAddr>(copy_amount); + src_addr += static_cast<VAddr>(copy_amount); remaining_size -= copy_amount; } } |
