Merge pull request #9370 from liamwhite/break-unmapped

core: add option to break on unmapped access
This commit is contained in:
merry 2022-12-06 20:20:20 +00:00 committed by GitHub
commit e1f5f4bdea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 69 additions and 6 deletions

View file

@ -400,6 +400,7 @@ struct Values {
Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_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_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,
// or if the thread is unable to continue for any reason.
if (Has(hr, breakpoint) || Has(hr, no_execute)) {
RewindBreakpointInstruction();
if (!Has(hr, no_execute)) {
RewindBreakpointInstruction();
}
if (system.DebuggerEnabled()) {
system.GetDebugger().NotifyThreadStopped(current_thread);
} else {
LogBacktrace();
}
current_thread->RequestSuspend(Kernel::SuspendType::Debug);
current_thread->RequestSuspend(SuspendType::Debug);
break;
}

View file

@ -29,7 +29,9 @@ class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ARM_Dynarmic_32& 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 {
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
@ -154,6 +156,17 @@ public:
}
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) {
return true;
}
@ -181,7 +194,8 @@ public:
ARM_Dynarmic_32& parent;
Core::Memory::Memory& memory;
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;
};
@ -264,6 +278,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
if (!Settings::values.cpuopt_recompile_exclusives) {
config.recompile_on_exclusive_fastmem_failure = false;
}
if (!Settings::values.cpuopt_ignore_memory_aborts) {
config.check_halt_on_memory_access = true;
}
} else {
// Unsafe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {

View file

@ -29,7 +29,9 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
explicit DynarmicCallbacks64(ARM_Dynarmic_64& 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 {
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
@ -198,6 +200,17 @@ public:
}
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) {
return true;
}
@ -226,7 +239,8 @@ public:
Core::Memory::Memory& memory;
u64 tpidrro_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;
};
@ -323,6 +337,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
if (!Settings::values.cpuopt_recompile_exclusives) {
config.recompile_on_exclusive_fastmem_failure = false;
}
if (!Settings::values.cpuopt_ignore_memory_aborts) {
config.check_halt_on_memory_access = true;
}
} else {
// Unsafe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {

View file

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

View file

@ -45,6 +45,9 @@ void ConfigureCpuDebug::SetConfiguration() {
ui->cpuopt_recompile_exclusives->setEnabled(runtime_lock);
ui->cpuopt_recompile_exclusives->setChecked(
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() {
@ -59,6 +62,7 @@ void ConfigureCpuDebug::ApplyConfiguration() {
Settings::values.cpuopt_fastmem = ui->cpuopt_fastmem->isChecked();
Settings::values.cpuopt_fastmem_exclusives = ui->cpuopt_fastmem_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) {

View file

@ -175,6 +175,19 @@
</property>
</widget>
</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>
</widget>
</item>

View file

@ -286,6 +286,7 @@ void Config::ReadValues() {
ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
ReadSetting("Cpu", Settings::values.cpuopt_fastmem_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_reduce_fp_error);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);

View file

@ -208,6 +208,10 @@ cpuopt_fastmem_exclusives =
# 0: Disabled, 1 (default): Enabled
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)
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
# 0: Disabled, 1 (default): Enabled