diff options
Diffstat (limited to 'src/core/arm')
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 41 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.h | 13 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 69 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.h | 6 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 79 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.h | 6 | 
6 files changed, 187 insertions, 27 deletions
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 9a285dfc6..6425e131f 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -121,8 +121,15 @@ void ARM_Interface::Run() {          // Notify the debugger and go to sleep if a breakpoint was hit.          if (Has(hr, breakpoint)) { +            RewindBreakpointInstruction();              system.GetDebugger().NotifyThreadStopped(current_thread); -            current_thread->RequestSuspend(Kernel::SuspendType::Debug); +            current_thread->RequestSuspend(SuspendType::Debug); +            break; +        } +        if (Has(hr, watchpoint)) { +            RewindBreakpointInstruction(); +            system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint()); +            current_thread->RequestSuspend(SuspendType::Debug);              break;          } @@ -136,4 +143,36 @@ void ARM_Interface::Run() {      }  } +void ARM_Interface::LoadWatchpointArray(const WatchpointArray& wp) { +    watchpoints = ℘ +} + +const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint( +    VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const { +    if (!watchpoints) { +        return nullptr; +    } + +    const VAddr start_address{addr}; +    const VAddr end_address{addr + size}; + +    for (size_t i = 0; i < Core::Hardware::NUM_WATCHPOINTS; i++) { +        const auto& watch{(*watchpoints)[i]}; + +        if (end_address <= watch.start_address) { +            continue; +        } +        if (start_address >= watch.end_address) { +            continue; +        } +        if ((access_type & watch.type) == Kernel::DebugWatchpointType::None) { +            continue; +        } + +        return &watch; +    } + +    return nullptr; +} +  } // namespace Core diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 66f6107e9..4e431e27a 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -5,6 +5,7 @@  #pragma once  #include <array> +#include <span>  #include <vector>  #include <dynarmic/interface/halt_reason.h> @@ -19,13 +20,16 @@ struct PageTable;  namespace Kernel {  enum class VMAPermission : u8; -} +enum class DebugWatchpointType : u8; +struct DebugWatchpoint; +} // namespace Kernel  namespace Core {  class System;  class CPUInterruptHandler;  using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>; +using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;  /// Generic ARMv8 CPU interface  class ARM_Interface { @@ -170,6 +174,7 @@ public:      virtual void SaveContext(ThreadContext64& ctx) = 0;      virtual void LoadContext(const ThreadContext32& ctx) = 0;      virtual void LoadContext(const ThreadContext64& ctx) = 0; +    void LoadWatchpointArray(const WatchpointArray& wp);      /// Clears the exclusive monitor's state.      virtual void ClearExclusiveState() = 0; @@ -198,18 +203,24 @@ public:      static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;      static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;      static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; +    static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5;  protected:      /// System context that this ARM interface is running under.      System& system;      CPUInterrupts& interrupt_handlers; +    const WatchpointArray* watchpoints;      bool uses_wall_clock;      static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out); +    const Kernel::DebugWatchpoint* MatchingWatchpoint( +        VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const;      virtual Dynarmic::HaltReason RunJit() = 0;      virtual Dynarmic::HaltReason StepJit() = 0;      virtual u32 GetSvcNumber() const = 0; +    virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; +    virtual void RewindBreakpointInstruction() = 0;  };  } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 7c82d0b96..8c90c8be0 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -29,45 +29,62 @@ using namespace Common::Literals;  class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {  public:      explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) -        : parent{parent_}, memory(parent.system.Memory()) {} +        : parent{parent_}, +          memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {}      u8 MemoryRead8(u32 vaddr) override { +        CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);          return memory.Read8(vaddr);      }      u16 MemoryRead16(u32 vaddr) override { +        CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);          return memory.Read16(vaddr);      }      u32 MemoryRead32(u32 vaddr) override { +        CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);          return memory.Read32(vaddr);      }      u64 MemoryRead64(u32 vaddr) override { +        CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);          return memory.Read64(vaddr);      }      void MemoryWrite8(u32 vaddr, u8 value) override { -        memory.Write8(vaddr, value); +        if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { +            memory.Write8(vaddr, value); +        }      }      void MemoryWrite16(u32 vaddr, u16 value) override { -        memory.Write16(vaddr, value); +        if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { +            memory.Write16(vaddr, value); +        }      }      void MemoryWrite32(u32 vaddr, u32 value) override { -        memory.Write32(vaddr, value); +        if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { +            memory.Write32(vaddr, value); +        }      }      void MemoryWrite64(u32 vaddr, u64 value) override { -        memory.Write64(vaddr, value); +        if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { +            memory.Write64(vaddr, value); +        }      }      bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override { -        return memory.WriteExclusive8(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive8(vaddr, value, expected);      }      bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override { -        return memory.WriteExclusive16(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive16(vaddr, value, expected);      }      bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override { -        return memory.WriteExclusive32(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive32(vaddr, value, expected);      }      bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override { -        return memory.WriteExclusive64(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive64(vaddr, value, expected);      }      void InterpreterFallback(u32 pc, std::size_t num_instructions) override { @@ -77,8 +94,8 @@ public:      }      void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { -        if (parent.system.DebuggerEnabled()) { -            parent.jit.load()->Regs()[15] = pc; +        if (debugger_enabled) { +            parent.SaveContext(parent.breakpoint_context);              parent.jit.load()->HaltExecution(ARM_Interface::breakpoint);              return;          } @@ -117,9 +134,26 @@ public:          return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);      } +    bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) { +        if (!debugger_enabled) { +            return true; +        } + +        const auto match{parent.MatchingWatchpoint(addr, size, type)}; +        if (match) { +            parent.SaveContext(parent.breakpoint_context); +            parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); +            parent.halted_watchpoint = match; +            return false; +        } + +        return true; +    } +      ARM_Dynarmic_32& parent;      Core::Memory::Memory& memory;      std::size_t num_interpreted_instructions{}; +    bool debugger_enabled{};      static constexpr u64 minimum_run_cycles = 1000U;  }; @@ -154,6 +188,11 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*      config.code_cache_size = 512_MiB;      config.far_code_offset = 400_MiB; +    // Allow memory fault handling to work +    if (system.DebuggerEnabled()) { +        config.check_halt_on_memory_access = true; +    } +      // null_jit      if (!page_table) {          // Don't waste too much memory on null_jit @@ -248,6 +287,14 @@ u32 ARM_Dynarmic_32::GetSvcNumber() const {      return svc_swi;  } +const Kernel::DebugWatchpoint* ARM_Dynarmic_32::HaltedWatchpoint() const { +    return halted_watchpoint; +} + +void ARM_Dynarmic_32::RewindBreakpointInstruction() { +    LoadContext(breakpoint_context); +} +  ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,                                   bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,                                   std::size_t core_index_) diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 5b1d60005..fcbe24f0c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -72,6 +72,8 @@ protected:      Dynarmic::HaltReason RunJit() override;      Dynarmic::HaltReason StepJit() override;      u32 GetSvcNumber() const override; +    const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; +    void RewindBreakpointInstruction() override;  private:      std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; @@ -98,6 +100,10 @@ private:      // SVC callback      u32 svc_swi{}; + +    // Watchpoint info +    const Kernel::DebugWatchpoint* halted_watchpoint; +    ThreadContext32 breakpoint_context;  };  } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index d4c67eafd..4370ca294 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -29,55 +29,76 @@ using namespace Common::Literals;  class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {  public:      explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) -        : parent{parent_}, memory(parent.system.Memory()) {} +        : parent{parent_}, +          memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {}      u8 MemoryRead8(u64 vaddr) override { +        CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);          return memory.Read8(vaddr);      }      u16 MemoryRead16(u64 vaddr) override { +        CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);          return memory.Read16(vaddr);      }      u32 MemoryRead32(u64 vaddr) override { +        CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);          return memory.Read32(vaddr);      }      u64 MemoryRead64(u64 vaddr) override { +        CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);          return memory.Read64(vaddr);      }      Vector MemoryRead128(u64 vaddr) override { +        CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);          return {memory.Read64(vaddr), memory.Read64(vaddr + 8)};      }      void MemoryWrite8(u64 vaddr, u8 value) override { -        memory.Write8(vaddr, value); +        if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { +            memory.Write8(vaddr, value); +        }      }      void MemoryWrite16(u64 vaddr, u16 value) override { -        memory.Write16(vaddr, value); +        if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { +            memory.Write16(vaddr, value); +        }      }      void MemoryWrite32(u64 vaddr, u32 value) override { -        memory.Write32(vaddr, value); +        if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { +            memory.Write32(vaddr, value); +        }      }      void MemoryWrite64(u64 vaddr, u64 value) override { -        memory.Write64(vaddr, value); +        if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { +            memory.Write64(vaddr, value); +        }      }      void MemoryWrite128(u64 vaddr, Vector value) override { -        memory.Write64(vaddr, value[0]); -        memory.Write64(vaddr + 8, value[1]); +        if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) { +            memory.Write64(vaddr, value[0]); +            memory.Write64(vaddr + 8, value[1]); +        }      }      bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override { -        return memory.WriteExclusive8(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive8(vaddr, value, expected);      }      bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override { -        return memory.WriteExclusive16(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive16(vaddr, value, expected);      }      bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override { -        return memory.WriteExclusive32(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive32(vaddr, value, expected);      }      bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override { -        return memory.WriteExclusive64(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive64(vaddr, value, expected);      }      bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override { -        return memory.WriteExclusive128(vaddr, value, expected); +        return CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write) && +               memory.WriteExclusive128(vaddr, value, expected);      }      void InterpreterFallback(u64 pc, std::size_t num_instructions) override { @@ -118,8 +139,8 @@ public:          case Dynarmic::A64::Exception::Yield:              return;          default: -            if (parent.system.DebuggerEnabled()) { -                parent.jit.load()->SetPC(pc); +            if (debugger_enabled) { +                parent.SaveContext(parent.breakpoint_context);                  parent.jit.load()->HaltExecution(ARM_Interface::breakpoint);                  return;              } @@ -160,10 +181,27 @@ public:          return parent.system.CoreTiming().GetClockTicks();      } +    bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) { +        if (!debugger_enabled) { +            return true; +        } + +        const auto match{parent.MatchingWatchpoint(addr, size, type)}; +        if (match) { +            parent.SaveContext(parent.breakpoint_context); +            parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); +            parent.halted_watchpoint = match; +            return false; +        } + +        return true; +    } +      ARM_Dynarmic_64& parent;      Core::Memory::Memory& memory;      u64 tpidrro_el0 = 0;      u64 tpidr_el0 = 0; +    bool debugger_enabled{};      static constexpr u64 minimum_run_cycles = 1000U;  }; @@ -214,6 +252,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*      config.code_cache_size = 512_MiB;      config.far_code_offset = 400_MiB; +    // Allow memory fault handling to work +    if (system.DebuggerEnabled()) { +        config.check_halt_on_memory_access = true; +    } +      // null_jit      if (!page_table) {          // Don't waste too much memory on null_jit @@ -308,6 +351,14 @@ u32 ARM_Dynarmic_64::GetSvcNumber() const {      return svc_swi;  } +const Kernel::DebugWatchpoint* ARM_Dynarmic_64::HaltedWatchpoint() const { +    return halted_watchpoint; +} + +void ARM_Dynarmic_64::RewindBreakpointInstruction() { +    LoadContext(breakpoint_context); +} +  ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,                                   bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,                                   std::size_t core_index_) diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index abfbc3c3f..71dbaac5e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -66,6 +66,8 @@ protected:      Dynarmic::HaltReason RunJit() override;      Dynarmic::HaltReason StepJit() override;      u32 GetSvcNumber() const override; +    const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; +    void RewindBreakpointInstruction() override;  private:      std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, @@ -91,6 +93,10 @@ private:      // SVC callback      u32 svc_swi{}; + +    // Breakpoint info +    const Kernel::DebugWatchpoint* halted_watchpoint; +    ThreadContext64 breakpoint_context;  };  } // namespace Core  | 
