core: add option to break on unmapped access

This commit is contained in:
Liam 2022-12-01 22:48:43 -05:00
parent dcc663e1bf
commit 6072b22a0b
9 changed files with 69 additions and 6 deletions

View File

@ -399,6 +399,7 @@ struct Values {
Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"}; Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"}; Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"}; Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
Setting<bool> cpuopt_ignore_memory_aborts{true, "cpuopt_ignore_memory_aborts"};
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"}; SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"}; SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};

View File

@ -145,11 +145,15 @@ void ARM_Interface::Run() {
// Notify the debugger and go to sleep if a breakpoint was hit, // Notify the debugger and go to sleep if a breakpoint was hit,
// or if the thread is unable to continue for any reason. // or if the thread is unable to continue for any reason.
if (Has(hr, breakpoint) || Has(hr, no_execute)) { if (Has(hr, breakpoint) || Has(hr, no_execute)) {
RewindBreakpointInstruction(); if (!Has(hr, no_execute)) {
RewindBreakpointInstruction();
}
if (system.DebuggerEnabled()) { if (system.DebuggerEnabled()) {
system.GetDebugger().NotifyThreadStopped(current_thread); system.GetDebugger().NotifyThreadStopped(current_thread);
} else {
LogBacktrace();
} }
current_thread->RequestSuspend(Kernel::SuspendType::Debug); current_thread->RequestSuspend(SuspendType::Debug);
break; break;
} }

View File

@ -29,7 +29,9 @@ class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public: public:
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
: parent{parent_}, : parent{parent_},
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {} memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()},
check_memory_access{debugger_enabled ||
!Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
u8 MemoryRead8(u32 vaddr) override { u8 MemoryRead8(u32 vaddr) override {
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
@ -154,6 +156,17 @@ public:
} }
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) { bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
if (!check_memory_access) {
return true;
}
if (!memory.IsValidVirtualAddressRange(addr, size)) {
LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
addr);
parent.jit.load()->HaltExecution(ARM_Interface::no_execute);
return false;
}
if (!debugger_enabled) { if (!debugger_enabled) {
return true; return true;
} }
@ -181,7 +194,8 @@ public:
ARM_Dynarmic_32& parent; ARM_Dynarmic_32& parent;
Core::Memory::Memory& memory; Core::Memory::Memory& memory;
std::size_t num_interpreted_instructions{}; std::size_t num_interpreted_instructions{};
bool debugger_enabled{}; const bool debugger_enabled{};
const bool check_memory_access{};
static constexpr u64 minimum_run_cycles = 10000U; static constexpr u64 minimum_run_cycles = 10000U;
}; };
@ -264,6 +278,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
if (!Settings::values.cpuopt_recompile_exclusives) { if (!Settings::values.cpuopt_recompile_exclusives) {
config.recompile_on_exclusive_fastmem_failure = false; config.recompile_on_exclusive_fastmem_failure = false;
} }
if (!Settings::values.cpuopt_ignore_memory_aborts) {
config.check_halt_on_memory_access = true;
}
} else { } else {
// Unsafe optimizations // Unsafe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {

View File

@ -29,7 +29,9 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public: public:
explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_)
: parent{parent_}, : parent{parent_},
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {} memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()},
check_memory_access{debugger_enabled ||
!Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
u8 MemoryRead8(u64 vaddr) override { u8 MemoryRead8(u64 vaddr) override {
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
@ -198,6 +200,17 @@ public:
} }
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) { bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
if (!check_memory_access) {
return true;
}
if (!memory.IsValidVirtualAddressRange(addr, size)) {
LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
addr);
parent.jit.load()->HaltExecution(ARM_Interface::no_execute);
return false;
}
if (!debugger_enabled) { if (!debugger_enabled) {
return true; return true;
} }
@ -226,7 +239,8 @@ public:
Core::Memory::Memory& memory; Core::Memory::Memory& memory;
u64 tpidrro_el0 = 0; u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0; u64 tpidr_el0 = 0;
bool debugger_enabled{}; const bool debugger_enabled{};
const bool check_memory_access{};
static constexpr u64 minimum_run_cycles = 10000U; static constexpr u64 minimum_run_cycles = 10000U;
}; };
@ -323,6 +337,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
if (!Settings::values.cpuopt_recompile_exclusives) { if (!Settings::values.cpuopt_recompile_exclusives) {
config.recompile_on_exclusive_fastmem_failure = false; config.recompile_on_exclusive_fastmem_failure = false;
} }
if (!Settings::values.cpuopt_ignore_memory_aborts) {
config.check_halt_on_memory_access = true;
}
} else { } else {
// Unsafe optimizations // Unsafe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {

View File

@ -658,6 +658,7 @@ void Config::ReadCpuValues() {
ReadBasicSetting(Settings::values.cpuopt_fastmem); ReadBasicSetting(Settings::values.cpuopt_fastmem);
ReadBasicSetting(Settings::values.cpuopt_fastmem_exclusives); ReadBasicSetting(Settings::values.cpuopt_fastmem_exclusives);
ReadBasicSetting(Settings::values.cpuopt_recompile_exclusives); ReadBasicSetting(Settings::values.cpuopt_recompile_exclusives);
ReadBasicSetting(Settings::values.cpuopt_ignore_memory_aborts);
} }
qt_config->endGroup(); qt_config->endGroup();
@ -1257,6 +1258,7 @@ void Config::SaveCpuValues() {
WriteBasicSetting(Settings::values.cpuopt_fastmem); WriteBasicSetting(Settings::values.cpuopt_fastmem);
WriteBasicSetting(Settings::values.cpuopt_fastmem_exclusives); WriteBasicSetting(Settings::values.cpuopt_fastmem_exclusives);
WriteBasicSetting(Settings::values.cpuopt_recompile_exclusives); WriteBasicSetting(Settings::values.cpuopt_recompile_exclusives);
WriteBasicSetting(Settings::values.cpuopt_ignore_memory_aborts);
} }
qt_config->endGroup(); qt_config->endGroup();

View File

@ -45,6 +45,9 @@ void ConfigureCpuDebug::SetConfiguration() {
ui->cpuopt_recompile_exclusives->setEnabled(runtime_lock); ui->cpuopt_recompile_exclusives->setEnabled(runtime_lock);
ui->cpuopt_recompile_exclusives->setChecked( ui->cpuopt_recompile_exclusives->setChecked(
Settings::values.cpuopt_recompile_exclusives.GetValue()); Settings::values.cpuopt_recompile_exclusives.GetValue());
ui->cpuopt_ignore_memory_aborts->setEnabled(runtime_lock);
ui->cpuopt_ignore_memory_aborts->setChecked(
Settings::values.cpuopt_ignore_memory_aborts.GetValue());
} }
void ConfigureCpuDebug::ApplyConfiguration() { void ConfigureCpuDebug::ApplyConfiguration() {
@ -59,6 +62,7 @@ void ConfigureCpuDebug::ApplyConfiguration() {
Settings::values.cpuopt_fastmem = ui->cpuopt_fastmem->isChecked(); Settings::values.cpuopt_fastmem = ui->cpuopt_fastmem->isChecked();
Settings::values.cpuopt_fastmem_exclusives = ui->cpuopt_fastmem_exclusives->isChecked(); Settings::values.cpuopt_fastmem_exclusives = ui->cpuopt_fastmem_exclusives->isChecked();
Settings::values.cpuopt_recompile_exclusives = ui->cpuopt_recompile_exclusives->isChecked(); Settings::values.cpuopt_recompile_exclusives = ui->cpuopt_recompile_exclusives->isChecked();
Settings::values.cpuopt_ignore_memory_aborts = ui->cpuopt_ignore_memory_aborts->isChecked();
} }
void ConfigureCpuDebug::changeEvent(QEvent* event) { void ConfigureCpuDebug::changeEvent(QEvent* event) {

View File

@ -175,6 +175,19 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="cpuopt_ignore_memory_aborts">
<property name="toolTip">
<string>
&lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.&lt;/div&gt;
&lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.&lt;/div&gt;
</string>
</property>
<property name="text">
<string>Enable fallbacks for invalid memory accesses</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -286,6 +286,7 @@ void Config::ReadValues() {
ReadSetting("Cpu", Settings::values.cpuopt_fastmem); ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives); ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives);
ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives); ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives);
ReadSetting("Cpu", Settings::values.cpuopt_ignore_memory_aborts);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma); ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error); ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr); ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);

View File

@ -208,6 +208,10 @@ cpuopt_fastmem_exclusives =
# 0: Disabled, 1 (default): Enabled # 0: Disabled, 1 (default): Enabled
cpuopt_recompile_exclusives = cpuopt_recompile_exclusives =
# Enable optimization to ignore invalid memory accesses (faster guest memory access)
# 0: Disabled, 1 (default): Enabled
cpuopt_ignore_memory_aborts =
# Enable unfuse FMA (improve performance on CPUs without FMA) # Enable unfuse FMA (improve performance on CPUs without FMA)
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
# 0: Disabled, 1 (default): Enabled # 0: Disabled, 1 (default): Enabled