Merge a277d66c50
into 2c83a256ae
This commit is contained in:
commit
52401d6808
|
@ -22,6 +22,7 @@ struct WindowsMemoryFunctions
|
||||||
void* m_address_UnmapViewOfFileEx = nullptr;
|
void* m_address_UnmapViewOfFileEx = nullptr;
|
||||||
void* m_address_VirtualAlloc2 = nullptr;
|
void* m_address_VirtualAlloc2 = nullptr;
|
||||||
void* m_address_MapViewOfFile3 = nullptr;
|
void* m_address_MapViewOfFile3 = nullptr;
|
||||||
|
void* m_address_VirtualProtect = nullptr;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -111,6 +112,15 @@ public:
|
||||||
///
|
///
|
||||||
void UnmapFromMemoryRegion(void* view, size_t size);
|
void UnmapFromMemoryRegion(void* view, size_t size);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Virtual protect a section from the memory region previously mapped by CreateView.
|
||||||
|
///
|
||||||
|
/// @param data Pointer to data to protect.
|
||||||
|
/// @param size Size of the protection.
|
||||||
|
/// @param flag What new permission to protect with.
|
||||||
|
///
|
||||||
|
bool VirtualProtectMemoryRegion(u8* data, size_t size, u64 flag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WindowsMemoryRegion* EnsureSplitRegionForMapping(void* address, size_t size);
|
WindowsMemoryRegion* EnsureSplitRegionForMapping(void* address, size_t size);
|
||||||
|
|
|
@ -34,6 +34,9 @@ using PMapViewOfFile3 = PVOID(WINAPI*)(HANDLE FileMapping, HANDLE Process, PVOID
|
||||||
|
|
||||||
using PUnmapViewOfFileEx = BOOL(WINAPI*)(PVOID BaseAddress, ULONG UnmapFlags);
|
using PUnmapViewOfFileEx = BOOL(WINAPI*)(PVOID BaseAddress, ULONG UnmapFlags);
|
||||||
|
|
||||||
|
using PVirtualProtect = BOOL(WINAPI*)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect,
|
||||||
|
PDWORD lpflOldProtect);
|
||||||
|
|
||||||
using PIsApiSetImplemented = BOOL(APIENTRY*)(PCSTR Contract);
|
using PIsApiSetImplemented = BOOL(APIENTRY*)(PCSTR Contract);
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
|
@ -78,11 +81,14 @@ static bool InitWindowsMemoryFunctions(WindowsMemoryFunctions* functions)
|
||||||
functions->m_api_ms_win_core_memory_l1_1_6_handle.GetSymbolAddress("MapViewOfFile3FromApp");
|
functions->m_api_ms_win_core_memory_l1_1_6_handle.GetSymbolAddress("MapViewOfFile3FromApp");
|
||||||
void* const address_UnmapViewOfFileEx =
|
void* const address_UnmapViewOfFileEx =
|
||||||
functions->m_kernel32_handle.GetSymbolAddress("UnmapViewOfFileEx");
|
functions->m_kernel32_handle.GetSymbolAddress("UnmapViewOfFileEx");
|
||||||
|
void* const address_VirtualProtect =
|
||||||
|
functions->m_kernel32_handle.GetSymbolAddress("VirtualProtect");
|
||||||
if (address_VirtualAlloc2 && address_MapViewOfFile3 && address_UnmapViewOfFileEx)
|
if (address_VirtualAlloc2 && address_MapViewOfFile3 && address_UnmapViewOfFileEx)
|
||||||
{
|
{
|
||||||
functions->m_address_VirtualAlloc2 = address_VirtualAlloc2;
|
functions->m_address_VirtualAlloc2 = address_VirtualAlloc2;
|
||||||
functions->m_address_MapViewOfFile3 = address_MapViewOfFile3;
|
functions->m_address_MapViewOfFile3 = address_MapViewOfFile3;
|
||||||
functions->m_address_UnmapViewOfFileEx = address_UnmapViewOfFileEx;
|
functions->m_address_UnmapViewOfFileEx = address_UnmapViewOfFileEx;
|
||||||
|
functions->m_address_VirtualProtect = address_VirtualProtect;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +215,13 @@ void MemArena::ReleaseMemoryRegion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemArena::VirtualProtectMemoryRegion(u8* data, size_t size, u64 flag)
|
||||||
|
{
|
||||||
|
DWORD lpflOldProtect = 0;
|
||||||
|
return static_cast<PVirtualProtect>(m_memory_functions.m_address_VirtualProtect)(
|
||||||
|
data, size, flag, &lpflOldProtect);
|
||||||
|
}
|
||||||
|
|
||||||
WindowsMemoryRegion* MemArena::EnsureSplitRegionForMapping(void* start_address, size_t size)
|
WindowsMemoryRegion* MemArena::EnsureSplitRegionForMapping(void* start_address, size_t size)
|
||||||
{
|
{
|
||||||
u8* const address = static_cast<u8*>(start_address);
|
u8* const address = static_cast<u8*>(start_address);
|
||||||
|
|
|
@ -289,4 +289,15 @@ size_t MemPhysical()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t PageSize()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
SYSTEM_INFO sysInfo;
|
||||||
|
GetSystemInfo(&sysInfo);
|
||||||
|
return sysInfo.dwPageSize;
|
||||||
|
#else
|
||||||
|
return sysconf(_SC_PAGESIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
|
@ -34,5 +34,6 @@ bool ReadProtectMemory(void* ptr, size_t size);
|
||||||
bool WriteProtectMemory(void* ptr, size_t size, bool executable = false);
|
bool WriteProtectMemory(void* ptr, size_t size, bool executable = false);
|
||||||
bool UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
|
bool UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
|
||||||
size_t MemPhysical();
|
size_t MemPhysical();
|
||||||
|
size_t PageSize();
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
#include "Core/State.h"
|
#include "Core/State.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
#include "Core/WiiRoot.h"
|
#include "Core/WiiRoot.h"
|
||||||
|
#include "Core/HW/Memmap.h"
|
||||||
|
|
||||||
#ifdef USE_MEMORYWATCHER
|
#ifdef USE_MEMORYWATCHER
|
||||||
#include "Core/MemoryWatcher.h"
|
#include "Core/MemoryWatcher.h"
|
||||||
|
@ -385,8 +386,9 @@ static void CpuThread(Core::System& system, const std::optional<std::string>& sa
|
||||||
// The JIT need to be able to intercept faults, both for fastmem and for the BLR optimization.
|
// The JIT need to be able to intercept faults, both for fastmem and for the BLR optimization.
|
||||||
const bool exception_handler = EMM::IsExceptionHandlerSupported();
|
const bool exception_handler = EMM::IsExceptionHandlerSupported();
|
||||||
if (exception_handler)
|
if (exception_handler)
|
||||||
|
{
|
||||||
EMM::InstallExceptionHandler();
|
EMM::InstallExceptionHandler();
|
||||||
|
}
|
||||||
#ifdef USE_MEMORYWATCHER
|
#ifdef USE_MEMORYWATCHER
|
||||||
s_memory_watcher = std::make_unique<MemoryWatcher>();
|
s_memory_watcher = std::make_unique<MemoryWatcher>();
|
||||||
#endif
|
#endif
|
||||||
|
@ -689,6 +691,9 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
|
||||||
cpuThreadFunc(system, savestate_path, delete_savestate);
|
cpuThreadFunc(system, savestate_path, delete_savestate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cpuThreadFunc == CpuThread)
|
||||||
|
system.GetMemory().InitDirtyPages();
|
||||||
|
|
||||||
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stopping GDB ..."));
|
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stopping GDB ..."));
|
||||||
GDBStub::Deinit();
|
GDBStub::Deinit();
|
||||||
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "GDB stopped."));
|
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "GDB stopped."));
|
||||||
|
|
|
@ -82,9 +82,9 @@ void Shutdown(Core::System& system)
|
||||||
system.GetCoreTiming().Shutdown();
|
system.GetCoreTiming().Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoState(Core::System& system, PointerWrap& p)
|
void DoState(Core::System& system, PointerWrap& p, bool delta)
|
||||||
{
|
{
|
||||||
system.GetMemory().DoState(p);
|
system.GetMemory().DoState(p, delta);
|
||||||
p.DoMarker("Memory");
|
p.DoMarker("Memory");
|
||||||
system.GetMemoryInterface().DoState(p);
|
system.GetMemoryInterface().DoState(p);
|
||||||
p.DoMarker("MemoryInterface");
|
p.DoMarker("MemoryInterface");
|
||||||
|
|
|
@ -14,5 +14,5 @@ namespace HW
|
||||||
{
|
{
|
||||||
void Init(Core::System& system, const Sram* override_sram);
|
void Init(Core::System& system, const Sram* override_sram);
|
||||||
void Shutdown(Core::System& system);
|
void Shutdown(Core::System& system);
|
||||||
void DoState(Core::System& system, PointerWrap& p);
|
void DoState(Core::System& system, PointerWrap& p, bool delta);
|
||||||
} // namespace HW
|
} // namespace HW
|
||||||
|
|
|
@ -47,6 +47,57 @@ MemoryManager::MemoryManager(Core::System& system) : m_system(system)
|
||||||
|
|
||||||
MemoryManager::~MemoryManager() = default;
|
MemoryManager::~MemoryManager() = default;
|
||||||
|
|
||||||
|
u64 MemoryManager::GetDirtyPageIndexFromAddress(u64 address)
|
||||||
|
{
|
||||||
|
const size_t page_size = Common::PageSize();
|
||||||
|
const size_t page_mask = page_size - 1;
|
||||||
|
return address & ~page_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryManager::HandleFault(uintptr_t fault_address)
|
||||||
|
{
|
||||||
|
u8* fault_address_bytes = reinterpret_cast<u8*>(fault_address);
|
||||||
|
if (!IsAddressInEmulatedMemory(fault_address_bytes) || IsPageDirty(fault_address))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetPageDirtyBit(fault_address, 0x1, true);
|
||||||
|
bool change_protection =
|
||||||
|
m_arena.VirtualProtectMemoryRegion(fault_address_bytes, 0x1, PAGE_READWRITE);
|
||||||
|
|
||||||
|
if (!change_protection)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryManager::WriteProtectPhysicalMemoryRegions()
|
||||||
|
{
|
||||||
|
for (const PhysicalMemoryRegion& region : m_physical_regions)
|
||||||
|
{
|
||||||
|
if (!region.active || !region.track)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool change_protection =
|
||||||
|
m_arena.VirtualProtectMemoryRegion((*region.out_pointer), region.size, PAGE_READONLY);
|
||||||
|
|
||||||
|
if (!change_protection)
|
||||||
|
{
|
||||||
|
PanicAlertFmt("Memory::WriteProtectPhysicalMemoryRegions(): Failed to write protect for "
|
||||||
|
"this block of memory at 0x{:08X}.",
|
||||||
|
reinterpret_cast<u64>(*region.out_pointer));
|
||||||
|
}
|
||||||
|
const size_t page_size = Common::PageSize();
|
||||||
|
const intptr_t out_pointer = reinterpret_cast<intptr_t>(*region.out_pointer);
|
||||||
|
for (size_t i = out_pointer; i < region.size; i += page_size)
|
||||||
|
{
|
||||||
|
m_dirty_pages[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryManager::InitMMIO(bool is_wii)
|
void MemoryManager::InitMMIO(bool is_wii)
|
||||||
{
|
{
|
||||||
m_mmio_mapping = std::make_unique<MMIO::Mapping>();
|
m_mmio_mapping = std::make_unique<MMIO::Mapping>();
|
||||||
|
@ -71,6 +122,11 @@ void MemoryManager::InitMMIO(bool is_wii)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemoryManager::InitDirtyPages()
|
||||||
|
{
|
||||||
|
WriteProtectPhysicalMemoryRegions();
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryManager::Init()
|
void MemoryManager::Init()
|
||||||
{
|
{
|
||||||
const auto get_mem1_size = [] {
|
const auto get_mem1_size = [] {
|
||||||
|
@ -95,13 +151,14 @@ void MemoryManager::Init()
|
||||||
m_exram_mask = GetExRamSize() - 1;
|
m_exram_mask = GetExRamSize() - 1;
|
||||||
|
|
||||||
m_physical_regions[0] = PhysicalMemoryRegion{
|
m_physical_regions[0] = PhysicalMemoryRegion{
|
||||||
&m_ram, 0x00000000, GetRamSize(), PhysicalMemoryRegion::ALWAYS, 0, false};
|
&m_ram, 0x00000000, GetRamSize(), PhysicalMemoryRegion::ALWAYS, 0, false, true};
|
||||||
m_physical_regions[1] = PhysicalMemoryRegion{
|
m_physical_regions[1] = PhysicalMemoryRegion{
|
||||||
&m_l1_cache, 0xE0000000, GetL1CacheSize(), PhysicalMemoryRegion::ALWAYS, 0, false};
|
&m_l1_cache, 0xE0000000, GetL1CacheSize(), PhysicalMemoryRegion::ALWAYS, 0, false, false};
|
||||||
m_physical_regions[2] = PhysicalMemoryRegion{
|
m_physical_regions[2] = PhysicalMemoryRegion{
|
||||||
&m_fake_vmem, 0x7E000000, GetFakeVMemSize(), PhysicalMemoryRegion::FAKE_VMEM, 0, false};
|
&m_fake_vmem, 0x7E000000, GetFakeVMemSize(), PhysicalMemoryRegion::FAKE_VMEM, 0,
|
||||||
|
false, false};
|
||||||
m_physical_regions[3] = PhysicalMemoryRegion{
|
m_physical_regions[3] = PhysicalMemoryRegion{
|
||||||
&m_exram, 0x10000000, GetExRamSize(), PhysicalMemoryRegion::WII_ONLY, 0, false};
|
&m_exram, 0x10000000, GetExRamSize(), PhysicalMemoryRegion::WII_ONLY, 0, false, true};
|
||||||
|
|
||||||
const bool wii = m_system.IsWii();
|
const bool wii = m_system.IsWii();
|
||||||
const bool mmu = m_system.IsMMUMode();
|
const bool mmu = m_system.IsMMUMode();
|
||||||
|
@ -164,6 +221,21 @@ bool MemoryManager::IsAddressInFastmemArea(const u8* address) const
|
||||||
return address >= m_fastmem_arena && address < m_fastmem_arena + m_fastmem_arena_size;
|
return address >= m_fastmem_arena && address < m_fastmem_arena + m_fastmem_arena_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemoryManager::IsAddressInEmulatedMemory(const u8* address) const
|
||||||
|
{
|
||||||
|
for (const PhysicalMemoryRegion& region : m_physical_regions)
|
||||||
|
{
|
||||||
|
if (!region.active || !region.track)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (address >= *region.out_pointer && address < *region.out_pointer + region.size)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool MemoryManager::InitFastmemArena()
|
bool MemoryManager::InitFastmemArena()
|
||||||
{
|
{
|
||||||
// Here we set up memory mappings for fastmem. The basic idea of fastmem is that we reserve 4 GiB
|
// Here we set up memory mappings for fastmem. The basic idea of fastmem is that we reserve 4 GiB
|
||||||
|
@ -290,7 +362,7 @@ void MemoryManager::UpdateLogicalMemory(const PowerPC::BatTable& dbat_table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryManager::DoState(PointerWrap& p)
|
void MemoryManager::DoState(PointerWrap& p, bool delta)
|
||||||
{
|
{
|
||||||
const u32 current_ram_size = GetRamSize();
|
const u32 current_ram_size = GetRamSize();
|
||||||
const u32 current_l1_cache_size = GetL1CacheSize();
|
const u32 current_l1_cache_size = GetL1CacheSize();
|
||||||
|
@ -327,28 +399,60 @@ void MemoryManager::DoState(PointerWrap& p)
|
||||||
p.SetVerifyMode();
|
p.SetVerifyMode();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (delta)
|
||||||
p.DoArray(m_ram, current_ram_size);
|
{
|
||||||
p.DoArray(m_l1_cache, current_l1_cache_size);
|
const u32 page_size = static_cast<u32>(Common::PageSize());
|
||||||
p.DoMarker("Memory RAM");
|
p.Do(m_dirty_pages);
|
||||||
if (current_have_fake_vmem)
|
for (size_t i = 0; i < current_ram_size; i += page_size)
|
||||||
p.DoArray(m_fake_vmem, current_fake_vmem_size);
|
{
|
||||||
p.DoMarker("Memory FakeVMEM");
|
if (IsPageDirty(reinterpret_cast<uintptr_t>(&m_ram[i])))
|
||||||
if (current_have_exram)
|
{
|
||||||
p.DoArray(m_exram, current_exram_size);
|
p.DoArray(m_ram + i, page_size);
|
||||||
p.DoMarker("Memory EXRAM");
|
}
|
||||||
|
}
|
||||||
|
p.DoArray(m_l1_cache, current_l1_cache_size);
|
||||||
|
p.DoMarker("Memory RAM");
|
||||||
|
if (current_have_fake_vmem)
|
||||||
|
{
|
||||||
|
p.DoArray(m_fake_vmem, current_fake_vmem_size);
|
||||||
|
}
|
||||||
|
p.DoMarker("Memory FakeVMEM");
|
||||||
|
if (current_have_exram)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < current_exram_size; i += page_size)
|
||||||
|
{
|
||||||
|
if (IsPageDirty(reinterpret_cast<uintptr_t>(&m_exram[i])))
|
||||||
|
{
|
||||||
|
p.DoArray(m_exram + i, page_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.DoMarker("Memory EXRAM");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.DoArray(m_ram, current_ram_size);
|
||||||
|
p.DoArray(m_l1_cache, current_l1_cache_size);
|
||||||
|
p.DoMarker("Memory RAM");
|
||||||
|
if (current_have_fake_vmem)
|
||||||
|
p.DoArray(m_fake_vmem, current_fake_vmem_size);
|
||||||
|
p.DoMarker("Memory FakeVMEM");
|
||||||
|
if (current_have_exram)
|
||||||
|
p.DoArray(m_exram, current_exram_size);
|
||||||
|
p.DoMarker("Memory EXRAM");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryManager::Shutdown()
|
void MemoryManager::Shutdown()
|
||||||
{
|
{
|
||||||
ShutdownFastmemArena();
|
ShutdownFastmemArena();
|
||||||
|
m_dirty_pages.clear();
|
||||||
|
|
||||||
m_is_initialized = false;
|
m_is_initialized = false;
|
||||||
for (const PhysicalMemoryRegion& region : m_physical_regions)
|
for (const PhysicalMemoryRegion& region : m_physical_regions)
|
||||||
{
|
{
|
||||||
if (!region.active)
|
if (!region.active)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_arena.ReleaseView(*region.out_pointer, region.size);
|
m_arena.ReleaseView(*region.out_pointer, region.size);
|
||||||
*region.out_pointer = nullptr;
|
*region.out_pointer = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -573,4 +677,22 @@ void MemoryManager::Write_U64_Swap(u64 value, u32 address)
|
||||||
CopyToEmu(address, &value, sizeof(value));
|
CopyToEmu(address, &value, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemoryManager::IsPageDirty(uintptr_t address)
|
||||||
|
{
|
||||||
|
return m_dirty_pages[GetDirtyPageIndexFromAddress(address)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryManager::SetPageDirtyBit(uintptr_t address, size_t size, bool dirty)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
m_dirty_pages[GetDirtyPageIndexFromAddress(address + i)] = dirty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryManager::ResetDirtyPages()
|
||||||
|
{
|
||||||
|
WriteProtectPhysicalMemoryRegions();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/MathUtil.h"
|
#include "Common/MathUtil.h"
|
||||||
|
@ -48,6 +49,7 @@ struct PhysicalMemoryRegion
|
||||||
} flags;
|
} flags;
|
||||||
u32 shm_position;
|
u32 shm_position;
|
||||||
bool active;
|
bool active;
|
||||||
|
bool track;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LogicalMemoryView
|
struct LogicalMemoryView
|
||||||
|
@ -78,6 +80,7 @@ public:
|
||||||
u32 GetExRamMask() const { return m_exram_mask; }
|
u32 GetExRamMask() const { return m_exram_mask; }
|
||||||
|
|
||||||
bool IsAddressInFastmemArea(const u8* address) const;
|
bool IsAddressInFastmemArea(const u8* address) const;
|
||||||
|
bool IsAddressInEmulatedMemory(const u8* address) const;
|
||||||
u8* GetPhysicalBase() const { return m_physical_base; }
|
u8* GetPhysicalBase() const { return m_physical_base; }
|
||||||
u8* GetLogicalBase() const { return m_logical_base; }
|
u8* GetLogicalBase() const { return m_logical_base; }
|
||||||
u8* GetPhysicalPageMappingsBase() const { return m_physical_page_mappings_base; }
|
u8* GetPhysicalPageMappingsBase() const { return m_physical_page_mappings_base; }
|
||||||
|
@ -94,10 +97,11 @@ public:
|
||||||
// Init and Shutdown
|
// Init and Shutdown
|
||||||
bool IsInitialized() const { return m_is_initialized; }
|
bool IsInitialized() const { return m_is_initialized; }
|
||||||
void Init();
|
void Init();
|
||||||
|
void InitDirtyPages();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
bool InitFastmemArena();
|
bool InitFastmemArena();
|
||||||
void ShutdownFastmemArena();
|
void ShutdownFastmemArena();
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p, bool delta);
|
||||||
|
|
||||||
void UpdateLogicalMemory(const PowerPC::BatTable& dbat_table);
|
void UpdateLogicalMemory(const PowerPC::BatTable& dbat_table);
|
||||||
|
|
||||||
|
@ -130,6 +134,13 @@ public:
|
||||||
void Write_U32_Swap(u32 var, u32 address);
|
void Write_U32_Swap(u32 var, u32 address);
|
||||||
void Write_U64_Swap(u64 var, u32 address);
|
void Write_U64_Swap(u64 var, u32 address);
|
||||||
|
|
||||||
|
bool IsPageDirty(uintptr_t address);
|
||||||
|
void SetPageDirtyBit(uintptr_t address, size_t size, bool dirty);
|
||||||
|
void ResetDirtyPages();
|
||||||
|
bool HandleFault(uintptr_t fault_address);
|
||||||
|
|
||||||
|
std::map<u64, u8>& GetDirtyPages() { return m_dirty_pages; }
|
||||||
|
|
||||||
// Templated functions for byteswapped copies.
|
// Templated functions for byteswapped copies.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void CopyFromEmuSwapped(T* data, u32 address, size_t size) const
|
void CopyFromEmuSwapped(T* data, u32 address, size_t size) const
|
||||||
|
@ -254,6 +265,11 @@ private:
|
||||||
|
|
||||||
Core::System& m_system;
|
Core::System& m_system;
|
||||||
|
|
||||||
|
std::map<u64, u8> m_dirty_pages;
|
||||||
|
|
||||||
|
u64 GetDirtyPageIndexFromAddress(u64 address);
|
||||||
|
void WriteProtectPhysicalMemoryRegions();
|
||||||
|
|
||||||
void InitMMIO(bool is_wii);
|
void InitMMIO(bool is_wii);
|
||||||
};
|
};
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
|
|
||||||
|
#include "Core/HW/Memmap.h"
|
||||||
#include "Core/MachineContext.h"
|
#include "Core/MachineContext.h"
|
||||||
#include "Core/PowerPC/JitInterface.h"
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <unistd.h> // Needed for _POSIX_VERSION
|
#include <unistd.h> // Needed for _POSIX_VERSION
|
||||||
#endif
|
#endif
|
||||||
|
#include <Common/MemoryUtil.h>
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#ifdef _M_X86_64
|
#ifdef _M_X86_64
|
||||||
|
@ -60,8 +62,12 @@ static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
|
||||||
// virtual address of the inaccessible data
|
// virtual address of the inaccessible data
|
||||||
uintptr_t fault_address = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1];
|
uintptr_t fault_address = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1];
|
||||||
SContext* ctx = pPtrs->ContextRecord;
|
SContext* ctx = pPtrs->ContextRecord;
|
||||||
|
Core::System& system = Core::System::GetInstance();
|
||||||
if (Core::System::GetInstance().GetJitInterface().HandleFault(fault_address, ctx))
|
if (system.GetMemory().HandleFault(fault_address))
|
||||||
|
{
|
||||||
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
|
}
|
||||||
|
else if (system.GetJitInterface().HandleFault(fault_address, ctx))
|
||||||
{
|
{
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ void EnableCompression(bool compression)
|
||||||
s_use_compression = compression;
|
s_use_compression = compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DoState(Core::System& system, PointerWrap& p)
|
static void DoState(Core::System& system, PointerWrap& p, bool delta)
|
||||||
{
|
{
|
||||||
bool is_wii = system.IsWii() || system.IsMIOS();
|
bool is_wii = system.IsWii() || system.IsMIOS();
|
||||||
const bool is_wii_currently = is_wii;
|
const bool is_wii_currently = is_wii;
|
||||||
|
@ -188,7 +188,7 @@ static void DoState(Core::System& system, PointerWrap& p)
|
||||||
p.DoMarker("CoreTiming");
|
p.DoMarker("CoreTiming");
|
||||||
|
|
||||||
// HW needs to be restored before PowerPC because the data cache might need to be flushed.
|
// HW needs to be restored before PowerPC because the data cache might need to be flushed.
|
||||||
HW::DoState(system, p);
|
HW::DoState(system, p, delta);
|
||||||
p.DoMarker("HW");
|
p.DoMarker("HW");
|
||||||
|
|
||||||
system.GetPowerPC().DoState(p);
|
system.GetPowerPC().DoState(p);
|
||||||
|
@ -224,7 +224,7 @@ void LoadFromBuffer(Core::System& system, std::vector<u8>& buffer)
|
||||||
[&] {
|
[&] {
|
||||||
u8* ptr = buffer.data();
|
u8* ptr = buffer.data();
|
||||||
PointerWrap p(&ptr, buffer.size(), PointerWrap::Mode::Read);
|
PointerWrap p(&ptr, buffer.size(), PointerWrap::Mode::Read);
|
||||||
DoState(system, p);
|
DoState(system, p, false);
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
@ -237,13 +237,13 @@ void SaveToBuffer(Core::System& system, std::vector<u8>& buffer)
|
||||||
u8* ptr = nullptr;
|
u8* ptr = nullptr;
|
||||||
PointerWrap p_measure(&ptr, 0, PointerWrap::Mode::Measure);
|
PointerWrap p_measure(&ptr, 0, PointerWrap::Mode::Measure);
|
||||||
|
|
||||||
DoState(system, p_measure);
|
DoState(system, p_measure, false);
|
||||||
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
|
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
|
||||||
buffer.resize(buffer_size);
|
buffer.resize(buffer_size);
|
||||||
|
|
||||||
ptr = buffer.data();
|
ptr = buffer.data();
|
||||||
PointerWrap p(&ptr, buffer_size, PointerWrap::Mode::Write);
|
PointerWrap p(&ptr, buffer_size, PointerWrap::Mode::Write);
|
||||||
DoState(system, p);
|
DoState(system, p, false);
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
@ -486,7 +486,7 @@ void SaveAs(Core::System& system, const std::string& filename, bool wait)
|
||||||
// Measure the size of the buffer.
|
// Measure the size of the buffer.
|
||||||
u8* ptr = nullptr;
|
u8* ptr = nullptr;
|
||||||
PointerWrap p_measure(&ptr, 0, PointerWrap::Mode::Measure);
|
PointerWrap p_measure(&ptr, 0, PointerWrap::Mode::Measure);
|
||||||
DoState(system, p_measure);
|
DoState(system, p_measure, false);
|
||||||
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
|
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
|
||||||
|
|
||||||
// Then actually do the write.
|
// Then actually do the write.
|
||||||
|
@ -494,7 +494,7 @@ void SaveAs(Core::System& system, const std::string& filename, bool wait)
|
||||||
current_buffer.resize(buffer_size);
|
current_buffer.resize(buffer_size);
|
||||||
ptr = current_buffer.data();
|
ptr = current_buffer.data();
|
||||||
PointerWrap p(&ptr, buffer_size, PointerWrap::Mode::Write);
|
PointerWrap p(&ptr, buffer_size, PointerWrap::Mode::Write);
|
||||||
DoState(system, p);
|
DoState(system, p, true);
|
||||||
|
|
||||||
if (p.IsWriteMode())
|
if (p.IsWriteMode())
|
||||||
{
|
{
|
||||||
|
@ -900,7 +900,7 @@ void LoadAs(Core::System& system, const std::string& filename)
|
||||||
{
|
{
|
||||||
u8* ptr = buffer.data();
|
u8* ptr = buffer.data();
|
||||||
PointerWrap p(&ptr, buffer.size(), PointerWrap::Mode::Read);
|
PointerWrap p(&ptr, buffer.size(), PointerWrap::Mode::Read);
|
||||||
DoState(system, p);
|
DoState(system, p, true);
|
||||||
loaded = true;
|
loaded = true;
|
||||||
loadedSuccessfully = p.IsReadMode();
|
loadedSuccessfully = p.IsReadMode();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue