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