probe_rs/architecture/arm/
mod.rs

1//! All the interface bits for ARM.
2
3#[macro_use]
4pub mod ap;
5pub(crate) mod assembly;
6pub(crate) mod communication_interface;
7pub mod component;
8// TODO: Check if this should be public.
9pub mod core;
10pub mod dp;
11pub mod memory;
12pub mod sequences;
13pub mod swo;
14pub(crate) mod traits;
15
16pub use self::core::{Dump, armv6m, armv7a, armv7m, armv8a, armv8m};
17use self::{
18    ap::AccessPortError,
19    dp::DebugPortError,
20    memory::romtable::RomTableError,
21    sequences::ArmDebugSequenceError,
22    {armv7a::Armv7aError, armv8a::Armv8aError},
23};
24use crate::{
25    core::memory_mapped_registers::RegisterAddressOutOfBounds,
26    memory::{InvalidDataLengthError, MemoryNotAlignedError},
27    probe::DebugProbeError,
28};
29pub use communication_interface::{
30    ArmChipInfo, ArmCommunicationInterface, ArmDebugInterface, DapError, DapProbe,
31};
32pub use swo::{SwoAccess, SwoConfig, SwoMode, SwoReader};
33pub use traits::*;
34
35/// A error that occured while parsing a raw register value.
36#[derive(Debug, thiserror::Error)]
37#[error("Failed to parse register {name} from {value:#010x}")]
38pub struct RegisterParseError {
39    name: &'static str,
40    value: u32,
41}
42
43impl RegisterParseError {
44    /// Creates a new instance of error.
45    pub fn new(name: &'static str, value: u32) -> Self {
46        RegisterParseError { name, value }
47    }
48}
49
50/// ARM-specific errors
51#[derive(Debug, thiserror::Error, docsplay::Display)]
52pub enum ArmError {
53    /// The operation requires one of the following architectures: {0:?}
54    ArchitectureRequired(&'static [&'static str]),
55
56    /// A timeout occurred during an operation.
57    Timeout,
58
59    /// The address is too large for the 32 bit address space.
60    AddressOutOf32BitAddressSpace,
61
62    /// The current target device is not an ARM device.
63    NoArmTarget,
64
65    /// Error using access port {address:?}.
66    AccessPort {
67        /// Address of the access port
68        address: FullyQualifiedApAddress,
69        /// Source of the error.
70        source: AccessPortError,
71    },
72
73    /// An error occurred while using a debug port.
74    DebugPort(#[from] DebugPortError),
75
76    /// The core has to be halted for the operation, but was not.
77    CoreNotHalted,
78
79    /// Performing certain operations (e.g device unlock or Chip-Erase) can leave the device in a
80    /// state that requires a probe re-attach to resolve.
81    ReAttachRequired,
82
83    /// An operation could not be performed because it lacked the permission to do so: {0}
84    ///
85    /// This can for example happen when the core is locked and needs to be erased to be unlocked.
86    /// Then the correct permission needs to be given to automatically unlock the core to prevent
87    /// accidental erases.
88    #[ignore_extra_doc_attributes]
89    MissingPermissions(String),
90
91    /// An error occurred in the communication with an access port or debug port.
92    Dap(#[from] DapError),
93
94    /// The debug probe encountered an error.
95    Probe(#[from] DebugProbeError),
96
97    /// Failed to access address 0x{0.address:08x} as it is not aligned to the requirement of
98    /// {0.alignment} bytes for this platform and API call.
99    MemoryNotAligned(#[from] MemoryNotAlignedError),
100
101    /// A region outside of the AP address space was accessed.
102    OutOfBounds,
103
104    /// {0} bit is not a supported memory transfer width on the current core.
105    UnsupportedTransferWidth(usize),
106
107    /// The AP with address {0:?} does not exist.
108    ApDoesNotExist(FullyQualifiedApAddress),
109
110    /// The AP has the wrong version for the operation.
111    WrongApVersion,
112
113    /// The AP has the wrong type for the operation.
114    WrongApType,
115
116    /// Unable to create a breakpoint at address {0:#010X}. Hardware breakpoints are only supported
117    /// at addresses < 0x2000_0000.
118    UnsupportedBreakpointAddress(u32),
119
120    /// ARMv8a specific error occurred.
121    Armv8a(#[from] Armv8aError),
122
123    /// ARMv7a specific error occurred.
124    Armv7a(#[from] Armv7aError),
125
126    /// Error occurred in a debug sequence.
127    DebugSequence(#[from] ArmDebugSequenceError),
128
129    /// Tracing has not been configured.
130    TracingUnconfigured,
131
132    /// Error parsing a register.
133    RegisterParse(#[from] RegisterParseError),
134
135    /// Error reading ROM table.
136    RomTable(#[source] RomTableError),
137
138    /// Failed to erase chip.
139    ChipEraseFailed,
140
141    /// The operation requires the following extension(s): {0:?}.
142    ExtensionRequired(&'static [&'static str]),
143
144    /// An error occurred while calculating the address of a register.
145    RegisterAddressOutOfBounds(#[from] RegisterAddressOutOfBounds),
146
147    /// Some required functionality is not implemented: {0}
148    NotImplemented(&'static str),
149
150    /// Invalid data length error: {0}
151    InvalidDataLength(#[from] InvalidDataLengthError),
152
153    /// Another ARM error occurred: {0}
154    Other(String),
155}
156
157impl ArmError {
158    /// Constructs [`ArmError::MemoryNotAligned`] from the address and the required alignment.
159    pub fn from_access_port(err: AccessPortError, ap_address: &FullyQualifiedApAddress) -> Self {
160        ArmError::AccessPort {
161            address: ap_address.clone(),
162            source: err,
163        }
164    }
165
166    /// Constructs a [`ArmError::MemoryNotAligned`] from the address and the required alignment.
167    pub fn alignment_error(address: u64, alignment: usize) -> Self {
168        ArmError::MemoryNotAligned(MemoryNotAlignedError { address, alignment })
169    }
170}
171
172impl From<RomTableError> for ArmError {
173    fn from(value: RomTableError) -> Self {
174        match value {
175            RomTableError::Memory(err) => *err,
176            other => ArmError::RomTable(other),
177        }
178    }
179}
180
181/// Check if the address is a valid 32 bit address. This functions
182/// is ARM specific for ease of use, so that a specific error code can be returned.
183pub fn valid_32bit_arm_address(address: u64) -> Result<u32, ArmError> {
184    address
185        .try_into()
186        .map_err(|_| ArmError::AddressOutOf32BitAddressSpace)
187}