Repository: probe-rs/probe-rs
Pull request #3106 (2025-02-18 03:21:37)

Added support for Texas Instruments MSPM0G151x/G351x/L122x/L222x series
Both of the new target files have been tested with my G3519 and L2228 Launchpad boards.


Patch:
diff --git a/changelog/added-black-magic-dpv3.md b/changelog/added-black-magic-dpv3.md
new file mode 100644
index 00000000..0722f4bc
--- /dev/null
+++ b/changelog/added-black-magic-dpv3.md
@@ -0,0 +1,1 @@
+Added support for dpv3 for Black Magic Probes
diff --git a/changelog/added-black-magic-multi-drop.md b/changelog/added-black-magic-multi-drop.md
new file mode 100644
index 00000000..bed6a4ab
--- /dev/null
+++ b/changelog/added-black-magic-multi-drop.md
@@ -0,0 +1,1 @@
+Added multi-drop support for Black Magic Probes
diff --git a/changelog/added-config-presets.md b/changelog/added-config-presets.md
new file mode 100644
index 00000000..1ac4d24e
--- /dev/null
+++ b/changelog/added-config-presets.md
@@ -0,0 +1,1 @@
+Added config presets. Define a set of values in the probe-rs config file, and activate them all by using `--preset name_of_preset`.
\ No newline at end of file
diff --git a/changelog/added-errno-semihosting.md b/changelog/added-errno-semihosting.md
new file mode 100644
index 00000000..8f8f12bd
--- /dev/null
+++ b/changelog/added-errno-semihosting.md
@@ -0,0 +1,1 @@
+Probe-rs now handles (and ignores) the ERRNO semihosting command.
\ No newline at end of file
diff --git a/changelog/added-mspm0g151x-g351x-l122x-l222x.md b/changelog/added-mspm0g151x-g351x-l122x-l222x.md
new file mode 100644
index 00000000..9fe67efe
--- /dev/null
+++ b/changelog/added-mspm0g151x-g351x-l122x-l222x.md
@@ -0,0 +1,1 @@
+Added support for Texas Instruments MSPM0G151x/G351x/L122x/L222x series
diff --git a/changelog/fixed-cargo-embed-multicore.md b/changelog/fixed-cargo-embed-multicore.md
new file mode 100644
index 00000000..b2213b79
--- /dev/null
+++ b/changelog/fixed-cargo-embed-multicore.md
@@ -0,0 +1,1 @@
+Fixed cargo-embed panicking when a core is disabled.
\ No newline at end of file
diff --git a/probe-rs-tools/src/bin/probe-rs/main.rs b/probe-rs-tools/src/bin/probe-rs/main.rs
index 6aa8e389..b53be6e2 100644
--- a/probe-rs-tools/src/bin/probe-rs/main.rs
+++ b/probe-rs-tools/src/bin/probe-rs/main.rs
@@ -4,15 +4,17 @@ mod rpc;
 mod util;
 
 use std::cmp::Reverse;
+use std::collections::HashMap;
 use std::fs;
 use std::path::Path;
 use std::str::FromStr;
 use std::{ffi::OsString, path::PathBuf};
 
 use anyhow::{Context, Result};
-use clap::Parser;
+use clap::{ArgMatches, CommandFactory, FromArgMatches};
 use colored::Colorize;
 use figment::providers::{Data, Format as _, Json, Toml, Yaml};
+use figment::value::Value;
 use figment::Figment;
 use itertools::Itertools;
 use postcard_schema::Schema;
@@ -37,11 +39,16 @@ struct ServerUser {
     pub token: String,
 }
 
+type ConfigPreset = HashMap<String, Value>;
+
 #[derive(Debug, Default, Clone, Serialize, Deserialize)]
 #[serde(deny_unknown_fields)]
 pub(crate) struct Config {
     #[cfg(feature = "remote")]
     pub server_users: Vec<ServerUser>,
+
+    /// A named set of `--key=value` pairs.
+    pub presets: HashMap<String, ConfigPreset>,
 }
 
 #[derive(clap::Parser)]
