Bus: Protect main RAM buffer

Get rid of write-time checks.
This commit is contained in:
Stenzek
2023-10-07 18:10:09 +10:00
parent 79e1ae3e54
commit a062b00c1a
12 changed files with 82 additions and 99 deletions

View File

@ -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<RAM_8MB_CODE_PAGE_COUNT> 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<std::pair<u8*, size_t>> 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<TickCount, TickCount, TickCount> 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<u8*>(MemMap::MapSharedMemory(s_shmem_handle, MemoryMap::RAM_OFFSET, nullptr, MemoryMap::RAM_SIZE,
PageProtect::ReadWrite));
if (!g_ram)
g_unprotected_ram = static_cast<u8*>(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<uintptr_t>(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<uintptr_t>(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<u8**>(std::malloc(sizeof(u8*) * FASTMEM_LUT_NUM_SLOTS));
s_fastmem_lut = static_cast<u8**>(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<const void*>(&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<u32>(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<u32>(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<MemoryAccessSize size>
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)
{