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)) {
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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