diff --git a/src/core/achievements.cpp b/src/core/achievements.cpp index d4a184b9c..f3db8942b 100644 --- a/src/core/achievements.cpp +++ b/src/core/achievements.cpp @@ -3009,7 +3009,7 @@ unsigned int Achievements::RAIntegration::RACallbackReadMemoryBlock(unsigned int return 0; const u32 copy_size = std::min(Bus::g_ram_size - nAddress, nBytes); - std::memcpy(pBuffer, Bus::g_ram + nAddress, copy_size); + std::memcpy(pBuffer, Bus::g_unprotected_ram + nAddress, copy_size); return copy_size; } diff --git a/src/core/bus.cpp b/src/core/bus.cpp index ea89220cb..5ecefec9b 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -37,6 +37,7 @@ Log_SetChannel(Bus); // TODO: Get rid of page code bits, instead use page faults to track SMC. // Exports for external debugger access +#ifndef __ANDROID__ namespace Exports { extern "C" { @@ -50,6 +51,7 @@ __attribute__((visibility("default"), used)) u32 RAM_SIZE, RAM_MASK; } } // namespace Exports +#endif namespace Bus { @@ -105,6 +107,7 @@ static void* s_shmem_handle = nullptr; std::bitset g_ram_code_bits{}; u8* g_ram = nullptr; +u8* g_unprotected_ram = nullptr; u32 g_ram_size = 0; u32 g_ram_mask = 0; u8* g_bios = nullptr; @@ -132,16 +135,13 @@ static std::vector> s_fastmem_ram_views; #endif static u8** s_fastmem_lut = nullptr; -static constexpr const std::array s_fastmem_ram_mirrors = {0x00000000u, 0x00200000u, 0x00400000u, 0x00600000u, - 0x80000000u, 0x80200000u, 0x80400000u, 0x80600000u, - 0xA0000000u, 0xA0200000u, 0xA0400000u, 0xA0600000u}; static void SetRAMSize(bool enable_8mb_ram); static std::tuple CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay); static void RecalculateMemoryTimings(); -static void SetCodePageFastmemProtection(u32 page_index, bool writable); +static void SetRAMPageWritable(u32 page_index, bool writable); static void SetHandlers(); @@ -182,7 +182,9 @@ bool Bus::AllocateMemory() g_ram = static_cast(MemMap::MapSharedMemory(s_shmem_handle, MemoryMap::RAM_OFFSET, nullptr, MemoryMap::RAM_SIZE, PageProtect::ReadWrite)); - if (!g_ram) + g_unprotected_ram = static_cast(MemMap::MapSharedMemory(s_shmem_handle, MemoryMap::RAM_OFFSET, nullptr, + MemoryMap::RAM_SIZE, PageProtect::ReadWrite)); + if (!g_ram || !g_unprotected_ram) { Host::ReportErrorAsync("Error", "Failed to map memory for RAM"); ReleaseMemory(); @@ -227,11 +229,21 @@ bool Bus::AllocateMemory() Log_InfoPrintf("Fastmem base: %p", s_fastmem_arena.BasePointer()); #endif +#ifndef __ANDROID__ + Exports::RAM = reinterpret_cast(g_unprotected_ram); +#endif + return true; } void Bus::ReleaseMemory() { +#ifndef __ANDROID__ + Exports::RAM = 0; + Exports::RAM_SIZE = 0; + Exports::RAM_MASK = 0; +#endif + #ifdef ENABLE_MMAP_FASTMEM DebugAssert(s_fastmem_ram_views.empty()); s_fastmem_arena.Destroy(); @@ -253,6 +265,12 @@ void Bus::ReleaseMemory() g_bios = nullptr; } + if (g_unprotected_ram) + { + MemMap::UnmapSharedMemory(g_unprotected_ram, MemoryMap::RAM_SIZE); + g_unprotected_ram = nullptr; + } + if (g_ram) { MemMap::UnmapSharedMemory(g_ram, MemoryMap::RAM_SIZE); @@ -278,9 +296,10 @@ void Bus::SetRAMSize(bool enable_8mb_ram) g_ram_size = enable_8mb_ram ? RAM_8MB_SIZE : RAM_2MB_SIZE; g_ram_mask = enable_8mb_ram ? RAM_8MB_MASK : RAM_2MB_MASK; - Exports::RAM = reinterpret_cast(g_ram); +#ifndef __ANDROID__ Exports::RAM_SIZE = g_ram_size; Exports::RAM_MASK = g_ram_mask; +#endif } void Bus::Shutdown() @@ -291,9 +310,11 @@ void Bus::Shutdown() g_ram_mask = 0; g_ram_size = 0; +#ifndef __ANDROID__ Exports::RAM = 0; Exports::RAM_SIZE = 0; Exports::RAM_MASK = 0; +#endif } void Bus::Reset() @@ -509,13 +530,13 @@ void Bus::UpdateFastmemViews(CPUFastmemMode mode) if (!s_fastmem_lut) { - s_fastmem_lut = static_cast(std::malloc(sizeof(u8*) * FASTMEM_LUT_NUM_SLOTS)); + s_fastmem_lut = static_cast(std::malloc(sizeof(u8*) * FASTMEM_LUT_SIZE)); Assert(s_fastmem_lut); Log_InfoPrintf("Fastmem base (software): %p", s_fastmem_lut); } - std::memset(s_fastmem_lut, 0, sizeof(u8*) * FASTMEM_LUT_NUM_SLOTS); + std::memset(s_fastmem_lut, 0, sizeof(u8*) * FASTMEM_LUT_SIZE); auto MapRAM = [](u32 base_address) { u8* ram_ptr = g_ram + (base_address & g_ram_mask); @@ -523,8 +544,6 @@ void Bus::UpdateFastmemViews(CPUFastmemMode mode) { const u32 lut_index = (base_address + address) >> FASTMEM_LUT_PAGE_SHIFT; s_fastmem_lut[lut_index] = ram_ptr; - s_fastmem_lut[FASTMEM_LUT_NUM_PAGES + lut_index] = - g_ram_code_bits[address >> HOST_PAGE_SHIFT] ? nullptr : ram_ptr; ram_ptr += FASTMEM_LUT_PAGE_SIZE; } }; @@ -584,7 +603,7 @@ void Bus::SetRAMCodePage(u32 index) // protect fastmem pages g_ram_code_bits[index] = true; - SetCodePageFastmemProtection(index, false); + SetRAMPageWritable(index, false); } void Bus::ClearRAMCodePage(u32 index) @@ -594,11 +613,19 @@ void Bus::ClearRAMCodePage(u32 index) // unprotect fastmem pages g_ram_code_bits[index] = false; - SetCodePageFastmemProtection(index, true); + SetRAMPageWritable(index, true); } -void Bus::SetCodePageFastmemProtection(u32 page_index, bool writable) +void Bus::SetRAMPageWritable(u32 page_index, bool writable) { + if (!MemMap::MemProtect(&g_ram[page_index * HOST_PAGE_SIZE], HOST_PAGE_SIZE, + writable ? PageProtect::ReadWrite : PageProtect::ReadOnly)) [[unlikely]] + { + Log_ErrorFmt("Failed to set RAM host page {} ({}) to {}", page_index, + reinterpret_cast(&g_ram[page_index * HOST_PAGE_SIZE]), + writable ? "read-write" : "read-only"); + } + #ifdef ENABLE_MMAP_FASTMEM if (s_fastmem_mode == CPUFastmemMode::MMap) { @@ -608,7 +635,7 @@ void Bus::SetCodePageFastmemProtection(u32 page_index, bool writable) for (const auto& it : s_fastmem_ram_views) { u8* page_address = it.first + (page_index * HOST_PAGE_SIZE); - if (!MemMap::MemProtect(page_address, HOST_PAGE_SIZE, protect)) + if (!MemMap::MemProtect(page_address, HOST_PAGE_SIZE, protect)) [[unlikely]] { Log_ErrorPrintf("Failed to %s code page %u (0x%08X) @ %p", writable ? "unprotect" : "protect", page_index, page_index * static_cast(HOST_PAGE_SIZE), page_address); @@ -618,30 +645,15 @@ void Bus::SetCodePageFastmemProtection(u32 page_index, bool writable) return; } #endif - - if (s_fastmem_mode == CPUFastmemMode::LUT) - { - // mirrors... - const u32 code_addr = page_index << HOST_PAGE_SHIFT; - for (u32 mirror_start : s_fastmem_ram_mirrors) - { - u32 lut_addr = mirror_start + code_addr; - u32 ram_offset = (lut_addr & g_ram_mask); - for (u32 j = 0; j < FASTMEM_LUT_PAGES_PER_CODE_PAGE; j++) - { - s_fastmem_lut[FASTMEM_LUT_NUM_PAGES + (lut_addr >> FASTMEM_LUT_PAGE_SHIFT)] = - writable ? &g_ram[ram_offset] : nullptr; - lut_addr += FASTMEM_LUT_PAGE_SIZE; - ram_offset += FASTMEM_LUT_PAGE_SIZE; - } - } - } } void Bus::ClearRAMCodePageFlags() { g_ram_code_bits.reset(); + if (!MemMap::MemProtect(g_ram, RAM_8MB_SIZE, PageProtect::ReadWrite)) + Log_ErrorPrint("Failed to restore RAM protection to read-write."); + #ifdef ENABLE_MMAP_FASTMEM if (s_fastmem_mode == CPUFastmemMode::MMap) { @@ -655,21 +667,6 @@ void Bus::ClearRAMCodePageFlags() } } #endif - - if (s_fastmem_mode == CPUFastmemMode::LUT) - { - for (u32 i = 0; i < static_cast(g_ram_code_bits.size()); i++) - { - u32 lut_addr = (i * HOST_PAGE_SIZE); - u32 ram_offset = (lut_addr & g_ram_mask); - for (u32 j = 0; j < FASTMEM_LUT_PAGES_PER_CODE_PAGE; j++) - { - s_fastmem_lut[FASTMEM_LUT_NUM_PAGES + (lut_addr >> FASTMEM_LUT_PAGE_SHIFT)] = &g_ram[ram_offset]; - lut_addr += FASTMEM_LUT_PAGE_SIZE; - ram_offset += FASTMEM_LUT_PAGE_SIZE; - } - } - } } bool Bus::IsCodePageAddress(PhysicalMemoryAddress address) @@ -740,16 +737,16 @@ u8* Bus::GetMemoryRegionPointer(MemoryRegion region) switch (region) { case MemoryRegion::RAM: - return g_ram; + return g_unprotected_ram; case MemoryRegion::RAMMirror1: - return (g_ram + (RAM_2MB_SIZE & g_ram_mask)); + return (g_unprotected_ram + (RAM_2MB_SIZE & g_ram_mask)); case MemoryRegion::RAMMirror2: - return (g_ram + ((RAM_2MB_SIZE * 2) & g_ram_mask)); + return (g_unprotected_ram + ((RAM_2MB_SIZE * 2) & g_ram_mask)); case MemoryRegion::RAMMirror3: - return (g_ram + ((RAM_8MB_SIZE * 3) & g_ram_mask)); + return (g_unprotected_ram + ((RAM_8MB_SIZE * 3) & g_ram_mask)); case MemoryRegion::EXP1: return nullptr; @@ -932,9 +929,6 @@ template void Bus::RAMWriteHandler(VirtualMemoryAddress address, u32 value) { const u32 offset = address & g_ram_mask; - const u32 page_index = offset / HOST_PAGE_SIZE; - if (g_ram_code_bits[page_index]) - CPU::CodeCache::InvalidateBlocksWithPageIndex(page_index); if constexpr (size == MemoryAccessSize::Byte) { diff --git a/src/core/bus.h b/src/core/bus.h index 59a8c06ae..ee609f4c6 100644 --- a/src/core/bus.h +++ b/src/core/bus.h @@ -96,10 +96,7 @@ enum : u32 FASTMEM_LUT_PAGE_SIZE = 4096, FASTMEM_LUT_PAGE_MASK = FASTMEM_LUT_PAGE_SIZE - 1, FASTMEM_LUT_PAGE_SHIFT = 12, - FASTMEM_LUT_PAGES_PER_CODE_PAGE = HOST_PAGE_SIZE / FASTMEM_LUT_PAGE_SIZE, - - FASTMEM_LUT_NUM_PAGES = 0x100000, // 0x100000000 >> 12 - FASTMEM_LUT_NUM_SLOTS = FASTMEM_LUT_NUM_PAGES * 2, + FASTMEM_LUT_SIZE = 0x100000, // 0x100000000 >> 12 }; #ifdef ENABLE_MMAP_FASTMEM @@ -135,10 +132,11 @@ bool CanUseFastmemForAddress(VirtualMemoryAddress address); void SetExpansionROM(std::vector data); extern std::bitset g_ram_code_bits; -extern u8* g_ram; // 2MB-8MB RAM -extern u32 g_ram_size; // Active size of RAM. -extern u32 g_ram_mask; // Active address bits for RAM. -extern u8* g_bios; // 512K BIOS ROM +extern u8* g_ram; // 2MB-8MB RAM +extern u8* g_unprotected_ram; // RAM without page protection, use for debugger access. +extern u32 g_ram_size; // Active size of RAM. +extern u32 g_ram_mask; // Active address bits for RAM. +extern u8* g_bios; // 512K BIOS ROM extern std::array g_exp1_access_time; extern std::array g_exp2_access_time; extern std::array g_bios_access_time; diff --git a/src/core/cpu_code_cache.cpp b/src/core/cpu_code_cache.cpp index 45ba18bc7..3edef3860 100644 --- a/src/core/cpu_code_cache.cpp +++ b/src/core/cpu_code_cache.cpp @@ -672,7 +672,19 @@ void CPU::CodeCache::ClearBlocks() Common::PageFaultHandler::HandlerResult CPU::CodeCache::ExceptionHandler(void* exception_pc, void* fault_address, bool is_write) { - // TODO: Catch general RAM writes, not just fastmem + if (static_cast(fault_address) >= Bus::g_ram && + static_cast(fault_address) < (Bus::g_ram + Bus::RAM_8MB_SIZE)) + { + // Writing to protected RAM. + DebugAssert(is_write); + const u32 guest_address = static_cast(static_cast(fault_address) - Bus::g_ram); + const u32 page_index = Bus::GetRAMCodePageIndex(guest_address); + Log_DevFmt("Page fault on protected RAM @ 0x{:08X} (page #{}), invalidating code cache.", guest_address, + page_index); + InvalidateBlocksWithPageIndex(page_index); + return Common::PageFaultHandler::HandlerResult::ContinueExecution; + } + #ifdef ENABLE_RECOMPILER_SUPPORT return HandleFastmemException(exception_pc, fault_address, is_write); #else diff --git a/src/core/cpu_code_cache.h b/src/core/cpu_code_cache.h index 126243afa..ee6edf9e5 100644 --- a/src/core/cpu_code_cache.h +++ b/src/core/cpu_code_cache.h @@ -38,16 +38,4 @@ void InvalidateBlocksWithPageIndex(u32 page_index); /// Invalidates all blocks in the cache. void InvalidateAllRAMBlocks(); -/// Invalidates any code pages which overlap the specified range. -ALWAYS_INLINE void InvalidateCodePages(PhysicalMemoryAddress address, u32 word_count) -{ - const u32 start_page = address / HOST_PAGE_SIZE; - const u32 end_page = (address + word_count * sizeof(u32) - sizeof(u32)) / HOST_PAGE_SIZE; - for (u32 page = start_page; page <= end_page; page++) - { - if (Bus::g_ram_code_bits[page]) - CPU::CodeCache::InvalidateBlocksWithPageIndex(page); - } -} - } // namespace CPU::CodeCache diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index 0ef3f48f2..8eacdf163 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -2740,17 +2740,17 @@ ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& va { if constexpr (size == MemoryAccessSize::Byte) { - value = g_ram[offset]; + value = g_unprotected_ram[offset]; } else if constexpr (size == MemoryAccessSize::HalfWord) { u16 temp; - std::memcpy(&temp, &g_ram[offset], sizeof(temp)); + std::memcpy(&temp, &g_unprotected_ram[offset], sizeof(temp)); value = ZeroExtend32(temp); } else if constexpr (size == MemoryAccessSize::Word) { - std::memcpy(&value, &g_ram[offset], sizeof(u32)); + std::memcpy(&value, &g_unprotected_ram[offset], sizeof(u32)); } } else @@ -2759,9 +2759,9 @@ ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& va if constexpr (size == MemoryAccessSize::Byte) { - if (g_ram[offset] != Truncate8(value)) + if (g_unprotected_ram[offset] != Truncate8(value)) { - g_ram[offset] = Truncate8(value); + g_unprotected_ram[offset] = Truncate8(value); if (g_ram_code_bits[page_index]) CPU::CodeCache::InvalidateBlocksWithPageIndex(page_index); } @@ -2770,10 +2770,10 @@ ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& va { const u16 new_value = Truncate16(value); u16 old_value; - std::memcpy(&old_value, &g_ram[offset], sizeof(old_value)); + std::memcpy(&old_value, &g_unprotected_ram[offset], sizeof(old_value)); if (old_value != new_value) { - std::memcpy(&g_ram[offset], &new_value, sizeof(u16)); + std::memcpy(&g_unprotected_ram[offset], &new_value, sizeof(u16)); if (g_ram_code_bits[page_index]) CPU::CodeCache::InvalidateBlocksWithPageIndex(page_index); } @@ -2781,10 +2781,10 @@ ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& va else if constexpr (size == MemoryAccessSize::Word) { u32 old_value; - std::memcpy(&old_value, &g_ram[offset], sizeof(u32)); + std::memcpy(&old_value, &g_unprotected_ram[offset], sizeof(u32)); if (old_value != value) { - std::memcpy(&g_ram[offset], &value, sizeof(u32)); + std::memcpy(&g_unprotected_ram[offset], &value, sizeof(u32)); if (g_ram_code_bits[page_index]) CPU::CodeCache::InvalidateBlocksWithPageIndex(page_index); } @@ -2955,11 +2955,8 @@ void* CPU::GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAcces const PhysicalMemoryAddress paddr = address & PHYSICAL_MEMORY_ADDRESS_MASK; -#if 0 - // Not enabled until we can protect code regions. if (paddr < RAM_MIRROR_END) - return &g_ram[paddr & RAM_MASK]; -#endif + return &g_ram[paddr & g_ram_mask]; if ((paddr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION) return &g_state.dcache[paddr & DCACHE_OFFSET_MASK]; diff --git a/src/core/cpu_recompiler_code_generator.h b/src/core/cpu_recompiler_code_generator.h index 096c64dde..e8d11da8b 100644 --- a/src/core/cpu_recompiler_code_generator.h +++ b/src/core/cpu_recompiler_code_generator.h @@ -109,8 +109,6 @@ public: void EmitLoadGlobalAddress(HostReg host_reg, const void* ptr); // Automatically generates an exception handler. - Value GetFastmemLoadBase(); - Value GetFastmemStoreBase(); Value EmitLoadGuestMemory(Instruction instruction, const CodeCache::InstructionInfo& info, const Value& address, const SpeculativeValue& address_spec, RegSize size); void EmitLoadGuestRAMFastmem(const Value& address, RegSize size, Value& result); diff --git a/src/core/cpu_recompiler_code_generator_aarch64.cpp b/src/core/cpu_recompiler_code_generator_aarch64.cpp index 57853376f..887bad787 100644 --- a/src/core/cpu_recompiler_code_generator_aarch64.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch64.cpp @@ -1999,7 +1999,6 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(Instruction instruction, const C { m_emit->lsr(GetHostReg32(RARG1), GetHostReg32(address_reg), Bus::FASTMEM_LUT_PAGE_SHIFT); m_emit->and_(GetHostReg32(RARG2), GetHostReg32(address_reg), Bus::FASTMEM_LUT_PAGE_MASK); - m_emit->add(GetHostReg64(RARG3), GetFastmemBasePtrReg(), Bus::FASTMEM_LUT_NUM_PAGES * sizeof(u32*)); m_emit->ldr(GetHostReg64(RARG1), a64::MemOperand(GetHostReg64(RARG3), GetHostReg32(RARG1), a64::LSL, 3)); host_pc = GetCurrentNearCodePointer(); diff --git a/src/core/cpu_recompiler_code_generator_generic.cpp b/src/core/cpu_recompiler_code_generator_generic.cpp index 4521fd671..6c50823f8 100644 --- a/src/core/cpu_recompiler_code_generator_generic.cpp +++ b/src/core/cpu_recompiler_code_generator_generic.cpp @@ -63,7 +63,7 @@ Value CodeGenerator::EmitLoadGuestMemory(Instruction instruction, const CodeCach Value result = m_register_cache.AllocateScratch(HostPointerSize); - const bool use_fastmem = + const bool use_fastmem = !g_settings.cpu_recompiler_memory_exceptions && (address_spec ? Bus::CanUseFastmemForAddress(*address_spec) : true) && !SpeculativeIsCacheIsolated(); if (address_spec) { @@ -137,7 +137,7 @@ void CodeGenerator::EmitStoreGuestMemory(Instruction instruction, const CodeCach } } - const bool use_fastmem = + const bool use_fastmem = !g_settings.cpu_recompiler_memory_exceptions && (address_spec ? Bus::CanUseFastmemForAddress(*address_spec) : true) && !SpeculativeIsCacheIsolated(); if (address_spec) { diff --git a/src/core/cpu_recompiler_code_generator_x64.cpp b/src/core/cpu_recompiler_code_generator_x64.cpp index 46cb4beb1..d1efeabad 100644 --- a/src/core/cpu_recompiler_code_generator_x64.cpp +++ b/src/core/cpu_recompiler_code_generator_x64.cpp @@ -2524,8 +2524,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(Instruction instruction, const C m_emit->mov(GetHostReg32(RARG2), GetHostReg32(RARG1)); m_emit->shr(GetHostReg32(RARG1), Bus::FASTMEM_LUT_PAGE_SHIFT); m_emit->and_(GetHostReg32(RARG2), Bus::FASTMEM_LUT_PAGE_MASK); - m_emit->mov(GetHostReg64(RARG1), - m_emit->qword[GetFastmemBasePtrReg() + GetHostReg64(RARG1) * 8 + (Bus::FASTMEM_LUT_NUM_PAGES * 8)]); + m_emit->mov(GetHostReg64(RARG1), m_emit->qword[GetFastmemBasePtrReg() + GetHostReg64(RARG1) * 8]); host_pc = GetCurrentNearCodePointer(); switch (size) diff --git a/src/core/dma.cpp b/src/core/dma.cpp index e628c5846..393f60f3d 100644 --- a/src/core/dma.cpp +++ b/src/core/dma.cpp @@ -739,7 +739,6 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen const u32 terminator = UINT32_C(0xFFFFFF); std::memcpy(&ram_pointer[address], &terminator, sizeof(terminator)); - CPU::CodeCache::InvalidateCodePages(address, word_count); return Bus::GetDMARAMTickCount(word_count); } @@ -787,7 +786,6 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen } } - CPU::CodeCache::InvalidateCodePages(address, word_count); return Bus::GetDMARAMTickCount(word_count); } diff --git a/src/core/system.cpp b/src/core/system.cpp index da854247b..4fd0736cf 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -3191,7 +3191,7 @@ bool System::DumpRAM(const char* filename) if (!IsValid()) return false; - return FileSystem::WriteBinaryFile(filename, Bus::g_ram, Bus::g_ram_size); + return FileSystem::WriteBinaryFile(filename, Bus::g_unprotected_ram, Bus::g_ram_size); } bool System::DumpVRAM(const char* filename)