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}