probe_rs/architecture/arm/core/
mod.rs

1//! The different ARM core implementations with all constants and custom handling.
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    CoreStatus, HaltReason,
7    core::{BreakpointCause, RegisterValue},
8    memory_mapped_bitfield_register,
9    semihosting::SemihostingCommand,
10};
11
12use super::memory::ArmMemoryInterface;
13
14pub mod armv6m;
15pub mod armv7a;
16pub mod armv7m;
17pub mod armv8a;
18pub mod armv8m;
19
20pub(crate) mod armv7a_debug_regs;
21pub(crate) mod armv8a_debug_regs;
22pub(crate) mod cortex_m;
23pub(crate) mod instructions;
24pub mod registers;
25
26/// Core information data which is downloaded from the target, represents its state and can be used for debugging.
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Dump {
29    /// The register values at the time of the dump.
30    pub regs: [u32; 16],
31    stack_addr: u32,
32    stack: Vec<u8>,
33}
34
35impl Dump {
36    /// Create a new dump from a SP and a stack dump with zeroed out registers.
37    pub fn new(stack_addr: u32, stack: Vec<u8>) -> Dump {
38        Dump {
39            regs: [0u32; 16],
40            stack_addr,
41            stack,
42        }
43    }
44}
45
46memory_mapped_bitfield_register! {
47    pub struct Dfsr(u32);
48    0xE000_ED30, "DFSR",
49    /// Indicates an asynchronous debug event generated because of **EDBGRQ** being asserted:
50    /// * `false`: no **EDBGRQ** debug event.
51    /// * `true`: **EDBGRQ** debug event.
52    pub external, set_external: 4;
53    /// Indicates whether a vector catch debug event was generated:
54    /// * `false`: no vector catch debug event generated.
55    /// * `true`: vector catch debug event generated.
56    ///
57    /// The corresponding FSR shows the primary cause of the exception.
58    pub vcatch, set_vcatch: 3;
59    /// Indicates a debug event generated by the DWT:
60    /// * `false`: no debug events generated by the DWT.
61    /// * `true`: at least one debug event generated by the DWT.
62    pub dwttrap, set_dwttrap: 2;
63    /// Indicates a debug event generated by BKPT instruction execution or a breakpoint match in the BPU:
64    /// * `false`: no breakpoint debug event.
65    /// * `true`: at least one breakpoint debug event.
66    pub bkpt, set_bkpt: 1;
67    /// Indicates a debug event generated by a C_HALT or C_STEP request, triggered by a write to the DHCSR:
68    /// * `false`: no active halt request debug event.
69    /// * `true`: halt request debug event active.
70    pub halted, set_halted: 0;
71}
72
73impl Dfsr {
74    fn clear_all() -> Self {
75        Dfsr(0b11111)
76    }
77
78    /// This only returns the correct halt_reason for armv(x)-m variants. The armv(x)-a variants have their own implementation.
79    // TODO: The different implementations between -m and -a can do with cleanup/refactoring.
80    pub(crate) fn halt_reason(&self) -> HaltReason {
81        if self.0 == 0 {
82            // No bit is set
83            HaltReason::Unknown
84        } else if self.0.count_ones() > 1 {
85            tracing::debug!("DFSR: {:?}", self);
86
87            // We cannot identify why the chip halted,
88            // it could be for multiple reasons.
89
90            // For debuggers, it's important to know if
91            // the core halted because of a breakpoint.
92            // Because of this, we still return breakpoint
93            // even if other reasons are possible as well.
94            if self.bkpt() {
95                HaltReason::Breakpoint(BreakpointCause::Unknown)
96            } else {
97                HaltReason::Multiple
98            }
99        } else if self.bkpt() {
100            HaltReason::Breakpoint(BreakpointCause::Unknown)
101        } else if self.external() {
102            HaltReason::External
103        } else if self.dwttrap() {
104            HaltReason::Watchpoint
105        } else if self.halted() {
106            HaltReason::Request
107        } else if self.vcatch() {
108            HaltReason::Exception
109        } else {
110            // We check that exactly one bit is set, so we should hit one of the cases above.
111            panic!("This should not happen. Please open a bug report.")
112        }
113    }
114}
115
116impl From<u32> for Dfsr {
117    fn from(val: u32) -> Self {
118        // Ensure that all unused bits are set to zero
119        // This makes it possible to check the number of
120        // set bits using count_ones().
121        Dfsr(val & 0b11111)
122    }
123}
124
125impl From<Dfsr> for u32 {
126    fn from(register: Dfsr) -> Self {
127        register.0
128    }
129}
130
131/// The state cache of a Cortex-M core.
132///
133/// This state is used internally to not having to poll the core constantly.
134#[derive(Debug)]
135pub struct CortexMState {
136    initialized: bool,
137
138    hw_breakpoints_enabled: bool,
139
140    current_state: CoreStatus,
141
142    fp_present: bool,
143
144    /// The semihosting command that was decoded at the current program counter
145    semihosting_command: Option<SemihostingCommand>,
146}
147
148impl CortexMState {
149    pub(crate) fn new() -> Self {
150        Self {
151            initialized: false,
152            hw_breakpoints_enabled: false,
153            current_state: CoreStatus::Unknown,
154            fp_present: false,
155            semihosting_command: None,
156        }
157    }
158
159    fn initialize(&mut self) {
160        self.initialized = true;
161    }
162
163    fn initialized(&self) -> bool {
164        self.initialized
165    }
166}
167
168/// The state cache of a Cortex-A core.
169///
170/// This state is used internally to not having to poll the core constantly.
171#[derive(Debug)]
172pub struct CortexAState {
173    initialized: bool,
174
175    current_state: CoreStatus,
176
177    // Is the core currently in a 64-bit mode?
178    is_64_bit: bool,
179
180    register_cache: Vec<Option<(RegisterValue, bool)>>,
181
182    // Number of floating point registers
183    fp_reg_count: usize,
184}
185
186impl CortexAState {
187    pub(crate) fn new() -> Self {
188        Self {
189            initialized: false,
190            current_state: CoreStatus::Unknown,
191            is_64_bit: false,
192            register_cache: vec![],
193            fp_reg_count: 0,
194        }
195    }
196
197    fn initialize(&mut self) {
198        self.initialized = true;
199    }
200
201    fn initialized(&self) -> bool {
202        self.initialized
203    }
204}
205
206/// Core implementations should call this function when they
207/// wish to update the [`CoreStatus`] of their core.
208///
209/// It will reflect the core status to the probe/memory interface if
210/// the status has changed, and will replace `current_status` with
211/// `new_status`.
212pub fn update_core_status<P: ArmMemoryInterface + ?Sized, T: core::ops::DerefMut<Target = P>>(
213    probe: &mut T,
214    current_status: &mut CoreStatus,
215    new_status: CoreStatus,
216) {
217    if *current_status != new_status {
218        probe.deref_mut().update_core_status(new_status);
219    }
220    *current_status = new_status;
221}