From 3b3c60dc4cf8d2fa158accc2c401007439991224 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 7 May 2022 14:21:30 +0200 Subject: [PATCH] PowerPC: Check page crossing for non-translated reads This fixes a problem where Dolphin could crash if a non-translated read crossed the end of a physical memory region. The same change was applied to WriteToHardware in ecbce0a. --- Source/Core/Core/PowerPC/MMU.cpp | 40 +++++++++++--------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index 869a7a8648..aac5f35054 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -173,6 +173,20 @@ static void GenerateDSIException(u32 effective_address, bool write); template static T ReadFromHardware(u32 em_address) { + const u32 em_address_start_page = em_address & ~(HW_PAGE_SIZE - 1); + const u32 em_address_end_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1); + if (em_address_start_page != em_address_end_page) + { + // This could be unaligned down to the byte level... hopefully this is rare, so doing it this + // way isn't too terrible. + // TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions. + // Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned! + u64 var = 0; + for (u32 i = 0; i < sizeof(T); ++i) + var = (var << 8) | ReadFromHardware(em_address + i); + return static_cast(var); + } + if (!never_translate && MSR.DR) { auto translated_addr = TranslateAddress(em_address); @@ -182,35 +196,9 @@ static T ReadFromHardware(u32 em_address) GenerateDSIException(em_address, false); return 0; } - if ((em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T)) - { - // This could be unaligned down to the byte level... hopefully this is rare, so doing it this - // way isn't too terrible. - // TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions. - // Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned! - u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1); - auto addr_next_page = TranslateAddress(em_address_next_page); - if (!addr_next_page.Success()) - { - if (flag == XCheckTLBFlag::Read) - GenerateDSIException(em_address_next_page, false); - return 0; - } - T var = 0; - u32 addr_translated = translated_addr.address; - for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, addr_translated++) - { - if (addr == em_address_next_page) - addr_translated = addr_next_page.address; - var = (var << 8) | ReadFromHardware(addr_translated); - } - return var; - } em_address = translated_addr.address; } - // TODO: Make sure these are safe for unaligned addresses. - if (Memory::m_pRAM && (em_address & 0xF8000000) == 0x00000000) { // Handle RAM; the masking intentionally discards bits (essentially creating