@@ -94,6 +101,17 @@ struct Cli {
 
     #[clap(subcommand)]
     subcommand: Subcommand,
+
+    /// A configuration preset to apply.
+    ///
+    /// A preset is a list of command line arguments, that can be defined in the configuration file.
+    /// Presets can be used as a shortcut to specify any number of options, e.g. they can be used to
+    /// assign a name to a specific probe-chip pair.
+    ///
+    /// Manually specified command line arguments take overwrite presets, but presets
+    /// take precedence over environment variables.
+    #[arg(long, global = true, env = "PROBE_RS_CONFIG_PRESET")]
+    preset: Option<String>,
 }
 
 impl Cli {
@@ -407,7 +425,7 @@ async fn main() -> Result<()> {
     //        at this point we don't have a logger yet.
     let utc_offset = UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC);
 
-    let args: Vec<_> = std::env::args_os().collect();
+    let mut args: Vec<_> = std::env::args_os().collect();
 
     // Special-case `cargo-embed` and `cargo-flash`.
     if let Some(args) = multicall_check(&args, "cargo-flash") {
@@ -424,11 +442,23 @@ async fn main() -> Result<()> {
     let config = load_config().context("Failed to load configuration.")?;
 
     // Parse the commandline options.
-    let matches = Cli::parse_from(args);
+    let mut matches = Cli::command().get_matches_from(&args);
+
+    // Apply the configuration preset if one is specified.
+    if apply_config_preset(&config, &matches, &mut args)? {
+        // Re-parse the modified CLI input. Ignore errors so that users can specify
+        // options that are only valid for certain subcommands.
+        matches = Cli::command().ignore_errors(true).get_matches_from(args);
+    }
+
+    let cli = match Cli::from_arg_matches(&matches) {
+        Ok(matches) => matches,
+        Err(err) => err.exit(),
+    };
 
-    let log_path = if let Some(ref location) = matches.log_file {
+    let log_path = if let Some(ref location) = cli.log_file {
         Some(location.clone())
-    } else if matches.log_to_folder || matches.report.is_some() {
+    } else if cli.log_to_folder || cli.report.is_some() {
         // We always log if we create a report.
         let location =
             default_logfile_location().context("Unable to determine default log file location.")?;
@@ -445,27 +475,27 @@ async fn main() -> Result<()> {
 
     // the DAP server has special logging requirements. Run it before initializing logging,
     // so it can do its own special init.
-    if let Subcommand::DapServer(cmd) = matches.subcommand {
+    if let Subcommand::DapServer(cmd) = cli.subcommand {
         let lister = Lister::new();
         return cmd::dap_server::run(cmd, &lister, utc_offset, log_path);
     }
 
     let _logger_guard = setup_logging(log_path, None);
 
-    let elf = matches.elf();
-    let report_path = matches.report.clone();
+    let elf = cli.elf();
+    let report_path = cli.report.clone();
 
     #[cfg(feature = "remote")]
-    if let Some(host) = matches.host.as_deref() {
+    if let Some(host) = cli.host.as_deref() {
         // Run the command remotely.
-        let client = rpc::client::connect(host, matches.token.clone()).await?;
+        let client = rpc::client::connect(host, cli.token.clone()).await?;
 
         anyhow::ensure!(
-            matches.subcommand.is_remote_cmd(),
+            cli.subcommand.is_remote_cmd(),
             "The subcommand is not supported in remote mode."
         );
 
-        matches.run(client, config, utc_offset).await?;
+        cli.run(client, config, utc_offset).await?;
         // TODO: handle the report
         return Ok(());
     }
@@ -476,7 +506,7 @@ async fn main() -> Result<()> {
 
     // Run the command locally.
     let client = RpcClient::new_local_from_wire(tx, rx);
-    let result = matches.run(client, config, utc_offset).await;
+    let result = cli.run(client, config, utc_offset).await;
 
     // Wait for the server to shut down
     _ = handle.await.unwrap();
@@ -484,6 +514,57 @@ async fn main() -> Result<()> {
     compile_report(result, report_path, elf, log_path)
 }
 
+fn apply_config_preset(
+    config: &Config,
+    matches: &ArgMatches,
+    args: &mut Vec<OsString>,
+) -> anyhow::Result<bool> {
+    let Some(preset) = matches.get_one::<String>("preset") else {
+        // No --preset in the CLI arguments or environment variables.
+        return Ok(false);
+    };
+
+    let Some(preset) = config.presets.get(preset) else {
+        anyhow::bail!("Config preset '{preset}' not found.");
+    };
+
+    let mut args_modified = false;
+    for (arg, value) in preset {
+        let flag = format!("--{}", arg).into();
+        if args.contains(&flag) {
+            continue;
+        }
+
+        if let Value::Bool(_, false) = value {
+            continue;
+        }
+
+        // Append --flag. For booleans, this is all we do. For strings and
+        // numbers, we'll append a value as well.
+        args_modified = true;
+        args.push(flag);
+
+        match value {
+            Value::String(_, value) => args.push(value.into()),
+            Value::Num(_, num) => {
+                if let Some(uint) = num.to_u128() {
+                    args.push(format!("{}", uint).into())
+                } else if let Some(int) = num.to_i128() {
+                    args.push(format!("{}", int).into())
+                } else if let Some(float) = num.to_f64() {
+                    args.push(format!("{}", float).into())
+                } else {
+                    unreachable!()
+                }
+            }
+            Value::Bool(_, _) => {}
+            _ => anyhow::bail!("Unsupported value: {:?}", value),
+        }
+    }
+
+    Ok(args_modified)
+}
+
 fn reject_format_arg(args: &[OsString]) -> anyhow::Result<()> {
     if let Some(format_arg_pos) = args.iter().position(|arg| arg == "--format") {
         if let Some(format_arg) = args.get(format_arg_pos + 1) {
diff --git a/probe-rs-tools/src/bin/probe-rs/rpc/functions/monitor.rs b/probe-rs-tools/src/bin/probe-rs/rpc/functions/monitor.rs
index 0ce7834e..15a8f179 100644
--- a/probe-rs-tools/src/bin/probe-rs/rpc/functions/monitor.rs
+++ b/probe-rs-tools/src/bin/probe-rs/rpc/functions/monitor.rs
@@ -167,6 +167,7 @@ impl<F: FnMut(MonitorEvent)> MonitorEventHandler<F> {
                 tracing::warn!("Target wanted to run semihosting operation SYS_GET_CMDLINE, but probe-rs does not support this operation yet. Continuing...");
                 Ok(None) // Continue running
             }
+            SemihostingCommand::Errno(_) => Ok(None),
             other @ (SemihostingCommand::Open(_)
             | SemihostingCommand::Close(_)
             | SemihostingCommand::WriteConsole(_)
diff --git a/probe-rs-tools/src/bin/probe-rs/util/rtt/processing.rs b/probe-rs-tools/src/bin/probe-rs/util/rtt/processing.rs
index c513547d..458de08b 100644
--- a/probe-rs-tools/src/bin/probe-rs/util/rtt/processing.rs
+++ b/probe-rs-tools/src/bin/probe-rs/util/rtt/processing.rs
@@ -68,7 +68,11 @@ impl RttDecoder {
         buffer: &[u8],
         collector: &mut impl RttDataHandler,
     ) -> Result<(), Error> {
-        // FIXME: clean this up by splitting the enum variants out into separate structs
+        // Prevent the format processors generating empty strings.
+        if buffer.is_empty() {
+            return Ok(());
+        }
+
         match self {
             RttDecoder::BinaryLE => collector.on_binary_data(number, buffer),
             RttDecoder::String {
diff --git a/probe-rs/src/architecture/arm/ap/memory_ap/mock.rs b/probe-rs/src/architecture/arm/ap/memory_ap/mock.rs
index 2267f823..81c7d77c 100644
--- a/probe-rs/src/architecture/arm/ap/memory_ap/mock.rs
+++ b/probe-rs/src/architecture/arm/ap/memory_ap/mock.rs
@@ -3,7 +3,7 @@ use crate::architecture::arm::{
         memory_ap::amba_ahb3::CSW, AddressIncrement, ApClass, ApRegister, ApType, DataSize, CFG,
         DRW, IDR, TAR,
     },
-    communication_interface::FlushableArmAccess,
+    communication_interface::{DapProbe, FlushableArmAccess},
     dp::{DpAddress, DpRegisterAddress},
     ArmError, DapAccess,
 };
@@ -212,4 +212,8 @@ impl DapAccess for MockMemoryAp {
             _ => panic!("MockMemoryAp: unknown register"),
         }
     }
+
+    fn try_dap_probe(&self) -> Option<&dyn DapProbe> {
+        None
+    }
 }
diff --git a/probe-rs/src/architecture/arm/ap/v2/mod.rs b/probe-rs/src/architecture/arm/ap/v2/mod.rs
index 0fe9563d..22651720 100644
--- a/probe-rs/src/architecture/arm/ap/v2/mod.rs
+++ b/probe-rs/src/architecture/arm/ap/v2/mod.rs
@@ -9,15 +9,16 @@ use crate::architecture::arm::{
         romtable::{RomTable, CORESIGHT_ROM_TABLE_ARCHID},
         ADIMemoryInterface, ArmMemoryInterface, Component, PeripheralType,
     },
-    ApAddress, ApV2Address, ArmCommunicationInterface, ArmError, FullyQualifiedApAddress,
+    ApAddress, ApV2Address, ArmCommunicationInterface, ArmError, ArmProbeInterface,
+    FullyQualifiedApAddress,
 };
 
 mod root_memory_interface;
 use root_memory_interface::RootMemoryInterface;
 
 /// Deeply scans the debug port and returns a list of the addresses the memory access points discovered.
-pub fn enumerate_access_ports(
-    probe: &mut ArmCommunicationInterface<Initialized>,
+pub fn enumerate_access_ports<API: ArmProbeInterface>(
+    probe: &mut API,
     dp: DpAddress,
 ) -> Result<BTreeSet<FullyQualifiedApAddress>, ArmError> {
     let mut root_interface = RootMemoryInterface::new(probe, dp)?;
@@ -36,8 +37,8 @@ pub fn enumerate_access_ports(
         .collect())
 }
 
-fn process_root_component(
-    iface: &mut RootMemoryInterface<ArmCommunicationInterface<Initialized>>,
+fn process_root_component<API: ArmProbeInterface>(
+    iface: &mut RootMemoryInterface<API>,
     component: &Component,
 ) -> Result<BTreeSet<ApV2Address>, ArmError> {
     let mut result = BTreeSet::new();
diff --git a/probe-rs/src/architecture/arm/communication_interface.rs b/probe-rs/src/architecture/arm/communication_interface.rs
index d9a5bfba..71f5f3ad 100644
--- a/probe-rs/src/architecture/arm/communication_interface.rs
+++ b/probe-rs/src/architecture/arm/communication_interface.rs
@@ -193,18 +193,18 @@ impl ArmDebugState for Initialized {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum SelectCache {
+pub(crate) enum SelectCache {
     DPv1(SelectV1),
     DPv3(SelectV3, Select1),
 }
 impl SelectCache {
-    fn dp_bank_sel(&self) -> u8 {
+    pub fn dp_bank_sel(&self) -> u8 {
         match self {
             SelectCache::DPv1(s) => s.dp_bank_sel(),
             SelectCache::DPv3(s, _) => s.dp_bank_sel(),
         }
     }
-    fn set_dp_bank_sel(&mut self, bank: u8) {
+    pub fn set_dp_bank_sel(&mut self, bank: u8) {
         match self {
             SelectCache::DPv1(s) => s.set_dp_bank_sel(bank),
             SelectCache::DPv3(s, _) => s.set_dp_bank_sel(bank),
@@ -215,7 +215,7 @@ impl SelectCache {
 pub(crate) struct DpState {
     pub debug_port_version: DebugPortVersion,
 
-    current_select: SelectCache,
+    pub(crate) current_select: SelectCache,
 }
 
 impl DpState {
@@ -671,6 +671,10 @@ impl DapAccess for ArmCommunicationInterface<Initialized> {
     fn flush(&mut self) -> Result<(), ArmError> {
         self.probe_mut().raw_flush()
     }
+
+    fn try_dap_probe(&self) -> Option<&dyn DapProbe> {
+        self.probe.as_deref()
+    }
 }
 
 /// Information about the chip target we are currently attached to.
diff --git a/probe-rs/src/architecture/arm/dp/mod.rs b/probe-rs/src/architecture/arm/dp/mod.rs
index 0121cd92..11dc6732 100644
--- a/probe-rs/src/architecture/arm/dp/mod.rs
+++ b/probe-rs/src/architecture/arm/dp/mod.rs
@@ -137,7 +137,7 @@ pub trait DpAccess {
     ) -> Result<(), ArmError>;
 }
 
-impl<T: DapAccess> DpAccess for T {
+impl<T: ?Sized + DapAccess> DpAccess for T {
     #[tracing::instrument(skip(self))]
     fn read_dp_register<R: DpRegister>(&mut self, dp: DpAddress) -> Result<R, ArmError> {
         tracing::debug!("Reading DP register {}", R::NAME);
diff --git a/probe-rs/src/architecture/arm/sequences.rs b/probe-rs/src/architecture/arm/sequences.rs
index 37dacc1d..d574bcd6 100644
--- a/probe-rs/src/architecture/arm/sequences.rs
+++ b/probe-rs/src/architecture/arm/sequences.rs
@@ -23,7 +23,7 @@ use crate::{
 use super::{
     ap::AccessPortError,
     armv6m::Demcr,
-    communication_interface::{DapProbe, Initialized},
+    communication_interface::DapProbe,
     component::{TraceFunnel, TraceSink},
     core::cortex_m::{Dhcsr, Vtor},
     dp::{Abort, DpAccess, DpAddress, SelectV1, DPIDR},
@@ -31,7 +31,7 @@ use super::{
         romtable::{CoresightComponent, PeripheralType},
         ArmMemoryInterface,
     },
-    ArmCommunicationInterface, ArmError, FullyQualifiedApAddress, Pins,
+    ArmError, DapAccess, FullyQualifiedApAddress, Pins,
 };
 
 /// An error occurred when executing an ARM debug sequence
@@ -600,7 +600,7 @@ pub trait ArmDebugSequence: Send + Sync + Debug {
     #[doc(alias = "DebugPortStart")]
     fn debug_port_start(
         &self,
-        interface: &mut ArmCommunicationInterface<Initialized>,
+        interface: &mut dyn DapAccess,
         dp: DpAddress,
     ) -> Result<(), ArmError> {
         // Clear all errors.
diff --git a/probe-rs/src/architecture/arm/traits.rs b/probe-rs/src/architecture/arm/traits.rs
index ac9ef978..eb11c451 100644
--- a/probe-rs/src/architecture/arm/traits.rs
+++ b/probe-rs/src/architecture/arm/traits.rs
@@ -4,6 +4,7 @@ use crate::{
 };
 
 use super::{
+    communication_interface::DapProbe,
     dp::{DpAddress, DpRegisterAddress},
     ArmError,
 };
@@ -420,4 +421,7 @@ pub trait DapAccess {
     fn flush(&mut self) -> Result<(), ArmError> {
         Ok(())
     }
+
+    /// Gain access to the Probe that implements this trait
+    fn try_dap_probe(&self) -> Option<&dyn DapProbe>;
 }
diff --git a/probe-rs/src/flashing/download.rs b/probe-rs/src/flashing/download.rs
index f3c3a90c..371bae87 100644
--- a/probe-rs/src/flashing/download.rs
+++ b/probe-rs/src/flashing/download.rs
@@ -157,6 +157,9 @@ pub enum FileDownloadError {
         /// The image's instruction set.
         image: InstructionSet,
     },
+
+    /// An error occurred during download.
+    Other(#[source] crate::Error),
 }
 
 fn print_instr_sets(instr_sets: &[InstructionSet]) -> String {
diff --git a/probe-rs/src/flashing/loader.rs b/probe-rs/src/flashing/loader.rs
index eb319906..e3c779b9 100644
--- a/probe-rs/src/flashing/loader.rs
+++ b/probe-rs/src/flashing/loader.rs
@@ -412,10 +412,16 @@ impl FlashLoader {
 
             // Get a unique list of core architectures
             for (core, _) in session.list_cores() {
-                if let Ok(set) = session.core(core).unwrap().instruction_set() {
-                    if !target_archs.contains(&set) {
-                        target_archs.push(set);
+                match session.core(core) {
+                    Ok(mut core) => {
+                        if let Ok(set) = core.instruction_set() {
+                            if !target_archs.contains(&set) {
+                                target_archs.push(set);
+                            }
+                        }
                     }
+                    Err(crate::Error::CoreDisabled(_)) => continue,
+                    Err(error) => return Err(FileDownloadError::Other(error)),
                 }
             }
 
diff --git a/probe-rs/src/gdb_server/target/monitor.rs b/probe-rs/src/gdb_server/target/monitor.rs
index 891ce317..597e0c69 100644
--- a/probe-rs/src/gdb_server/target/monitor.rs
+++ b/probe-rs/src/gdb_server/target/monitor.rs
@@ -18,38 +18,24 @@ impl MonitorCmd for RuntimeTarget<'_> {
         cmd: &[u8],
         mut out: gdbstub::target::ext::monitor_cmd::ConsoleOutput<'_>,
     ) -> Result<(), Self::Error> {
-        let cmd = String::from_utf8_lossy(cmd);
-
-        match cmd.as_ref() {
-            "info" => {
-                outputln!(out, "Target info:\n\n{:#?}", self.session.lock().target());
-            }
-            "reset" => {
+        match cmd {
+            b"info" => outputln!(out, "Target info:\n\n{:#?}", self.session.lock().target()),
+            b"reset" => {
                 outputln!(out, "Resetting target");
                 match self.session.lock().core(0)?.reset() {
-                    Ok(_) => {
-                        outputln!(out, "Done")
-                    }
-                    Err(e) => {
-                        outputln!(out, "Error while resetting target:\n\t{}", e)
-                    }
+                    Ok(_) => outputln!(out, "Done"),
+                    Err(e) => outputln!(out, "Error while resetting target:\n\t{}", e),
                 }
             }
-            "reset halt" => {
+            b"reset halt" => {
                 let timeout = Duration::from_secs(1);
                 outputln!(out, "Resetting and halting target");
                 match self.session.lock().core(0)?.reset_and_halt(timeout) {
-                    Ok(_) => {
-                        outputln!(out, "Target halted")
-                    }
-                    Err(e) => {
-                        outputln!(out, "Error while halting target:\n\t{}", e)
-                    }
+                    Ok(_) => outputln!(out, "Target halted"),
+                    Err(e) => outputln!(out, "Error while halting target:\n\t{}", e),
                 }
             }
-            _ => {
-                outputln!(out, "{}", HELP_TEXT);
-            }
+            _ => outputln!(out, "{}", HELP_TEXT),
         }
 
         Ok(())
diff --git a/probe-rs/src/probe/blackmagic/arm.rs b/probe-rs/src/probe/blackmagic/arm.rs
index 42ba564b..a2ba6cc9 100644
--- a/probe-rs/src/probe/blackmagic/arm.rs
+++ b/probe-rs/src/probe/blackmagic/arm.rs
@@ -1,11 +1,15 @@
 use crate::architecture::arm::{
     ap::{
+        self,
         memory_ap::{MemoryAp, MemoryApType},
         v1::valid_access_ports,
         AccessPortType, AddressIncrement, DataSize, CSW,
     },
-    communication_interface::{SwdSequence, UninitializedArmProbe},
-    dp::{Abort, Ctrl, DebugPortError, DpAccess, DpAddress, DpRegisterAddress, SelectV1},
+    communication_interface::{DapProbe, DpState, SelectCache, SwdSequence, UninitializedArmProbe},
+    dp::{
+        Ctrl, DebugPortError, DebugPortId, DebugPortVersion, DpAccess, DpAddress,
+        DpRegisterAddress, Select1, SelectV3, DPIDR,
+    },
     memory::ArmMemoryInterface,
     sequences::ArmDebugSequence,
     ArmProbeInterface, DapAccess, FullyQualifiedApAddress, RawDapAccess, SwoAccess,
@@ -13,9 +17,9 @@ use crate::architecture::arm::{
 use crate::probe::blackmagic::{Align, BlackMagicProbe, ProtocolVersion, RemoteCommand};
 use crate::probe::{ArmError, DebugProbeError, Probe};
 use crate::{Error as ProbeRsError, MemoryInterface};
+use std::collections::hash_map;
 use std::collections::BTreeSet;
-use std::sync::Arc;
-use std::time::{Duration, Instant};
+use std::{collections::HashMap, sync::Arc};
 use zerocopy::IntoBytes;
 
 #[derive(Debug)]
@@ -33,6 +37,15 @@ pub(crate) struct BlackMagicProbeArmDebug {
 
     /// A copy of the sequence that was passed during initialization
     sequence: Arc<dyn ArmDebugSequence>,
+
+    /// The currently selected Debug Port. Used for multi-drop targets.
+    current_dp: DpAddress,
+
+    /// A list of all discovered Debug Ports.
+    dps: HashMap<DpAddress, DpState>,
+
+    /// Whether to enable a hardware feature to detect overruns
+    use_overrun_detect: bool,
 }
 
 #[derive(Debug)]
@@ -51,24 +64,16 @@ impl UninitializedBlackMagicArmProbe {
 }
 
 impl UninitializedArmProbe for UninitializedBlackMagicArmProbe {
-    #[tracing::instrument(level = "trace", skip(self, sequence))]
     fn initialize(
         mut self: Box<Self>,
         sequence: Arc<dyn ArmDebugSequence>,
         dp: DpAddress,
     ) -> Result<Box<dyn ArmProbeInterface>, (Box<dyn UninitializedArmProbe>, ProbeRsError)> {
         // Switch to the correct mode
-        if let Err(e) = sequence.debug_port_setup(&mut *self.probe, dp) {
-            return Err((self, e.into()));
-        }
-
-        if let Err(e) = sequence.debug_port_connect(&mut *self.probe, dp) {
-            tracing::warn!("failed to switch to DP {:x?}: {}", dp, e);
-
-            // Try the more involved debug_port_setup sequence, which also handles dormant mode.
-            if let Err(e) = sequence.debug_port_setup(&mut *self.probe, dp) {
-                return Err((self, ProbeRsError::Arm(e)));
-            }
+        if let Err(err) = tracing::debug_span!("debug_port_setup")
+            .in_scope(|| sequence.debug_port_setup(&mut *self.probe, dp))
+        {
+            return Err((self, err.into()));
         }
 
         let interface = BlackMagicProbeArmDebug::new(self.probe, dp, sequence)
@@ -107,9 +112,12 @@ impl BlackMagicProbeArmDebug {
             probe,
             access_ports: BTreeSet::new(),
             sequence,
+            current_dp: dp,
+            dps: HashMap::new(),
+            use_overrun_detect: true,
         };
 
-        if let Err(e) = interface.debug_port_start(dp) {
+        if let Err(e) = interface.select_dp(dp) {
             return Err((
                 Box::new(UninitializedBlackMagicArmProbe {
                     probe: interface.probe,
@@ -118,7 +126,7 @@ impl BlackMagicProbeArmDebug {
             ));
         }
 
-        interface.access_ports = valid_access_ports(&mut interface, DpAddress::Default)
+        interface.access_ports = valid_access_ports(&mut interface, dp)
             .into_iter()
             .inspect(|addr| tracing::debug!("AP {:#x?}", addr))
             .collect();
@@ -130,63 +138,129 @@ impl BlackMagicProbeArmDebug {
     ///
     /// [ARM SVD Debug Description]: https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/debug_description.html#debugPortStart
     fn debug_port_start(&mut self, dp: DpAddress) -> Result<(), ArmError> {
-        // Clear all errors.
-        // CMSIS says this is only necessary to do inside the `if powered_down`, but
-        // without it here, nRF52840 faults in the next access.
-        let mut abort = Abort(0);
-        abort.set_dapabort(true);
-        abort.set_orunerrclr(true);
-        abort.set_wderrclr(true);
-        abort.set_stkerrclr(true);
-        abort.set_stkcmpclr(true);
-        self.write_dp_register(dp, abort)?;
-
-        self.write_dp_register(dp, SelectV1(0))?;
-
-        let ctrl = self.read_dp_register::<Ctrl>(dp)?;
-
-        let powered_down = !(ctrl.csyspwrupack() && ctrl.cdbgpwrupack());
-
-        if powered_down {
-            let mut ctrl = Ctrl(0);
-            ctrl.set_cdbgpwrupreq(true);
-            ctrl.set_csyspwrupreq(true);
-            self.write_dp_register(dp, ctrl.clone())?;
-
-            let start = Instant::now();
-            loop {
-                let ctrl = self.read_dp_register::<Ctrl>(dp)?;
-                if ctrl.csyspwrupack() && ctrl.cdbgpwrupack() {
-                    break;
-                }
-                if start.elapsed() >= Duration::from_secs(1) {
-                    return Err(ArmError::Timeout);
-                }
-                std::thread::sleep(Duration::from_millis(10));
-            }
+        self.sequence.clone().debug_port_start(self, dp)
+    }
+
+    fn select_dp(&mut self, dp: DpAddress) -> Result<&mut DpState, ArmError> {
+        let mut switched_dp = false;
 
-            // TODO: Handle JTAG Specific part
+        let sequence = self.sequence.clone();
 
-            // TODO: Only run the following code when the SWD protocol is used
+        if self.current_dp != dp {
+            tracing::debug!("Selecting DP {:x?}", dp);
 
-            // Init AP Transfer Mode, Transaction Counter, and Lane Mask (Normal Transfer Mode, Include all Byte Lanes)
-            let mut ctrl = Ctrl(0);
-            ctrl.set_cdbgpwrupreq(true);
-            ctrl.set_csyspwrupreq(true);
-            ctrl.set_mask_lane(0b1111);
-            self.write_dp_register(dp, ctrl)?;
+            switched_dp = true;
 
-            let ctrl_reg: Ctrl = self.read_dp_register(dp)?;
-            if !(ctrl_reg.csyspwrupack() && ctrl_reg.cdbgpwrupack()) {
-                tracing::error!("debug power-up request failed");
-                return Err(DebugPortError::TargetPowerUpFailed.into());
+            self.probe.raw_flush()?;
+
+            // Try to switch to the new DP.
+            if let Err(e) = sequence.debug_port_connect(&mut *self.probe, dp) {
+                tracing::warn!("Failed to switch to DP {:x?}: {}", dp, e);
+
+                // Try the more involved debug_port_setup sequence, which also handles dormant mode.
+                sequence.debug_port_setup(&mut *self.probe, dp)?;
+            }
+
+            self.current_dp = dp;
+        }
+
+        // If we don't have  a state for this DP, this means that we haven't run the necessary init sequence yet.
+        if let hash_map::Entry::Vacant(entry) = self.dps.entry(dp) {
+            let sequence = self.sequence.clone();
+
+            entry.insert(DpState::new());
+
+            let start_span = tracing::debug_span!("debug_port_start").entered();
+            sequence.debug_port_start(self, dp)?;
+            drop(start_span);
+
+            // Make sure we enable the overrun detect mode when requested.
+            // For "bit-banging" probes, such as JLink or FTDI, we rely on it for good, stable communication.
+            // This is required as the default sequence (and most special implementations) does not do this.
+            let mut ctrl_reg: Ctrl = self.read_dp_register(dp)?;
+            if ctrl_reg.orun_detect() != self.use_overrun_detect {
+                tracing::debug!("Setting orun_detect: {}", self.use_overrun_detect);
+                // only write if there’s a need for it.
+                ctrl_reg.set_orun_detect(self.use_overrun_detect);
+                self.write_dp_register(dp, ctrl_reg)?;
+            }
+
+            let idr: DebugPortId = self.read_dp_register::<DPIDR>(dp)?.into();
+            tracing::info!(
+                "Debug Port version: {} MinDP: {:?}",
+                idr.version,
+                idr.min_dp_support
+            );
+
+            let state = self
+                .dps
+                .get_mut(&dp)
+                .expect("This DP State was inserted earlier in this function");
+            state.debug_port_version = idr.version;
+            if idr.version == DebugPortVersion::DPv3 {
+                state.current_select = SelectCache::DPv3(SelectV3(0), Select1(0));
             }
+        } else if switched_dp {
+            let sequence = self.sequence.clone();
 
-            // According to CMSIS docs, here's where we would clear errors
-            // in ABORT, but we do that above instead.
+            let start_span = tracing::debug_span!("debug_port_start").entered();
+            sequence.debug_port_start(self, dp)?;
+            drop(start_span);
         }
+
+        // note(unwrap): Entry gets inserted above
+        Ok(self.dps.get_mut(&dp).unwrap())
+    }
+
+    fn select_dp_and_dp_bank(
+        &mut self,
+        dp: DpAddress,
+        dp_register_address: &DpRegisterAddress,
+    ) -> Result<(), ArmError> {
+        let dp_state = self.select_dp(dp)?;
+
+        // DP register addresses are 4 bank bits, 4 address bits. Lowest 2 address bits are
+        // always 0, so this leaves only 4 possible addresses: 0x0, 0x4, 0x8, 0xC.
+        // On ADIv5, only address 0x4 is banked, the rest are don't care.
+        // On ADIv6, address 0x0 and 0x4 are banked, the rest are don't care.
+
+        let &DpRegisterAddress {
+            bank,
+            address: addr,
+        } = dp_register_address;
+
+        if addr != 0 && addr != 4 {
+            return Ok(());
+        }
+
+        let bank = bank.unwrap_or(0);
+
+        if bank != dp_state.current_select.dp_bank_sel() {
+            dp_state.current_select.set_dp_bank_sel(bank);
+
+            tracing::debug!("Changing DP_BANK_SEL to {:x?}", dp_state.current_select);
+
+            match dp_state.current_select {
+                SelectCache::DPv1(select) => self.write_dp_register(dp, select)?,
+                SelectCache::DPv3(select, _) => self.write_dp_register(dp, select)?,
+            }
+        }
+
         Ok(())
     }
+
+    fn select_ap(&mut self, ap: &FullyQualifiedApAddress) -> Result<u8, ArmError> {
+        let apsel = match ap.ap() {
+            crate::architecture::arm::ApAddress::V1(val) => *val,
+            crate::architecture::arm::ApAddress::V2(_) => {
+                return Err(ArmError::NotImplemented(
+                    "AP address v2 currently unsupported",
+                ))
+            }
+        };
+        self.select_dp(ap.dp())?;
+        Ok(apsel)
+    }
 }
 
 impl ArmProbeInterface for BlackMagicProbeArmDebug {
@@ -194,11 +268,14 @@ impl ArmProbeInterface for BlackMagicProbeArmDebug {
         &mut self,
         dp: DpAddress,
     ) -> Result<BTreeSet<FullyQualifiedApAddress>, ArmError> {
-        if dp != DpAddress::Default {
-            return Err(ArmError::NotImplemented("multidrop not yet implemented"));
+        let state = self.select_dp(dp)?;
+        match state.debug_port_version {
+            DebugPortVersion::DPv0 | DebugPortVersion::DPv1 | DebugPortVersion::DPv2 => {
+                Ok(ap::v1::valid_access_ports(self, dp).into_iter().collect())
+            }
+            DebugPortVersion::DPv3 => ap::v2::enumerate_access_ports(self, dp),
+            DebugPortVersion::Unsupported(_) => unreachable!(),
         }
-
-        Ok(self.access_ports.clone())
     }
 
     fn close(self: Box<Self>) -> Probe {
@@ -390,32 +467,14 @@ impl SwdSequence for BlackMagicProbeArmDebug {
     }
 }
 
-fn dp_to_bmp(dp: DpAddress) -> Result<u8, ArmError> {
-    match dp {
-        DpAddress::Default => Ok(0),
-        DpAddress::Multidrop(val) => val.try_into().map_err(|_| ArmError::OutOfBounds),
-    }
-}
-
-fn ap_to_bmp(ap: &FullyQualifiedApAddress) -> Result<(u8, u8), ArmError> {
-    let apsel = match ap.ap() {
-        crate::architecture::arm::ApAddress::V1(val) => *val,
-        crate::architecture::arm::ApAddress::V2(_) => {
-            return Err(ArmError::NotImplemented(
-                "AP address v2 currently unsupported",
-            ))
-        }
-    };
-    Ok((dp_to_bmp(ap.dp())?, apsel))
-}
-
 impl DapAccess for BlackMagicProbeArmDebug {
     fn read_raw_dp_register(
         &mut self,
         dp: DpAddress,
-        addr: DpRegisterAddress,
+        address: DpRegisterAddress,
     ) -> Result<u32, ArmError> {
-        let index = dp_to_bmp(dp)?;
+        self.select_dp_and_dp_bank(dp, &address)?;
+        let index = 0;
         let command = match self.probe.remote_protocol {
             ProtocolVersion::V0 => {
                 return Err(ArmError::Probe(
@@ -424,14 +483,16 @@ impl DapAccess for BlackMagicProbeArmDebug {
                     },
                 ));
             }
-            ProtocolVersion::V0P => RemoteCommand::ReadDpV0P { addr: addr.into() },
+            ProtocolVersion::V0P => RemoteCommand::ReadDpV0P {
+                addr: address.into(),
+            },
             ProtocolVersion::V1 | ProtocolVersion::V2 => RemoteCommand::ReadDpV1 {
                 index,
-                addr: addr.into(),
+                addr: address.into(),
             },
             ProtocolVersion::V3 | ProtocolVersion::V4 => RemoteCommand::ReadDpV3 {
                 index,
-                addr: addr.into(),
+                addr: address.into(),
             },
         };
         Ok(u32::from_be(
@@ -448,10 +509,11 @@ impl DapAccess for BlackMagicProbeArmDebug {
     fn write_raw_dp_register(
         &mut self,
         dp: DpAddress,
-        addr: DpRegisterAddress,
+        address: DpRegisterAddress,
         value: u32,
     ) -> Result<(), ArmError> {
-        let index = dp_to_bmp(dp)?;
+        self.select_dp_and_dp_bank(dp, &address)?;
+        let index = 0;
         let command = match self.probe.remote_protocol {
             ProtocolVersion::V0 => {
                 return Err(ArmError::Probe(
@@ -462,19 +524,19 @@ impl DapAccess for BlackMagicProbeArmDebug {
             }
             ProtocolVersion::V0P => RemoteCommand::RawAccessV0P {
                 rnw: 0,
-                addr: addr.into(),
+                addr: address.into(),
                 value,
             },
             ProtocolVersion::V1 | ProtocolVersion::V2 => RemoteCommand::RawAccessV1 {
                 index,
                 rnw: 0,
-                addr: addr.into(),
+                addr: address.into(),
                 value,
             },
             ProtocolVersion::V3 | ProtocolVersion::V4 => RemoteCommand::RawAccessV3 {
                 index,
                 rnw: 0,
-                addr: addr.into(),
+                addr: address.into(),
                 value,
             },
         };
@@ -504,9 +566,9 @@ impl DapAccess for BlackMagicProbeArmDebug {
                 "BlackMagicProbe does not yet support APv2",
             ));
         }
+        let index = ((addr >> 8) & 0xFF) as u8;
         let addr = (addr & 0xFF) as u8;
-
-        let (index, apsel) = ap_to_bmp(ap)?;
+        let apsel = self.select_ap(ap)?;
 
         let command = match self.probe.remote_protocol {
             ProtocolVersion::V0 => {
@@ -548,9 +610,10 @@ impl DapAccess for BlackMagicProbeArmDebug {
                 "BlackMagicProbe does not yet support APv2",
             ));
         }
+        let index = ((addr >> 8) & 0xFF) as u8;
         let addr = (addr & 0xFF) as u8;
 
-        let (index, apsel) = ap_to_bmp(ap)?;
+        let apsel = self.select_ap(ap)?;
         let command = match self.probe.remote_protocol {
             ProtocolVersion::V0 => {
                 return Err(ArmError::Probe(
@@ -588,6 +651,10 @@ impl DapAccess for BlackMagicProbeArmDebug {
             ))))
         }
     }
+
+    fn try_dap_probe(&self) -> Option<&dyn DapProbe> {
+        Some(&*self.probe)
+    }
 }
 
 impl ArmMemoryInterface for BlackMagicProbeMemoryInterface<'_> {
diff --git a/probe-rs/src/probe/blackmagic/mod.rs b/probe-rs/src/probe/blackmagic/mod.rs
index fd93e7c4..5720c95c 100644
--- a/probe-rs/src/probe/blackmagic/mod.rs
+++ b/probe-rs/src/probe/blackmagic/mod.rs
@@ -89,7 +89,7 @@ enum RemoteCommand<'a> {
     TargetClockOutput {
         enable: bool,
     },
-    SetSpeedKhz(u32),
+    SetSpeedHz(u32),
     SpeedKhz,
     TargetReset(bool),
     RawAccessV0P {
@@ -285,7 +285,7 @@ impl std::string::ToString for RemoteCommand<'_> {
             RemoteCommand::Handshake(_) => "+#!GA#".to_string(),
             RemoteCommand::GetVoltage => " !GV#".to_string(),
             RemoteCommand::GetSpeedKhz => "!Gf#".to_string(),
-            RemoteCommand::SetSpeedKhz(speed) => {
+            RemoteCommand::SetSpeedHz(speed) => {
                 format!("!GF{:08x}#", speed)
             }
             RemoteCommand::HighLevelCheck => "!HC#".to_string(),
@@ -690,7 +690,7 @@ impl BlackMagicProbe {
         probe.command(RemoteCommand::SetPower(false)).ok();
         probe.command(RemoteCommand::SetNrst(false)).ok();
         probe.command(RemoteCommand::GetVoltage).ok();
-        probe.command(RemoteCommand::SetSpeedKhz(400_0000)).ok();
+        probe.command(RemoteCommand::SetSpeedHz(400_0000)).ok();
         probe.command(RemoteCommand::GetSpeedKhz).ok();
 
         Ok(probe)
@@ -1030,7 +1030,7 @@ impl DebugProbe for BlackMagicProbe {
     }
 
     fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
-        Self::send(&mut self.writer, &RemoteCommand::SetSpeedKhz(speed_khz))?;
+        self.command(RemoteCommand::SetSpeedHz(speed_khz * 1000))?;
         self.speed_khz = self.get_speed()?;
         Ok(self.speed_khz)
     }
@@ -1042,7 +1042,7 @@ impl DebugProbe for BlackMagicProbe {
     }
 
     fn scan_chain(&self) -> Result<&[ScanChainElement], DebugProbeError> {
-        match self.active_protocol() {
+        match DebugProbe::active_protocol(self) {
             Some(WireProtocol::Jtag) => {
                 if let Some(ref chain) = self.jtag_state.expected_scan_chain {
                     Ok(chain.as_slice())
@@ -1396,10 +1396,14 @@ fn black_magic_debug_port_info(
     // Only accept /dev/cu.* values on macos, to avoid having two
     // copies of the port (both /dev/tty.* and /dev/cu.*)
     if cfg!(target_os = "macos") && !port_name.contains("/cu.") {
+        tracing::trace!(
+            "{}: port name doesn't contain `/cu.` -- skipping",
+            port_name
+        );
         return None;
     }
 
-    let (vendor_id, product_id, serial_number, hid_interface, identifier) = match port_type {
+    let (vendor_id, product_id, serial_number, mut interface, identifier) = match port_type {
         SerialPortType::UsbPort(info) => (
             info.vid,
             info.pid,
@@ -1408,29 +1412,72 @@ fn black_magic_debug_port_info(
             info.product
                 .unwrap_or_else(|| "Black Magic Probe".to_string()),
         ),
-        _ => return None,
+        _ => {
+            tracing::trace!(
+                "{}: serial port {:?} is not USB -- skipping",
+                port_name,
+                port_type,
+            );
+            return None;
+        }
     };
 
     if vendor_id != BLACK_MAGIC_PROBE_VID {
+        tracing::trace!(
+            "{}: vid is {:04x}, not {:04x} -- skipping",
+            port_name,
+            vendor_id,
+            BLACK_MAGIC_PROBE_VID
+        );
         return None;
     }
+
     if product_id != BLACK_MAGIC_PROBE_PID {
+        tracing::trace!(
+            "{}: pid is {:04x}, not {:04x} -- skipping",
+            port_name,
+            product_id,
+            BLACK_MAGIC_PROBE_PID
+        );
         return None;
     }
 
+    // The `interface` property has been observed on Mac to occasionally be `None`.
+    // This shouldn't happen on any known devices. If this happens, derive the
+    // interface number from the last character of the filename.
+    if cfg!(target_os = "macos") && interface.is_none() {
+        tracing::warn!(
+            "{}: interface number is `None` -- applying interface number workaround",
+            port_name
+        );
+        interface = port_name.as_bytes().last().map(|v| *v - b'0');
+    }
+
     // Mac specifies the interface as the CDC Data interface, whereas Linux and
     // Windows use the CDC Communications interface. Accept either one here.
-    if hid_interface != Some(0) && hid_interface != Some(1) {
+    if interface != Some(0) && interface != Some(1) {
+        tracing::trace!(
+            "{}: interface is {:?}, not Some(0) or Some(1) -- skipping",
+            port_name,
+            interface
+        );
         return None;
     }
 
+    tracing::debug!(
+        "{}: returning port {}:{}:{:?}",
+        port_name,
+        vendor_id,
+        product_id,
+        serial_number
+    );
     Some(DebugProbeInfo {
         identifier,
         vendor_id,
         product_id,
         serial_number,
         probe_factory: &BlackMagicProbeFactory,
-        hid_interface,
+        hid_interface: interface,
     })
 }
 
@@ -1443,6 +1490,13 @@ impl ProbeFactory for BlackMagicProbeFactory {
         if selector.vendor_id != BLACK_MAGIC_PROBE_VID
             || selector.product_id != BLACK_MAGIC_PROBE_PID
         {
+            tracing::trace!(
+                "{:04x}:{:04x} doesn't match BMP VID/PID {:04x}:{:04x}",
+                selector.vendor_id,
+                selector.product_id,
+                BLACK_MAGIC_PROBE_VID,
+                BLACK_MAGIC_PROBE_PID
+            );
             return Err(DebugProbeError::ProbeCouldNotBeCreated(
                 ProbeCreationError::NotFound,
             ));
@@ -1463,6 +1517,7 @@ impl ProbeFactory for BlackMagicProbeFactory {
 
         // Otherwise, treat it as a serial port and iterate through all ports.
         let Ok(ports) = available_ports() else {
+            tracing::trace!("unable to get available serial ports");
             return Err(DebugProbeError::ProbeCouldNotBeCreated(
                 ProbeCreationError::CouldNotOpen,
             ));
@@ -1476,7 +1531,12 @@ impl ProbeFactory for BlackMagicProbeFactory {
                 continue;
             };
 
-            if selector.serial_number != info.serial_number {
+            if selector.serial_number.is_some() && selector.serial_number != info.serial_number {
+                tracing::trace!(
+                    "serial number {:?} doesn't match requested number {:?}",
+                    info.serial_number,
+                    selector.serial_number
+                );
                 continue;
             }
 
@@ -1503,6 +1563,7 @@ impl ProbeFactory for BlackMagicProbeFactory {
                 .map(|p| Box::new(p) as Box<dyn DebugProbe>);
         }
 
+        tracing::trace!("unable to find port {:?}", selector);
         Err(DebugProbeError::ProbeCouldNotBeCreated(
             ProbeCreationError::NotFound,
         ))
@@ -1510,9 +1571,14 @@ impl ProbeFactory for BlackMagicProbeFactory {
 
     fn list_probes(&self) -> Vec<super::DebugProbeInfo> {
         let mut probes = vec![];
-        let Ok(ports) = available_ports() else {
-            return probes;
+        let ports = match available_ports() {
+            Ok(ports) => ports,
+            Err(e) => {
+                tracing::trace!("Unable to enumerate serial ports: {}", e);
+                return probes;
+            }
         };
+
         for port in ports {
             let Some(info) = black_magic_debug_port_info(port.port_type, &port.port_name) else {
                 continue;
diff --git a/probe-rs/src/probe/fake_probe.rs b/probe-rs/src/probe/fake_probe.rs
index da8865ce..c245a148 100644
--- a/probe-rs/src/probe/fake_probe.rs
+++ b/probe-rs/src/probe/fake_probe.rs
@@ -4,7 +4,7 @@ use crate::{
         ap::memory_ap::mock::MockMemoryAp,
         armv8m::Dhcsr,
         communication_interface::{
-            ArmDebugState, Initialized, SwdSequence, Uninitialized, UninitializedArmProbe,
+            ArmDebugState, DapProbe, Initialized, SwdSequence, Uninitialized, UninitializedArmProbe,
         },
         dp::{DpAddress, DpRegisterAddress},
         memory::{ADIMemoryInterface, ArmMemoryInterface},
@@ -768,6 +768,10 @@ impl DapAccess for FakeArmInterface<Initialized> {
     ) -> Result<(), ArmError> {
         todo!()
     }
+
+    fn try_dap_probe(&self) -> Option<&dyn DapProbe> {
+        None
+    }
 }
 
 #[cfg(all(test, feature = "builtin-targets"))]
diff --git a/probe-rs/src/probe/stlink/mod.rs b/probe-rs/src/probe/stlink/mod.rs
index 5126fa31..26f24943 100644
--- a/probe-rs/src/probe/stlink/mod.rs
+++ b/probe-rs/src/probe/stlink/mod.rs
@@ -11,7 +11,9 @@ use crate::{
             v1::valid_access_ports,
             AccessPortType,
         },
-        communication_interface::{ArmProbeInterface, SwdSequence, UninitializedArmProbe},
+        communication_interface::{
+            ArmProbeInterface, DapProbe, SwdSequence, UninitializedArmProbe,
+        },
         dp::{DpAddress, DpRegisterAddress},
         memory::ArmMemoryInterface,
         sequences::ArmDebugSequence,
@@ -1444,6 +1446,10 @@ impl DapAccess for StlinkArmDebug {
 
         Ok(())
     }
+
+    fn try_dap_probe(&self) -> Option<&dyn DapProbe> {
+        None
+    }
 }
 
 impl ArmProbeInterface for StlinkArmDebug {
diff --git a/probe-rs/src/semihosting.rs b/probe-rs/src/semihosting.rs
index 81ed67dc..d583f6f4 100644
--- a/probe-rs/src/semihosting.rs
+++ b/probe-rs/src/semihosting.rs
@@ -32,6 +32,9 @@ pub enum SemihostingCommand {
     /// The target indicated that it would like to write to the console.
     Write(WriteRequest),
 
+    /// The target indicated that it would like to read the value of errno.
+    Errno(ErrnoRequest),
+
     /// The target indicated that it would like to run a semihosting operation which we don't support yet.
     Unknown(UnknownCommandDetails),
 }
@@ -194,6 +197,17 @@ impl WriteRequest {
     }
 }
 
+/// A request to read the errno
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+pub struct ErrnoRequest {}
+impl ErrnoRequest {
+    /// Writes the errno to the target
+    pub fn write_errno(&self, core: &mut dyn CoreInterface, errno: i32) -> Result<(), Error> {
+        // On exit, the RETURN REGISTER contains the value of the C library errno variable.
+        write_status(core, errno)
+    }
+}
+
 fn write_status(core: &mut dyn CoreInterface, value: i32) -> Result<(), crate::Error> {
     let reg = core.registers().get_argument_register(0).unwrap();
     core.write_core_reg(reg.into(), RegisterValue::U32(value as u32))?;
@@ -309,6 +323,7 @@ pub fn decode_semihosting_syscall(
     const SYS_WRITEC: u32 = 0x03;
     const SYS_WRITE0: u32 = 0x04;
     const SYS_WRITE: u32 = 0x05;
+    const SYS_ERRNO: u32 = 0x13;
 
     Ok(match (operation, parameter) {
         (SYS_EXIT, SYS_EXIT_ADP_STOPPED_APPLICATIONEXIT) => SemihostingCommand::ExitSuccess,
@@ -410,6 +425,8 @@ pub fn decode_semihosting_syscall(
             SemihostingCommand::Write(WriteRequest { handle, bytes, len })
         }
 
+        (SYS_ERRNO, 0) => SemihostingCommand::Errno(ErrnoRequest {}),
+
         _ => {
             // signal to target: status = failure, in case the application does not answer this request
             // It is not guaranteed that a value of -1 will be treated as an error by the target, but it is a common value to indicate an error.
diff --git a/probe-rs/src/vendor/nxp/sequences/mcx.rs b/probe-rs/src/vendor/nxp/sequences/mcx.rs
index 0bdd7ac8..040f8e8f 100644
--- a/probe-rs/src/vendor/nxp/sequences/mcx.rs
+++ b/probe-rs/src/vendor/nxp/sequences/mcx.rs
@@ -13,12 +13,10 @@ use probe_rs_target::CoreType;
 use crate::{
     architecture::arm::{
         ap::ApRegister,
-        communication_interface::Initialized,
         dp::{DpAccess, DpAddress, DpRegister},
         memory::ArmMemoryInterface,
         sequences::ArmDebugSequence,
-        ArmCommunicationInterface, ArmError, ArmProbeInterface, DapAccess, FullyQualifiedApAddress,
-        Pins,
+        ArmError, ArmProbeInterface, DapAccess, FullyQualifiedApAddress, Pins,
     },
     probe::WireProtocol,
     MemoryMappedRegister,
@@ -217,7 +215,7 @@ impl MCX {
 impl ArmDebugSequence for MCX {
     fn debug_port_start(
         &self,
-        interface: &mut ArmCommunicationInterface<Initialized>,
+        interface: &mut dyn DapAccess,
         dp: DpAddress,
     ) -> Result<(), ArmError> {
         use crate::architecture::arm::dp::{Abort, Ctrl, SelectV1};
@@ -261,7 +259,7 @@ impl ArmDebugSequence for MCX {
             }
         }
 
-        if let Some(protocol) = interface.probe_mut().active_protocol() {
+        if let Some(protocol) = interface.try_dap_probe().and_then(|f| f.active_protocol()) {
             match protocol {
                 WireProtocol::Jtag => {
                     // Init AP Transfer Mode, Transaction Counter, and
diff --git a/probe-rs/src/vendor/nxp/sequences/nxp_armv8m.rs b/probe-rs/src/vendor/nxp/sequences/nxp_armv8m.rs
index 7e60551a..0e57bb5f 100644
--- a/probe-rs/src/vendor/nxp/sequences/nxp_armv8m.rs
+++ b/probe-rs/src/vendor/nxp/sequences/nxp_armv8m.rs
@@ -10,13 +10,11 @@ use std::{
 use crate::{
     architecture::arm::{
         ap::{AccessPortError, AccessPortType, ApRegister, GenericAp, IDR},
-        communication_interface::Initialized,
         core::armv8m::{Aircr, Demcr, Dhcsr},
         dp::{Abort, Ctrl, DpAccess, DpAddress, DpRegister, SelectV1, DPIDR},
         memory::ArmMemoryInterface,
         sequences::ArmDebugSequence,
-        ArmCommunicationInterface, ArmError, ArmProbeInterface, DapAccess, FullyQualifiedApAddress,
-        Pins,
+        ArmError, ArmProbeInterface, DapAccess, FullyQualifiedApAddress, Pins,
     },
     core::MemoryMappedRegister,
 };
@@ -30,7 +28,7 @@ pub mod ol23d0;
 /// Note that this routine only supports SWD protocols. See the inline TODOs to
 /// understand where JTAG support should go.
 fn debug_port_start(
-    interface: &mut ArmCommunicationInterface<Initialized>,
+    interface: &mut dyn DapAccess,
     dp: DpAddress,
     select: SelectV1,
 ) -> Result<bool, ArmError> {
@@ -100,7 +98,7 @@ impl LPC55Sxx {
 impl ArmDebugSequence for LPC55Sxx {
     fn debug_port_start(
         &self,
-        interface: &mut ArmCommunicationInterface<Initialized>,
+        interface: &mut dyn DapAccess,
         dp: DpAddress,
     ) -> Result<(), ArmError> {
         tracing::info!("debug_port_start");
@@ -584,7 +582,7 @@ impl MIMXRT5xxS {
 impl ArmDebugSequence for MIMXRT5xxS {
     fn debug_port_start(
         &self,
-        interface: &mut ArmCommunicationInterface<Initialized>,
+        interface: &mut dyn DapAccess,
         dp: DpAddress,
     ) -> Result<(), ArmError> {
         let mut abort = Abort::default();
diff --git a/probe-rs/targets/MSPM0GX51X_Series.yaml b/probe-rs/targets/MSPM0GX51X_Series.yaml
new file mode 100644
index 00000000..f0bcad1b
--- /dev/null
+++ b/probe-rs/targets/MSPM0GX51X_Series.yaml
@@ -0,0 +1,424 @@
+name: MSPM0GX51X Series
+manufacturer:
+  id: 0x17
+  cc: 0x0
+generated_from_pack: true
+pack_file_release: 1.0.0
+variants:
+- name: MSPM0G1518
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: !v1 0
+  memory_map:
+  - !Nvm
+    name: IROM1
+    range:
+      start: 0x0
+      end: 0x40000
+    cores:
+    - main
+    access:
+      write: false
+      boot: true
+  - !Generic
+    name: IROM2
+    range:
+      start: 0x400000
+      end: 0x440000
+    cores:
+    - main
+    access:
+      write: false
+  - !Generic
+    name: IRAM1
+    range:
+      start: 0x20000000
+      end: 0x20010000
+    cores:
+    - main
+  - !Generic
+    name: IRAM_Parity
+    range:
+      start: 0x20100000
+      end: 0x20110000
+    cores:
+    - main
+  - !Ram
+    name: IRAM_No_Parity
+    range:
+      start: 0x20200000
+      end: 0x20220000
+    cores:
+    - main
+  - !Generic
+    name: IRAM_Parity_Code
+    range:
+      start: 0x20300000
+      end: 0x20310000
+    cores:
+    - main
+  - !Generic
+    name: NonMain_ECC
+    range:
+      start: 0x41c00000
+      end: 0x41c00800
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Factory_ECC
+    range:
+      start: 0x41c40000
+      end: 0x41c40200
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Data
+    range:
+      start: 0x41d00000
+      end: 0x41d04000
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  flash_algorithms:
+  - mspm0gx51x_main_512kb
+  - mspm0gx51x_nonmain
+  - mspm0gx51x_data_16kb
+- name: MSPM0G1519
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: !v1 0
+  memory_map:
+  - !Nvm
+    name: IROM1
+    range:
+      start: 0x0
+      end: 0x80000
+    cores:
+    - main
+    access:
+      write: false
+      boot: true
+  - !Generic
+    name: IROM2
+    range:
+      start: 0x400000
+      end: 0x480000
+    cores:
+    - main
+    access:
+      write: false
+  - !Generic
+    name: IRAM1
+    range:
+      start: 0x20000000
+      end: 0x20010000
+    cores:
+    - main
+  - !Generic
+    name: IRAM_Parity
+    range:
+      start: 0x20100000
+      end: 0x20110000
+    cores:
+    - main
+  - !Ram
+    name: IRAM_No_Parity
+    range:
+      start: 0x20200000
+      end: 0x20220000
+    cores:
+    - main
+  - !Generic
+    name: IRAM_Parity_Code
+    range:
+      start: 0x20300000
+      end: 0x20310000
+    cores:
+    - main
+  - !Generic
+    name: NonMain_ECC
+    range:
+      start: 0x41c00000
+      end: 0x41c00800
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Factory_ECC
+    range:
+      start: 0x41c40000
+      end: 0x41c40200
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Data
+    range:
+      start: 0x41d00000
+      end: 0x41d04000
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  flash_algorithms:
+  - mspm0gx51x_main_512kb
+  - mspm0gx51x_nonmain
+  - mspm0gx51x_data_16kb
+- name: MSPM0G3518
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: !v1 0
+  memory_map:
+  - !Nvm
+    name: IROM1
+    range:
+      start: 0x0
+      end: 0x40000
+    cores:
+    - main
+    access:
+      write: false
+      boot: true
+  - !Generic
+    name: IROM2
+    range:
+      start: 0x400000
+      end: 0x440000
+    cores:
+    - main
+    access:
+      write: false
+  - !Generic
+    name: IRAM1
+    range:
+      start: 0x20000000
+      end: 0x20010000
+    cores:
+    - main
+  - !Generic
+    name: IRAM_Parity
+    range:
+      start: 0x20100000
+      end: 0x20110000
+    cores:
+    - main
+  - !Ram
+    name: IRAM_No_Parity
+    range:
+      start: 0x20200000
+      end: 0x20220000
+    cores:
+    - main
+  - !Generic
+    name: IRAM_Parity_Code
+    range:
+      start: 0x20300000
+      end: 0x20310000
+    cores:
+    - main
+  - !Generic
+    name: NonMain_ECC
+    range:
+      start: 0x41c00000
+      end: 0x41c00800
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Factory_ECC
+    range:
+      start: 0x41c40000
+      end: 0x41c40200
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Data
+    range:
+      start: 0x41d00000
+      end: 0x41d04000
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  flash_algorithms:
+  - mspm0gx51x_main_512kb
+  - mspm0gx51x_nonmain
+  - mspm0gx51x_data_16kb
+- name: MSPM0G3519
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: !v1 0
+  memory_map:
+  - !Nvm
+    name: IROM1
+    range:
+      start: 0x0
+      end: 0x80000
+    cores:
+    - main
+    access:
+      write: false
+      boot: true
+  - !Generic
+    name: IROM2
+    range:
+      start: 0x400000
+      end: 0x480000
+    cores:
+    - main
+    access:
+      write: false
+  - !Generic
+    name: IRAM1
+    range:
+      start: 0x20000000
+      end: 0x20010000
+    cores:
+    - main
+  - !Generic
+    name: IRAM_Parity
+    range:
+      start: 0x20100000
+      end: 0x20110000
+    cores:
+    - main
+  - !Ram
+    name: IRAM_No_Parity
+    range:
+      start: 0x20200000
+      end: 0x20220000
+    cores:
+    - main
+  - !Generic
+    name: IRAM_Parity_Code
+    range:
+      start: 0x20300000
+      end: 0x20310000
+    cores:
+    - main
+  - !Generic
+    name: NonMain_ECC
+    range:
+      start: 0x41c00000
+      end: 0x41c00800
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Factory_ECC
+    range:
+      start: 0x41c40000
+      end: 0x41c40200
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Data
+    range:
+      start: 0x41d00000
+      end: 0x41d04000
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  flash_algorithms:
+  - mspm0gx51x_main_512kb
+  - mspm0gx51x_nonmain
+  - mspm0gx51x_data_16kb
+flash_algorithms:
+- name: mspm0gx51x_main_512kb
+  description: MSPM0GX51X MAIN 512KB
+  default: true
+  instructions: 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
+  load_address: 0x20200008
+  pc_init: 0x1d
+  pc_uninit: 0x99
+  pc_program_page: 0x19d
+  pc_erase_sector: 0xcd
+  pc_erase_all: 0x9d
+  data_section_offset: 0x16e4
+  flash_properties:
+    address_range:
+      start: 0x0
+      end: 0x80000
+    page_size: 0x400
+    erased_byte_value: 0xff
+    program_page_timeout: 500
+    erase_sector_timeout: 3000
+    sectors:
+    - size: 0x400
+      address: 0x0
+- name: mspm0gx51x_nonmain
+  description: MSPM0GX51X NON-MAIN
+  instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1GEgBaAcikUMBYBZIF0kBYBdMYWggaAMikEMgYBEgAAQIQAEhCgWQQgXQCQSIQgTRAfDj+QHgAfC4+WBoDyGIQ2BgAfCy+QpIAWgEIpFDAWAA8BP4CEkCIAhgACDCQ0pgEL0AE0BAAAhEQAEAACYAAQtAEO0A4AARREAESAUhQWABIQFgA0gBaEkH/NRwRwDhDEDQ4wxA/rUBIYhDAig90QCRACACkMBDAZAfTS4jHUwgRgGfOUYqRgDwy/gGRhYjIEY5RhpKAPDE+ARGMEYgQx/QKEYA8DH4uCEVSnpEL0YoRgDwUvhYIRNKekQQSADwTPgALgPQApkDKQbZEOABIAAsB9ACmQQpBNJJHAKRPUbM5wKYACgAmADQ/r0AIP69AJj+vcBGAABEQAAAwEEAAcBBRhYAABgZAAD4tQRGQAoQSYhCGNEEIMZDACAOTQEnwQcT0QAuEdD/94//ugIoRiFGAPCa/EAiKEYhRgDww/h2HADwVvjq5wEg+L14QDhA+L0A4CAAANAMQPi1FEYNRgZGQQoBIBNKkUIi0QAtINAHISlAHdEBIRFPACAALRjQyQcW0P/3Yf8BIIICC0gxRgDwa/w4aEAH/NQHSDFGIkYA8FH7CDYINAg9APAi+AFG4+f4vcBGAOAgAADQDEDQ4wxAcLUEIMZDACQITeAHB9EALgXQKEYA8F75BEZ2HPXnASBEQARA//cw/yBGcL0A0AxAgbAKSAFoByIKQACSAJnJsgMpA9AAmcmyASnz0QCYwLLBHkhCSEEBsHBHwEbQ4wxAELUFTAFRABkAKwPQAspBYFse+eeAaBC9BBEAABC1BUwBUQAZmkIC2ALKQWD654BoEL3ARgQRAAC8tQpMBBkAlACcIYAISUEYACsG0BSIAZEBnSyAkhxbHvbnBElAWICyvL3ARgQRAAAIEQAADBEAALy1CUwEGQCUAJwhgAdJQRiaQgXYFIgBkQGdLICSHPfnA0lAWICyvL0EEQAACBEAAAwRAAAQtQIjE0MRIhIChBhjYCFiASGBUBC9wEaAtQIjE0MDSoNQghjRYf/3Yf6AvQQRAAAQtQRGEUgAISFQIBhBYIFgykMCZBEgAAIiGFIjU2ARYgEhIVAgRgDwKfgJSQpoBSMLYAcjE0AHShJoC2CRDgTQACgC0CBGAPAx+BC90BEAAAATQEAYAMRBA0kAIkJQQBhCYIJgcEfARtARAAAAIclDAUqBUHBHwEYQEgAAgbAKSUAYAWgHIgpAAJIAmcmyAykD0ACZybIBKfPRAJjAssEeSEJIQQGwcEfQEwAA/rUYSxloBSIaYAciCkAWSQloGmARIhICApCAGAGQjw4STQEgAp7/sv83+bK5QhXQwQcT0DBGAPD5+AEkYgIwRilGAPBB+0IgAZlIYA1iDGCgAi0YMEb/97v/5OcBIQhA/r3ARgATQEAYAMRBAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//e+/QpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3lf2AvdARAAAEEQAAAADQQfC1h7AERgDwhfgFRjpIAWgFIgJgByIKQDhJCWgCYDhIIBgCkBEgAAIElCYYNUgIQClGAfBf+CpGgAIBkGgIBpAQIAWQACcBJD1GIEYDkgCUlUJJ0sEHR9AGmIVCAdIAIQDgASEoSABoQAUgRgDVCEYpBokOBdH5FTtGJKd5Wh9GBZEAKCBGKtAEnCBGAPBU+AEgAQSyaApDsmAfIQkBBZoKQLNoi0OZGLFgDyFJArJoikNBAlEYsWAAIQKaEWBRYJFgyUMRZFIhcWApRgGaUUMxYjBgIEYAnP/3AP8DmgEhCQZ/GG0cs+cBIQoEs2iTQ7NgCEAHsPC9ABNAQBgAxEHQEQAA/w8AAEggC0AQACAAQACAAAZIAWgFIgJgByIKQARJCWgCYIgEgA9AHHBHwEYAE0BAGADEQREhCQJCGAUjU2ABIkJQAkgBaEkH/NRwR9DjDEAQtQRG//eC/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//eu/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//et/BC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3cP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//dx/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/3VPwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3NvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//cU/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/9/X7EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/99f7EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/97n7EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//eW+xC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//ds+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//dC+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//cY+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//fr+rC9BBEAAP8BAACwEQAA8LWHsB9GBpIFkQRGASEYRgSRCEBBQkFBWh4YRpBBCEARIQkCA5RhGAKRDJkBkQOdAC8f0MEHHdAoRv/30/0oRgWcIUYBmgDwG/gEmQKaUWAKSFBiFGIGnjBoEGNwaFBjEWAINAWUvx4oRv/3jfwINgaW3ecEmQhAB7Dwvf8BAABwtRVGDEYLSUYYIEYA8D75ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaIhDMGBwvcBG1BEAAPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3yv84RjFGKkb/98X+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3mv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wf8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/91z/IEYxRipGApwjRv/3/f4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//c2/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ec+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3/v4wRilGIkYBLwXQ//d5/b8eCCECIgTg//dT/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3VvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8DX8AUYgRgDwMfwMRiBGEL0AE0BAGADEQf8PAABwtRVGDEYLSUYYIEb/99b/ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaAhDMGBwvcBG1BEAALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/33PgQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/3zfgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/3vvgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//3rPgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/95v4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3i/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//d7+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3avgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//dU+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/9z74sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3KPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/9xH4sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/vdk/4C9wEYEEQAAELUTRgRGBEoA8Aj4ESAAAgEhIVAQvcBG//8AALC1B0wRJQVRABkCYsFhGWjBYlloAWOZaEFj2WiBY7C9BBEAABC1E0YERgRK//fo/xEgAAIBISFQEL3ARv//AQCwtR1GE0YERgZK//fZ/yh4BUlgUGAYaXhBYBEgAAIBISFQsL3//wEAsBEAAPC1hbAfRhRGDUYCRhEgAQIAKwHQAy8B2AAgAOABIASSVhgKmQOR/yEQMQKRAZYALzrQwQc40ASYKUYDmv/3WPwBLxDQAy8a2AEgcGACmfAxcWI1YiFoMWNhaHFjMGC/HgghAiIJ4AEicmACmHBiNWIhaDFjMmAAJwQhBJgO4C5GJUYEnCBGMUYqRv/3lf8gRixGNUYBnj8fECEEIm0YkQBkGP/3qfjC5wEhCEAFsPC9/7UBJCICKksZaAOSkUMZYChJDWhtBPzVRX4lQJ5ppkN0GZxhICQEXQMlLEDeaa5DNBncYSBMJWgFJiZgRmo3aB9idmheYgcmLkAmYMRpfyUtAt5prkNkBmQMNBncYQdoRWiCaACSxmgCaQGSQmkCkpppEkwUQDoHEgstA62yqhgyQwCdLQctDRVDAZoVQwKaFUMAfihDCkoCQBAZmGEYaAOaEEMYYAhogAX81f+9wEYIAQtABAILQAATQECNAPD/cv8PALC1/yIEMg5JC2iTQ4J4AyQUQAJ4EgISGRpDCmAJSgpLE2AKTCVobQX81UB4ACgD0AhoECQEQwxgWBwQYLC9wEYUAQtAFAMLQAEAAJEEAgtADEkKaAAoA9ABIIACAkMG4AMggkMKYAEggAIKaIJDCmABIAAFSmgCQ0pgA0gBaIkD/NVwRwABC0AEAgtAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAdJiGAHSAJokgL81QEiEgQLaBNDC2ABaMkG/NVwR8BGBAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQBC1D0kLaAEik0MLYAMjGwMYQIxonEMgGIhgiGgIIwND9yCDQ4tgCGgQQwhgEAeKaAJDimADSAFoyQX81RC9wEYIAQtABAILQHC1EUsdaAEkpUMdYAMlLQMoQJ5orkMwGJhgmGj/JahDybJAGJhgGGggQxhgmGghBwAqBtAIQ5hgBEgBaMkF/NVwvYhDmGBwvQgBC0AEAgtAsLU/IxsEBEwlaJ1DCEMQQxhAKBggYLC9OAELQAlIAGhABwjUCEhBaMkCBtQAaIAFBdUDIHBHACBwRwIgcEcBIHBHwEYQ7QDgAAELQApJCmwAIAAqANBwRwhKEmhSB/rVCGjABQTUCGiABQPVAyBwRwIgcEcBIHBHAAELQBDtAOAHScprACABKgfRBkoSaFIHA9UIaIACAdUCIHBHASBwRwQBC0AQ7QDgELUISxxrASIiQAjRBkwgQBhgIUBZYNhqBEkBQ9liUEJQQRC9GCALQMD/PwAQAAB2ELUIS5xqASIiQAjRBkwgQBhgIUAZYFhqBEkBQ1liUEJQQRC9ICALQMD/PwBAAAB2ACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAS7qruqu6q7qv//////////u6q7qruqu6r//7uqu6q7qv///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9B/+hoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFgIVAgEDAgOoEv//r5YTdg9yY1+9tEpaCmPDnxKvMPlQpu5clxvhiOicQFH/////////////////////////////////////////////SADJWPEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+  load_address: 0x20200008
+  pc_init: 0x1d
+  pc_uninit: 0xb5
+  pc_program_page: 0x1a9
+  pc_erase_sector: 0x159
+  pc_erase_all: 0x211
+  data_section_offset: 0x1b84
+  flash_properties:
+    address_range:
+      start: 0x41c00000
+      end: 0x41c00400
+    page_size: 0x40
+    erased_byte_value: 0xff
+    program_page_timeout: 500
+    erase_sector_timeout: 3000
+    sectors:
+    - size: 0x400
+      address: 0x0
+- name: mspm0gx51x_data_16kb
+  description: MSPM0GX51X DATA 16KB
+  instructions: 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
+  load_address: 0x20200008
+  pc_init: 0x1d
+  pc_uninit: 0x99
+  pc_program_page: 0x19d
+  pc_erase_sector: 0xcd
+  pc_erase_all: 0x9d
+  data_section_offset: 0x16e4
+  flash_properties:
+    address_range:
+      start: 0x0
+      end: 0x4000
+    page_size: 0x400
+    erased_byte_value: 0xff
+    program_page_timeout: 500
+    erase_sector_timeout: 3000
+    sectors:
+    - size: 0x400
+      address: 0x0
diff --git a/probe-rs/targets/MSPM0L122X_L222X_Series.yaml b/probe-rs/targets/MSPM0L122X_L222X_Series.yaml
new file mode 100644
index 00000000..23c06fcc
--- /dev/null
+++ b/probe-rs/targets/MSPM0L122X_L222X_Series.yaml
@@ -0,0 +1,239 @@
+name: MSPM0L122X_L222X Series
+manufacturer:
+  id: 0x17
+  cc: 0x0
+generated_from_pack: true
+pack_file_release: 1.1.1
+variants:
+- name: MSPM0L1227
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: !v1 0
+  memory_map:
+  - !Nvm
+    name: IROM1
+    range:
+      start: 0x0
+      end: 0x20000
+    cores:
+    - main
+    access:
+      write: false
+      boot: true
+  - !Ram
+    name: IRAM1
+    range:
+      start: 0x20200000
+      end: 0x20208000
+    cores:
+    - main
+  - !Generic
+    name: NonMain
+    range:
+      start: 0x41c00000
+      end: 0x41c00200
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Factory
+    range:
+      start: 0x41c40000
+      end: 0x41c40080
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  flash_algorithms:
+  - mspm0l122x_l222x_main_256kb
+  - mspm0l122x_l222x_nonmain
+- name: MSPM0L1228
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: !v1 0
+  memory_map:
+  - !Nvm
+    name: IROM1
+    range:
+      start: 0x0
+      end: 0x40000
+    cores:
+    - main
+    access:
+      write: false
+      boot: true
+  - !Ram
+    name: IRAM1
+    range:
+      start: 0x20200000
+      end: 0x20208000
+    cores:
+    - main
+  - !Generic
+    name: NonMain
+    range:
+      start: 0x41c00000
+      end: 0x41c00200
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Factory
+    range:
+      start: 0x41c40000
+      end: 0x41c40080
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  flash_algorithms:
+  - mspm0l122x_l222x_main_256kb
+  - mspm0l122x_l222x_nonmain
+- name: MSPM0L2227
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: !v1 0
+  memory_map:
+  - !Nvm
+    name: IROM1
+    range:
+      start: 0x0
+      end: 0x20000
+    cores:
+    - main
+    access:
+      write: false
+      boot: true
+  - !Ram
+    name: IRAM1
+    range:
+      start: 0x20200000
+      end: 0x20208000
+    cores:
+    - main
+  - !Generic
+    name: NonMain
+    range:
+      start: 0x41c00000
+      end: 0x41c00200
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Factory
+    range:
+      start: 0x41c40000
+      end: 0x41c40080
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  flash_algorithms:
+  - mspm0l122x_l222x_main_256kb
+  - mspm0l122x_l222x_nonmain
+- name: MSPM0L2228
+  cores:
+  - name: main
+    type: armv6m
+    core_access_options: !Arm
+      ap: !v1 0
+  memory_map:
+  - !Nvm
+    name: IROM1
+    range:
+      start: 0x0
+      end: 0x40000
+    cores:
+    - main
+    access:
+      write: false
+      boot: true
+  - !Ram
+    name: IRAM1
+    range:
+      start: 0x20200000
+      end: 0x20208000
+    cores:
+    - main
+  - !Generic
+    name: NonMain
+    range:
+      start: 0x41c00000
+      end: 0x41c00200
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  - !Generic
+    name: Factory
+    range:
+      start: 0x41c40000
+      end: 0x41c40080
+    cores:
+    - main
+    access:
+      write: false
+      execute: false
+  flash_algorithms:
+  - mspm0l122x_l222x_main_256kb
+  - mspm0l122x_l222x_nonmain
+flash_algorithms:
+- name: mspm0l122x_l222x_main_256kb
+  description: MSPM0L122X_222X MAIN 256KB
+  default: true
+  instructions: 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
+  load_address: 0x20200008
+  pc_init: 0x1d
+  pc_uninit: 0x5d
+  pc_program_page: 0x145
+  pc_erase_sector: 0x61
+  pc_erase_all: 0x131
+  data_section_offset: 0x12dc
+  flash_properties:
+    address_range:
+      start: 0x0
+      end: 0x40000
+    page_size: 0x400
+    erased_byte_value: 0xff
+    program_page_timeout: 500
+    erase_sector_timeout: 3000
+    sectors:
+    - size: 0x400
+      address: 0x0
+- name: mspm0l122x_l222x_nonmain
+  description: MSPM0L122X_222X NON-MAIN
+  instructions: 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A0gBaIkD/NRwR8BGAAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQAAiAwmLQizTAwqLQhHTACOcRk7gA0YLQzzUACJDCItCMdMDCYtCHNMDCotCAdOURj/gwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJBQwiLQgHTSwDAGlJBQRoA0gFGUkEQRnBHXeDKDwDQSUIDEADTQEJTQJxGACIDCYtCLdMDCotCEtOJAfwiEroDCotCDNOJAZIRi0II04kBkhGLQgTTiQE60JIRAOCJCcMJi0IB08sBwBpSQYMJi0IB04sBwBpSQUMJi0IB00sBwBpSQQMJi0IB0wsBwBpSQcMIi0IB08sAwBpSQYMIi0IB04sAwBpSQdnSQwiLQgHTSwDAGlJBQRoA0gFGUkEQRmNGWxAB00BCACsA1UlCcEdjRlsQANNAQgG1BUkAKALcSRwIQADgCEbARsBGAr0Av////38CAAABu6q7qruqu6r//////////7uqu6q7qruq//+7qruqu6r///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+yIGk/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABoCGQIBAwIDshL//6+WE3YPcmNfvbRKWgpjw58SrzD5UKbuXJcb4YjonEBR/////////////////////////////////////////////0gA0UsBbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+  load_address: 0x20200008
+  pc_init: 0x1d
+  pc_uninit: 0x7d
+  pc_program_page: 0x18d
+  pc_erase_sector: 0x121
+  pc_erase_all: 0x79
+  data_section_offset: 0x1774
+  flash_properties:
+    address_range:
+      start: 0x41c00000
+      end: 0x41c00200
+    page_size: 0x40
+    erased_byte_value: 0xff
+    program_page_timeout: 500
+    erase_sector_timeout: 3000
+    sectors:
+    - size: 0x200
+      address: 0x0


Test patch:
diff --git a/probe-rs-tools/src/bin/probe-rs/rpc/functions/test.rs b/probe-rs-tools/src/bin/probe-rs/rpc/functions/test.rs
index 801cb1d3..2e5a7c1b 100644
--- a/probe-rs-tools/src/bin/probe-rs/rpc/functions/test.rs
+++ b/probe-rs-tools/src/bin/probe-rs/rpc/functions/test.rs
@@ -340,6 +340,7 @@ impl<F: FnMut(MonitorEvent)> ListEventHandler<F> {
                 }
                 Ok(None)
             }
+            SemihostingCommand::Errno(_) => Ok(None),
             other => anyhow::bail!(
                 "Unexpected semihosting command {:?} cmdline_requested: {:?}",
                 other,
@@ -403,6 +404,7 @@ impl<F: FnMut(MonitorEvent)> RunEventHandler<F> {
                 }
                 Ok(None)
             }
+            SemihostingCommand::Errno(_) => Ok(None),
             other => {
                 // Invalid sequence of semihosting calls => Abort testing altogether
                 anyhow::bail!(