core: add option to break on unmapped access
This commit is contained in:
		| @@ -399,6 +399,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"}; | ||||
|   | ||||
| @@ -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)) { | ||||
|             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; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -658,6 +658,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(); | ||||
| @@ -1257,6 +1258,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(); | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -175,6 +175,19 @@ | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QCheckBox" name="cpuopt_ignore_memory_aborts"> | ||||
|           <property name="toolTip"> | ||||
|            <string> | ||||
|             <div style="white-space: nowrap">This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.</div> | ||||
|             <div style="white-space: nowrap">Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.</div> | ||||
|            </string> | ||||
|           </property> | ||||
|           <property name="text"> | ||||
|            <string>Enable fallbacks for invalid memory accesses</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|        </layout> | ||||
|       </widget> | ||||
|      </item> | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user