diff options
| m--------- | externals/dynarmic | 0 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 17 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.h | 1 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 42 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 28 |
5 files changed, 64 insertions, 24 deletions
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject 5ad1d02351bf4fee681a3d701d210b419f41a50 | Subproject 7f84870712ac2fe06aa62dc2bebbe46b51a2cc2 | ||
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 6425e131f..56d7d7b3c 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp | |||
| @@ -119,16 +119,23 @@ void ARM_Interface::Run() { | |||
| 119 | } | 119 | } |
| 120 | system.ExitDynarmicProfile(); | 120 | system.ExitDynarmicProfile(); |
| 121 | 121 | ||
| 122 | // Notify the debugger and go to sleep if a breakpoint was hit. | 122 | // Notify the debugger and go to sleep if a breakpoint was hit, |
| 123 | if (Has(hr, breakpoint)) { | 123 | // or if the thread is unable to continue for any reason. |
| 124 | if (Has(hr, breakpoint) || Has(hr, no_execute)) { | ||
| 124 | RewindBreakpointInstruction(); | 125 | RewindBreakpointInstruction(); |
| 125 | system.GetDebugger().NotifyThreadStopped(current_thread); | 126 | if (system.DebuggerEnabled()) { |
| 126 | current_thread->RequestSuspend(SuspendType::Debug); | 127 | system.GetDebugger().NotifyThreadStopped(current_thread); |
| 128 | } | ||
| 129 | current_thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 127 | break; | 130 | break; |
| 128 | } | 131 | } |
| 132 | |||
| 133 | // Notify the debugger and go to sleep if a watchpoint was hit. | ||
| 129 | if (Has(hr, watchpoint)) { | 134 | if (Has(hr, watchpoint)) { |
| 130 | RewindBreakpointInstruction(); | 135 | RewindBreakpointInstruction(); |
| 131 | system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint()); | 136 | if (system.DebuggerEnabled()) { |
| 137 | system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint()); | ||
| 138 | } | ||
| 132 | current_thread->RequestSuspend(SuspendType::Debug); | 139 | current_thread->RequestSuspend(SuspendType::Debug); |
| 133 | break; | 140 | break; |
| 134 | } | 141 | } |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 4e431e27a..8a066ed91 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -204,6 +204,7 @@ public: | |||
| 204 | static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; | 204 | static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; |
| 205 | static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; | 205 | static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; |
| 206 | static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5; | 206 | static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5; |
| 207 | static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6; | ||
| 207 | 208 | ||
| 208 | protected: | 209 | protected: |
| 209 | /// System context that this ARM interface is running under. | 210 | /// System context that this ARM interface is running under. |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 8c90c8be0..10cf72a45 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -48,6 +48,12 @@ public: | |||
| 48 | CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); | 48 | CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); |
| 49 | return memory.Read64(vaddr); | 49 | return memory.Read64(vaddr); |
| 50 | } | 50 | } |
| 51 | std::optional<u32> MemoryReadCode(u32 vaddr) override { | ||
| 52 | if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { | ||
| 53 | return std::nullopt; | ||
| 54 | } | ||
| 55 | return MemoryRead32(vaddr); | ||
| 56 | } | ||
| 51 | 57 | ||
| 52 | void MemoryWrite8(u32 vaddr, u8 value) override { | 58 | void MemoryWrite8(u32 vaddr, u8 value) override { |
| 53 | if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { | 59 | if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { |
| @@ -89,21 +95,28 @@ public: | |||
| 89 | 95 | ||
| 90 | void InterpreterFallback(u32 pc, std::size_t num_instructions) override { | 96 | void InterpreterFallback(u32 pc, std::size_t num_instructions) override { |
| 91 | parent.LogBacktrace(); | 97 | parent.LogBacktrace(); |
| 92 | UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc, | 98 | LOG_ERROR(Core_ARM, |
| 93 | MemoryReadCode(pc)); | 99 | "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, |
| 100 | num_instructions, MemoryRead32(pc)); | ||
| 94 | } | 101 | } |
| 95 | 102 | ||
| 96 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { | 103 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { |
| 97 | if (debugger_enabled) { | 104 | switch (exception) { |
| 98 | parent.SaveContext(parent.breakpoint_context); | 105 | case Dynarmic::A32::Exception::NoExecuteFault: |
| 99 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); | 106 | LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#08x}", pc); |
| 107 | ReturnException(pc, ARM_Interface::no_execute); | ||
| 100 | return; | 108 | return; |
| 101 | } | 109 | default: |
| 110 | if (debugger_enabled) { | ||
| 111 | ReturnException(pc, ARM_Interface::breakpoint); | ||
| 112 | return; | ||
| 113 | } | ||
| 102 | 114 | ||
| 103 | parent.LogBacktrace(); | 115 | parent.LogBacktrace(); |
| 104 | LOG_CRITICAL(Core_ARM, | 116 | LOG_CRITICAL(Core_ARM, |
| 105 | "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", | 117 | "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", |
| 106 | exception, pc, MemoryReadCode(pc), parent.IsInThumbMode()); | 118 | exception, pc, MemoryRead32(pc), parent.IsInThumbMode()); |
| 119 | } | ||
| 107 | } | 120 | } |
| 108 | 121 | ||
| 109 | void CallSVC(u32 swi) override { | 122 | void CallSVC(u32 swi) override { |
| @@ -141,15 +154,20 @@ public: | |||
| 141 | 154 | ||
| 142 | const auto match{parent.MatchingWatchpoint(addr, size, type)}; | 155 | const auto match{parent.MatchingWatchpoint(addr, size, type)}; |
| 143 | if (match) { | 156 | if (match) { |
| 144 | parent.SaveContext(parent.breakpoint_context); | ||
| 145 | parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); | ||
| 146 | parent.halted_watchpoint = match; | 157 | parent.halted_watchpoint = match; |
| 158 | ReturnException(parent.jit.load()->Regs()[15], ARM_Interface::watchpoint); | ||
| 147 | return false; | 159 | return false; |
| 148 | } | 160 | } |
| 149 | 161 | ||
| 150 | return true; | 162 | return true; |
| 151 | } | 163 | } |
| 152 | 164 | ||
| 165 | void ReturnException(u32 pc, Dynarmic::HaltReason hr) { | ||
| 166 | parent.SaveContext(parent.breakpoint_context); | ||
| 167 | parent.breakpoint_context.cpu_registers[15] = pc; | ||
| 168 | parent.jit.load()->HaltExecution(hr); | ||
| 169 | } | ||
| 170 | |||
| 153 | ARM_Dynarmic_32& parent; | 171 | ARM_Dynarmic_32& parent; |
| 154 | Core::Memory::Memory& memory; | 172 | Core::Memory::Memory& memory; |
| 155 | std::size_t num_interpreted_instructions{}; | 173 | std::size_t num_interpreted_instructions{}; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 4370ca294..92266aa9e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -52,6 +52,12 @@ public: | |||
| 52 | CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); | 52 | CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); |
| 53 | return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; | 53 | return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; |
| 54 | } | 54 | } |
| 55 | std::optional<u32> MemoryReadCode(u64 vaddr) override { | ||
| 56 | if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { | ||
| 57 | return std::nullopt; | ||
| 58 | } | ||
| 59 | return MemoryRead32(vaddr); | ||
| 60 | } | ||
| 55 | 61 | ||
| 56 | void MemoryWrite8(u64 vaddr, u8 value) override { | 62 | void MemoryWrite8(u64 vaddr, u8 value) override { |
| 57 | if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { | 63 | if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { |
| @@ -105,7 +111,7 @@ public: | |||
| 105 | parent.LogBacktrace(); | 111 | parent.LogBacktrace(); |
| 106 | LOG_ERROR(Core_ARM, | 112 | LOG_ERROR(Core_ARM, |
| 107 | "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, | 113 | "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, |
| 108 | num_instructions, MemoryReadCode(pc)); | 114 | num_instructions, MemoryRead32(pc)); |
| 109 | } | 115 | } |
| 110 | 116 | ||
| 111 | void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, | 117 | void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, |
| @@ -138,16 +144,19 @@ public: | |||
| 138 | case Dynarmic::A64::Exception::SendEventLocal: | 144 | case Dynarmic::A64::Exception::SendEventLocal: |
| 139 | case Dynarmic::A64::Exception::Yield: | 145 | case Dynarmic::A64::Exception::Yield: |
| 140 | return; | 146 | return; |
| 147 | case Dynarmic::A64::Exception::NoExecuteFault: | ||
| 148 | LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc); | ||
| 149 | ReturnException(pc, ARM_Interface::no_execute); | ||
| 150 | return; | ||
| 141 | default: | 151 | default: |
| 142 | if (debugger_enabled) { | 152 | if (debugger_enabled) { |
| 143 | parent.SaveContext(parent.breakpoint_context); | 153 | ReturnException(pc, ARM_Interface::breakpoint); |
| 144 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); | ||
| 145 | return; | 154 | return; |
| 146 | } | 155 | } |
| 147 | 156 | ||
| 148 | parent.LogBacktrace(); | 157 | parent.LogBacktrace(); |
| 149 | ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", | 158 | LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", |
| 150 | static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); | 159 | static_cast<std::size_t>(exception), pc, MemoryRead32(pc)); |
| 151 | } | 160 | } |
| 152 | } | 161 | } |
| 153 | 162 | ||
| @@ -188,15 +197,20 @@ public: | |||
| 188 | 197 | ||
| 189 | const auto match{parent.MatchingWatchpoint(addr, size, type)}; | 198 | const auto match{parent.MatchingWatchpoint(addr, size, type)}; |
| 190 | if (match) { | 199 | if (match) { |
| 191 | parent.SaveContext(parent.breakpoint_context); | ||
| 192 | parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); | ||
| 193 | parent.halted_watchpoint = match; | 200 | parent.halted_watchpoint = match; |
| 201 | ReturnException(parent.jit.load()->GetPC(), ARM_Interface::watchpoint); | ||
| 194 | return false; | 202 | return false; |
| 195 | } | 203 | } |
| 196 | 204 | ||
| 197 | return true; | 205 | return true; |
| 198 | } | 206 | } |
| 199 | 207 | ||
| 208 | void ReturnException(u64 pc, Dynarmic::HaltReason hr) { | ||
| 209 | parent.SaveContext(parent.breakpoint_context); | ||
| 210 | parent.breakpoint_context.pc = pc; | ||
| 211 | parent.jit.load()->HaltExecution(hr); | ||
| 212 | } | ||
| 213 | |||
| 200 | ARM_Dynarmic_64& parent; | 214 | ARM_Dynarmic_64& parent; |
| 201 | Core::Memory::Memory& memory; | 215 | Core::Memory::Memory& memory; |
| 202 | u64 tpidrro_el0 = 0; | 216 | u64 tpidrro_el0 = 0; |