From 4889803d75083ce8c120fefbca73553c276c96fe Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 19 Jun 2025 21:08:26 +0100 Subject: [PATCH 01/57] serial: Built out some very basic infrastructure to make the GDB and BMD RSP interfaces available --- src/lib.rs | 1 + src/serial/bmd_rsp.rs | 25 +++++++++++++++++++++++++ src/serial/gdb_rsp.rs | 24 ++++++++++++++++++++++++ src/serial/mod.rs | 6 ++++++ 4 files changed, 56 insertions(+) create mode 100644 src/serial/bmd_rsp.rs create mode 100644 src/serial/gdb_rsp.rs create mode 100644 src/serial/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 474e402..a8c6d54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub mod firmware_selector; pub mod flasher; pub mod metadata; pub mod probe_identity; +pub mod serial; pub mod switcher; pub mod usb; #[cfg(windows)] diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs new file mode 100644 index 0000000..8bb20cf --- /dev/null +++ b/src/serial/bmd_rsp.rs @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::fs::File; +use std::path::Path; + +use color_eyre::eyre::Result; + +pub struct BmdRspInterface +{ + interface: File, + protocol_version: u64, +} + +impl BmdRspInterface +{ + pub fn from_path(serial_port: &Path) -> Result + { + Ok(Self { + interface: File::options().read(true).write(true).open(serial_port)?, + protocol_version: u64::MAX, + }) + } +} diff --git a/src/serial/gdb_rsp.rs b/src/serial/gdb_rsp.rs new file mode 100644 index 0000000..6c2d64e --- /dev/null +++ b/src/serial/gdb_rsp.rs @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::fs::File; +use std::path::Path; + +use color_eyre::eyre::Result; + +pub struct GdbRspInterface +{ + #[allow(unused)] + interface: File, +} + +impl GdbRspInterface +{ + pub fn from_path(serial_port: &Path) -> Result + { + Ok(Self { + interface: File::options().read(true).write(true).open(serial_port)?, + }) + } +} diff --git a/src/serial/mod.rs b/src/serial/mod.rs new file mode 100644 index 0000000..dc7a6ec --- /dev/null +++ b/src/serial/mod.rs @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +mod bmd_rsp; +mod gdb_rsp; From 687875f08226574cfcf8835a9027c4af5d7d476f Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 19 Jun 2025 21:09:25 +0100 Subject: [PATCH 02/57] serial/interface: Built out Linux and macOS support for finding the GDB serial interface of a probe --- src/serial/interface.rs | 116 ++++++++++++++++++++++++++++++++++++++++ src/serial/mod.rs | 1 + 2 files changed, 117 insertions(+) create mode 100644 src/serial/interface.rs diff --git a/src/serial/interface.rs b/src/serial/interface.rs new file mode 100644 index 0000000..810d2d2 --- /dev/null +++ b/src/serial/interface.rs @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::path::PathBuf; + +use color_eyre::eyre::Result; + +use crate::bmp::BmpDevice; +use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::gdb_rsp::GdbRspInterface; + +pub struct ProbeInterface +{ + serial_number: String, +} + +impl ProbeInterface +{ + pub fn from_device(probe: BmpDevice) -> Result + { + Ok(Self { + serial_number: probe.serial_number()?.to_string(), + }) + } + + pub fn gdb_interface(&self) -> Result + { + GdbRspInterface::from_path(&self.probe_interface()?) + } + + pub fn bmd_interface(&self) -> Result + { + BmdRspInterface::from_path(&self.probe_interface()?) + } +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +impl ProbeInterface +{ + const BMD_IDSTRING_1BITSQUARED: &str = "usb-1BitSquared_Black_Magic_Probe"; + const BMD_IDSTRING_BLACKMAGIC: &str = "usb-Black_Magic_Debug_Black_Magic_Probe"; + const BMD_IDSTRING_BLACKSHERE: &str = "usb-Black_Sphere_Technologies_Black_Magic_Probe"; + const DEVICE_BY_ID: &str = "/dev/serial/by-id"; + + /// Locate the GDB serial interface associated with the probe of the given serial number + fn probe_interface(&self) -> Result + { + use std::fs::read_dir; + + use color_eyre::eyre::eyre; + + // Start by opening the by-id serial interfaces device tree + let dir = read_dir(Self::DEVICE_BY_ID)?; + // Read through all the entries and try to locate one that has a serial number match + for entry in dir { + let entry = entry?; + // Try to convert this entry's file name to a regular string - if we can't, it cannot be + // a BMD serial interface (ours strictly convert to valid UTF-8) + let file_name = entry.file_name(); + let file_name = if let Some(path) = file_name.to_str() { + path + } else { + continue; + }; + + // Check to see if this entry represents a BMD based probe + if !Self::device_is_bmd_gdb_port(file_name) { + continue; + } + // It does! Horray, now check if we have an entry with a matching serial number + if self.serial_matches(file_name) { + // We have a match! Convert the entry into a path and return then + return Ok(entry.path()); + } + } + // If we manage to get here, we could not find a matching device - so fail accordingly + Err(eyre!("Failed to locate a device matching serial number {}", self.serial_number)) + } + + fn device_is_bmd_gdb_port(file_name: &str) -> bool + { + // Check if the device file name fragment starts with one of the known + // by-id prefixes and ends with the right interface suffix + (file_name.starts_with(Self::BMD_IDSTRING_BLACKSHERE) || + file_name.starts_with(Self::BMD_IDSTRING_BLACKMAGIC) || + file_name.starts_with(Self::BMD_IDSTRING_1BITSQUARED)) && + file_name.ends_with("-if00") + } + + fn serial_matches(&self, file_name: &str) -> bool + { + // Start by trying to find the last _ just before the serial string + let last_underscore = if let Some(pos) = file_name.rfind('_') { + pos + } else { + return false; + }; + // Having done that, extract the slice representing the serial number for this device + let begin = last_underscore + 1; + // This represents one past the last byte of the serial number string, chopping off `-if00` + let end = file_name.len() - 5; + // Create the slice and compare to the stored serial number + file_name[begin..end] == self.serial_number + } +} + +#[cfg(target_os = "macos")] +impl ProbeInterface +{ + /// Locate the GDB serial interface associated with the probe of the given serial number + fn probe_interface(&self) -> Result + { + Ok(format!("/dev/cu.usbmodem{}1", self.serial_number).into()) + } +} diff --git a/src/serial/mod.rs b/src/serial/mod.rs index dc7a6ec..5e1e790 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -4,3 +4,4 @@ mod bmd_rsp; mod gdb_rsp; +pub mod interface; From 0be185c96a96dbc25c40d095ef5ab18d7449c498 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 19 Jun 2025 21:09:58 +0100 Subject: [PATCH 03/57] cargo: Added a dependency on the Windows registry crate --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 30f8051..576e0bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ deelevate = "0.2.0" libc = "0.2.132" lazy_static = "1.4.0" winreg = "0.10.1" +windows-registry = "0.5.2" [target.'cfg(windows)'.dependencies.winapi] version = "0.3.9" From 65c5b66472d04e7781b44859b62c73914258b3b5 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 19 Jun 2025 21:24:52 +0100 Subject: [PATCH 04/57] cargo: Built out the matching device path logic for Windows as for Linux and macOS before --- src/serial/interface.rs | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/serial/interface.rs b/src/serial/interface.rs index 810d2d2..579c722 100644 --- a/src/serial/interface.rs +++ b/src/serial/interface.rs @@ -105,6 +105,51 @@ impl ProbeInterface } } +#[cfg(target_os = "windows")] +impl ProbeInterface +{ + const PRODUCT_ID_BMP: u16 = 0x6018; + const VENDOR_ID_BMP: u16 = 0x1d50; + + /// Locate the GDB serial interface associated with the probe of the given serial number + fn probe_interface(&self) -> Result + { + // Try to locate the probe's instance ID from the registry + let serial_path = format!("\\{}", self.serial_number); + let prefix = Self::read_key_from_path(&serial_path, "ParentIdPrefix")?; + // Having grabbed the instance ID, read out the device path that matches up + // for interface 0, giving us a `\\.\COMn` name to use with the file APIs + let parameter_path = format!("&MI_00\\{}&0000\\Device Parameters", prefix); + let port_name = Self::read_key_from_path(¶meter_path, "PortName")?; + // Return by converting the string to a PathBuf + if port_name.starts_with("\\\\.\\") { + Ok(port_name.into()) + } else { + Ok(format!("\\\\.\\{}", port_name).into()) + } + } + + fn read_key_from_path(subpath: &str, key_name: &str) -> Result + { + use log::debug; + use windows_registry::LOCAL_MACHINE; + + // Try to open the registry subkey that contains the probe's enumeration data + let key_path = format!( + "SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_{:04X}&PID_{:04X}{}", + Self::VENDOR_ID_BMP, + Self::PRODUCT_ID_BMP, + subpath, + ); + debug!("Trying to open registry key {} to get value {}", key_path, key_name); + let key_handle = LOCAL_MACHINE.open(&key_path)?; + + // Now extract the data for the associated key we're interested in here - + // with that value read, we're done and can return + Ok(key_handle.get_string(key_name)?) + } +} + #[cfg(target_os = "macos")] impl ProbeInterface { From f4cf03531e369278009c6784b744f6d2068e9d7c Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 19 Jun 2025 21:35:22 +0100 Subject: [PATCH 05/57] bmp: Exposed functionality for getting access to the remote protocol serial interfaces of the probe --- src/bmp.rs | 17 +++++++++++++++++ src/serial/interface.rs | 2 +- src/serial/mod.rs | 4 ++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/bmp.rs b/src/bmp.rs index df7d154..dfd448b 100644 --- a/src/bmp.rs +++ b/src/bmp.rs @@ -25,6 +25,9 @@ use nusb::{Device, DeviceInfo, Interface, list_devices}; use crate::BmpParams; use crate::error::ErrorKind; use crate::probe_identity::ProbeIdentity; +use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::gdb_rsp::GdbRspInterface; +use crate::serial::interface::ProbeInterface; use crate::usb::{ DfuFunctionalDescriptor, DfuOperatingMode, DfuRequest, GenericDescriptorRef, InterfaceClass, InterfaceSubClass, Pid, PortId, Vid, @@ -513,6 +516,20 @@ impl BmpDevice self.mode, ) } + + /// Locate and return the GDB remote serial interface of the probe for probe debug communciations + pub fn gdb_serial_interface(&self) -> Result + { + let serial_interface = ProbeInterface::from_device(self)?; + serial_interface.gdb_interface() + } + + /// Locate and return the BMD remote serial interface of the probe for probe debug communciations + pub fn bmd_serial_interface(&self) -> Result + { + let serial_interface = ProbeInterface::from_device(self)?; + serial_interface.bmd_interface() + } } impl Debug for BmpDevice diff --git a/src/serial/interface.rs b/src/serial/interface.rs index 579c722..bcda359 100644 --- a/src/serial/interface.rs +++ b/src/serial/interface.rs @@ -17,7 +17,7 @@ pub struct ProbeInterface impl ProbeInterface { - pub fn from_device(probe: BmpDevice) -> Result + pub fn from_device(probe: &BmpDevice) -> Result { Ok(Self { serial_number: probe.serial_number()?.to_string(), diff --git a/src/serial/mod.rs b/src/serial/mod.rs index 5e1e790..2de8ca9 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -2,6 +2,6 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant -mod bmd_rsp; -mod gdb_rsp; +pub mod bmd_rsp; +pub mod gdb_rsp; pub mod interface; From 815d869fc426d383bb45979937bc30906d673317 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 05:15:07 +0100 Subject: [PATCH 06/57] serial/bmd_rsp: Built out the logic needed to properly initialise comms to a probe on Linux/macOS and begin a remote protocol session with te probe --- Cargo.lock | 334 +++++++++++++++++++++--------------------- Cargo.toml | 3 + src/serial/bmd_rsp.rs | 74 +++++++++- 3 files changed, 243 insertions(+), 168 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af5a827..9c1ec40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -68,33 +68,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.8" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", "once_cell_polyfill", @@ -115,9 +115,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" @@ -128,7 +128,7 @@ dependencies = [ "addr2line", "cfg-if", "libc", - "miniz_oxide 0.8.8", + "miniz_oxide 0.8.9", "object", "rustc-demangle", "windows-targets 0.52.6", @@ -174,7 +174,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.101", + "syn 2.0.104", "which", ] @@ -239,11 +239,13 @@ dependencies = [ "serde_json", "sha2 0.10.9", "static_vcruntime", + "termios", "thiserror 2.0.12", "tui-markdown", "url", "wdi", "winapi", + "windows-registry", "winreg", ] @@ -260,9 +262,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "byteorder" @@ -293,9 +295,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.25" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "shlex", ] @@ -311,9 +313,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -354,9 +356,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -364,9 +366,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -379,30 +381,30 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.52" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a554639e42d0c838336fc4fbedb9e2df3ad1fa4acda149f9126b4ccfcd7900f" +checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "color-eyre" @@ -433,9 +435,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "compact_str" @@ -574,7 +576,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -585,7 +587,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -721,7 +723,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.0", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -732,7 +734,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -800,12 +802,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -837,12 +839,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", - "miniz_oxide 0.8.8", + "miniz_oxide 0.8.9", ] [[package]] @@ -937,7 +939,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -988,11 +990,11 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" dependencies = [ - "unicode-width 0.1.14", + "unicode-width 0.2.0", ] [[package]] @@ -1004,7 +1006,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -1066,9 +1068,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", @@ -1083,9 +1085,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -1170,9 +1172,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.6" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ "http", "hyper", @@ -1203,9 +1205,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ "base64 0.22.1", "bytes", @@ -1385,7 +1387,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1457,9 +1459,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ "jiff-static", "log", @@ -1470,13 +1472,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1503,9 +1505,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libloading" @@ -1514,7 +1516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.53.2", ] [[package]] @@ -1529,9 +1531,9 @@ dependencies = [ [[package]] name = "libwdi-sys" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6611a6fbafc5bdf80ab4d2e6be9a63da1d5148f2e9bde3c727c491d1813abbe" +checksum = "a1674529994d22cb89710d297639ab976e5e1d06a0ba397ed0fc25d2211a0eb3" dependencies = [ "bindgen", "cc", @@ -1598,18 +1600,18 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "mach2" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" dependencies = [ "libc", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmem" @@ -1640,9 +1642,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] @@ -1655,7 +1657,7 @@ checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.59.0", ] @@ -1734,23 +1736,24 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1862,7 +1865,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1928,7 +1931,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1990,9 +1993,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", "thiserror 2.0.12", @@ -2063,9 +2066,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "plist" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d" +checksum = "3d77244ce2d584cd84f6a15f86195b8c9b2a0dfbfd817c09e0464244091a58ed" dependencies = [ "base64 0.22.1", "indexmap", @@ -2076,9 +2079,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -2142,12 +2145,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.33" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" +checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" dependencies = [ "proc-macro2", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -2212,9 +2215,9 @@ checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" [[package]] name = "quick-xml" -version = "0.32.0" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "memchr", ] @@ -2262,9 +2265,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" dependencies = [ "cfg_aliases", "libc", @@ -2285,9 +2288,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -2403,9 +2406,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.1", ] @@ -2469,9 +2472,9 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.12.19" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64 0.22.1", "bytes", @@ -2487,12 +2490,10 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", @@ -2555,15 +2556,15 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.101", + "syn 2.0.104", "unicode-ident", ] [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -2614,9 +2615,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ "once_cell", "ring", @@ -2700,7 +2701,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -2767,7 +2768,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -2903,18 +2904,15 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" @@ -2969,7 +2967,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -2991,9 +2989,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -3017,7 +3015,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3175,7 +3173,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3186,17 +3184,16 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -3305,19 +3302,19 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "toml_datetime", - "winnow 0.7.10", + "winnow 0.7.11", ] [[package]] @@ -3378,20 +3375,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -3577,9 +3574,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -3612,7 +3609,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -3647,7 +3644,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3663,9 +3660,9 @@ dependencies = [ [[package]] name = "wdi" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca5fad9b5e7cb471533ea55a131716a846c847fea8d1cb281beb0c14db83ceb" +checksum = "aac8a57ad1cf072ebff2186dfce0c221e976a1c26b0d7b85745cd74497bb54ad" dependencies = [ "bstr", "libwdi-sys", @@ -3694,9 +3691,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" dependencies = [ "rustls-pki-types", ] @@ -3746,19 +3743,19 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" dependencies = [ + "windows-link", "windows-result", "windows-strings", - "windows-targets 0.53.0", ] [[package]] @@ -3772,9 +3769,9 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -3806,6 +3803,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3839,9 +3845,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", @@ -4002,9 +4008,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -4068,28 +4074,28 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -4109,7 +4115,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "synstructure", ] @@ -4149,5 +4155,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] diff --git a/Cargo.toml b/Cargo.toml index 576e0bb..cf25d52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,9 @@ tui-markdown = "0.3.3" ratatui = { version = "0.29.0", features = ["unstable-rendered-line-info"] } clap_complete = "4.5.52" +[target.'cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))'.dependencies] +termios = "0.3.3" + [target.'cfg(windows)'.dependencies] wdi = "0.1.0" deelevate = "0.2.0" diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 8bb20cf..6307d77 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -3,23 +3,89 @@ // SPDX-FileContributor: Written by Rachel Mant use std::fs::File; +use std::io::Write; use std::path::Path; use color_eyre::eyre::Result; pub struct BmdRspInterface { - interface: File, + handle: File, protocol_version: u64, } +const REMOTE_START: &[u8] = b"+#!GA#"; +pub const REMOTE_MAX_MSG_SIZE: usize = 1024; + impl BmdRspInterface { pub fn from_path(serial_port: &Path) -> Result { - Ok(Self { - interface: File::options().read(true).write(true).open(serial_port)?, + // Get the serial interface to the probe open + let handle = File::options().read(true).write(true).open(serial_port)?; + + // Construct an interface object + let mut result = Self { + handle, + // Provide a dummy protocol version for the moment protocol_version: u64::MAX, - }) + }; + + // Call the OS-specific handle configuration function to ready + // the interface handle for use with the remote serial protocol + result.init_handle()?; + + // Start remote protocol communications with the probe + result.buffer_write(REMOTE_START)?; + // let buffer = result.buffer_read(REMOTE_MAX_MSG_SIZE); + + // Now the object is ready to go, return it to the caller + Ok(result) + } + + fn buffer_write(&mut self, message: &[u8]) -> Result<()> + { + Ok(self.handle.write_all(message)?) + } +} + +#[cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))] +impl BmdRspInterface +{ + fn init_handle(&self) -> Result<()> + { + use std::os::fd::AsRawFd; + + #[cfg(any(target_os = "linux", target_os = "android"))] + use termios::os::linux::CRTSCTS; + #[cfg(target_os = "macos")] + use termios::os::macos::CRTSCTS; + use termios::*; + + // Extract the current termios config for the handle + let fd = self.handle.as_raw_fd(); + let mut attrs = Termios::from_fd(fd)?; + + // Reconfigure the attributes for 8-bit characters, no CTS/RTS hardware control flow, + // w/ no model control signalling + attrs.c_cflag &= !(CSIZE | CSTOPB); + attrs.c_cflag |= CS8 | CLOCAL | CREAD | CRTSCTS; + // Disable break character handling and turn off XON/XOFF based control flow + attrs.c_iflag &= !(IGNBRK | IXON | IXOFF | IXANY); + // Disable all signaling, echo, remapping and delays + attrs.c_lflag = 0; + attrs.c_oflag = 0; + // Make reads not block, and set 0.5s for read timeout + attrs.c_cc[VMIN] = 0; + attrs.c_cc[VTIME] = 5; + + // Reconfigure the handle with the new termios config + tcsetattr(fd, TCSANOW, &attrs)?; + + // Let the caller know that we successfully got done + Ok(()) } } + +#[cfg(target_os = "windows")] +impl BmdRspInterface {} From 4694339b2fa25b3bba5c2047a440965f4d23e890 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 05:21:00 +0100 Subject: [PATCH 07/57] serial/remote: Begun building structures and definitions for the BMD remote protocol --- src/serial/mod.rs | 1 + src/serial/remote/mod.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/serial/remote/mod.rs diff --git a/src/serial/mod.rs b/src/serial/mod.rs index 2de8ca9..69d30e9 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -5,3 +5,4 @@ pub mod bmd_rsp; pub mod gdb_rsp; pub mod interface; +mod remote; diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs new file mode 100644 index 0000000..0833bc4 --- /dev/null +++ b/src/serial/remote/mod.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +/// Types implementing this trait implement the common portion of the BMD remote protocol +/// (this includes things like comms initialisation, and clock frequency control) +pub trait BmdRemoteProtocol +{ + // Comms protocol initialisation functions + fn swd_init(&self) -> bool; + fn jtag_init(&self) -> bool; + // Higher level protocol initialisation functions + fn adiv5_init(&self) -> bool; + fn adiv6_init(&self) -> bool; + fn riscv_jtag_init(&self) -> bool; + + // Probe operation control functions + fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev); + fn get_comms_frequency(&self) -> u32; + fn set_comms_frequency(&self, freq: u32) -> bool; + fn target_clk_output_enable(&self, enable: bool); +} + +/// Structure representing a device on the JTAG scan chain +#[allow(unused)] +pub struct JtagDev +{ + idcode: u32, + current_ir: u32, + + dr_prescan: u8, + dr_postscan: u8, + + ir_len: u8, + ir_prescan: u8, + ir_postscan: u8, +} From bca204603a44914599af984a51debd00b1b59f76 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 05:22:25 +0100 Subject: [PATCH 08/57] serial/remote: Moved a definition for the RSP into the proper module --- src/serial/bmd_rsp.rs | 1 - src/serial/remote/mod.rs | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 6307d77..56d27fa 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -15,7 +15,6 @@ pub struct BmdRspInterface } const REMOTE_START: &[u8] = b"+#!GA#"; -pub const REMOTE_MAX_MSG_SIZE: usize = 1024; impl BmdRspInterface { diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 0833bc4..e90af1e 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -2,6 +2,10 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant +/// This is the max possible size of a remote protocol packet which a hard limitation of the +/// firmware on the probe - 1KiB is all the buffer that could be spared. +pub const REMOTE_MAX_MSG_SIZE: usize = 1024; + /// Types implementing this trait implement the common portion of the BMD remote protocol /// (this includes things like comms initialisation, and clock frequency control) pub trait BmdRemoteProtocol From f75431a9db3d51ad6ec10124b9f690a7efd75f0f Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 05:28:52 +0100 Subject: [PATCH 09/57] serial/bmd_rsp: Built out machinary for displaying debug information about probe communications --- src/serial/bmd_rsp.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 56d27fa..1ad3994 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -7,6 +7,7 @@ use std::io::Write; use std::path::Path; use color_eyre::eyre::Result; +use log::debug; pub struct BmdRspInterface { @@ -14,13 +15,14 @@ pub struct BmdRspInterface protocol_version: u64, } -const REMOTE_START: &[u8] = b"+#!GA#"; +const REMOTE_START: &str = "+#!GA#"; impl BmdRspInterface { pub fn from_path(serial_port: &Path) -> Result { // Get the serial interface to the probe open + debug!("Opening probe interface at {:?}", serial_port); let handle = File::options().read(true).write(true).open(serial_port)?; // Construct an interface object @@ -42,9 +44,10 @@ impl BmdRspInterface Ok(result) } - fn buffer_write(&mut self, message: &[u8]) -> Result<()> + fn buffer_write(&mut self, message: &str) -> Result<()> { - Ok(self.handle.write_all(message)?) + debug!("BMD RSP write: {}", message); + Ok(self.handle.write_all(message.as_bytes())?) } } From 3c43953f8f93f2d539e7bffaedcde760e273056b Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 06:42:20 +0100 Subject: [PATCH 10/57] serial/bmd_rsp: Built out the logic for reading responses back from the probe safely but speedily --- src/serial/bmd_rsp.rs | 111 ++++++++++++++++++++++++++++++++++++++- src/serial/mod.rs | 2 +- src/serial/remote/mod.rs | 4 ++ 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 1ad3994..6b25f5e 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -9,10 +9,16 @@ use std::path::Path; use color_eyre::eyre::Result; use log::debug; +use crate::serial::remote::{REMOTE_EOM, REMOTE_MAX_MSG_SIZE, REMOTE_RESP}; + pub struct BmdRspInterface { handle: File, protocol_version: u64, + + read_buffer: [u8; REMOTE_MAX_MSG_SIZE], + read_buffer_fullness: usize, + read_buffer_offset: usize, } const REMOTE_START: &str = "+#!GA#"; @@ -30,6 +36,14 @@ impl BmdRspInterface handle, // Provide a dummy protocol version for the moment protocol_version: u64::MAX, + + // Initialise an empty read buffer to use for more efficiently reading + // probe responses, being mindful that there's no good way to find out + // how much data is waiting for us from the probe, so it's this or use + // a read call a byte, which is extremely expensive! + read_buffer: [0; REMOTE_MAX_MSG_SIZE], + read_buffer_fullness: 0, + read_buffer_offset: 0, }; // Call the OS-specific handle configuration function to ready @@ -38,17 +52,69 @@ impl BmdRspInterface // Start remote protocol communications with the probe result.buffer_write(REMOTE_START)?; - // let buffer = result.buffer_read(REMOTE_MAX_MSG_SIZE); + let buffer = result.buffer_read()?; // Now the object is ready to go, return it to the caller Ok(result) } - fn buffer_write(&mut self, message: &str) -> Result<()> + pub(crate) fn buffer_write(&mut self, message: &str) -> Result<()> { debug!("BMD RSP write: {}", message); Ok(self.handle.write_all(message.as_bytes())?) } + + pub(crate) fn buffer_read(&mut self) -> Result + { + // First drain the buffer till we see a start-of-response byte + let mut response = 0; + while response != REMOTE_RESP { + if self.read_buffer_offset == self.read_buffer_fullness { + self.read_more_data()?; + } + response = self.read_buffer[self.read_buffer_offset]; + self.read_buffer_offset += 1; + } + + // Now collect the response + let mut buffer = [0u8; REMOTE_MAX_MSG_SIZE]; + let mut offset = 0; + while offset < buffer.len() { + // Check if we need more data or should use what's in the buffer already + if self.read_buffer_offset == self.read_buffer_fullness { + self.read_more_data()?; + } + // Look for an end of packet marker + let mut response_length = 0; + while self.read_buffer_offset + response_length < self.read_buffer_fullness && + offset + response_length < buffer.len() + { + if self.read_buffer[self.read_buffer_offset + response_length] == REMOTE_EOM { + response_length += 1; + break; + } + response_length += 1; + } + // We now either have a REMOTE_EOM or need all the data from the buffer + let read_buffer_offset = self.read_buffer_offset; + buffer[offset..offset + response_length] + .copy_from_slice(&self.read_buffer[read_buffer_offset..read_buffer_offset + response_length]); + self.read_buffer_offset += response_length; + offset += response_length - 1; + // If this was because of REMOTE_EOM, return + if buffer[offset] == REMOTE_EOM { + buffer[offset] = 0; + let result = unsafe { String::from_utf8_unchecked(buffer[..offset].to_vec()) }; + debug!("BMD RSP read: {}", result); + return Ok(result); + } + offset += 1; + } + // If we fell out here, we got what we could so return that.. + let result = unsafe { String::from_utf8_unchecked(buffer.to_vec()) }; + debug!("BMD RSP read: {}", result); + Ok(result) + } } #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))] @@ -87,6 +153,47 @@ impl BmdRspInterface // Let the caller know that we successfully got done Ok(()) } + + fn read_more_data(&mut self) -> Result<()> + { + use std::io::Read; + use std::mem::MaybeUninit; + use std::os::fd::AsRawFd; + use std::ptr::null_mut; + + use color_eyre::eyre::eyre; + use libc::{FD_SET, FD_SETSIZE, FD_ZERO, c_int, fd_set, select, timeval}; + + // Set up a FD set that describes our handle's FD + let mut select_set = MaybeUninit::::uninit(); + unsafe { + FD_ZERO(select_set.as_mut_ptr()); + FD_SET(self.handle.as_raw_fd(), select_set.as_mut_ptr()); + } + let mut select_set = unsafe { select_set.assume_init() }; + + // Wait for more data from the probe for up to 2 seconds + let mut timeout = timeval { + tv_sec: 2, + tv_usec: 0, + }; + let result = unsafe { select(FD_SETSIZE as c_int, &mut select_set, null_mut(), null_mut(), &mut timeout) }; + + if result < 0 { + // If the select call failed, bail + Err(eyre!("Failed on select")) + } else if result == 0 { + // If we timed out then bail differently + Err(eyre!("Timeout while waiting for BMD remote protocol response")) + } else { + // Otherwise we now know there's data, so try to fill the read buffer + let bytes_received = self.handle.read(&mut self.read_buffer)?; + // Now we have more data, so update the read buffer counters + self.read_buffer_fullness = bytes_received; + self.read_buffer_offset = 0; + Ok(()) + } + } } #[cfg(target_os = "windows")] diff --git a/src/serial/mod.rs b/src/serial/mod.rs index 69d30e9..180001a 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -5,4 +5,4 @@ pub mod bmd_rsp; pub mod gdb_rsp; pub mod interface; -mod remote; +pub mod remote; diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index e90af1e..a9734aa 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -6,6 +6,10 @@ /// firmware on the probe - 1KiB is all the buffer that could be spared. pub const REMOTE_MAX_MSG_SIZE: usize = 1024; +pub const REMOTE_SOM: u8 = b'!'; +pub const REMOTE_EOM: u8 = b'#'; +pub const REMOTE_RESP: u8 = b'&'; + /// Types implementing this trait implement the common portion of the BMD remote protocol /// (this includes things like comms initialisation, and clock frequency control) pub trait BmdRemoteProtocol From 08969a7a3ae2bf649e4eca392930827b307a90a7 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 06:43:31 +0100 Subject: [PATCH 11/57] bmputil-cli: Make use of the probe's BMD serial interface to begin implementing list_targets() --- src/bin/bmputil-cli.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/bmputil-cli.rs b/src/bin/bmputil-cli.rs index 28437ca..f0323b1 100644 --- a/src/bin/bmputil-cli.rs +++ b/src/bin/bmputil-cli.rs @@ -378,6 +378,7 @@ fn display_releases(paths: &ProjectDirs) -> Result<()> fn list_targets(probe: BmpDevice) -> Result<()> { + let bmd_interface = probe.bmd_serial_interface()?; Ok(()) } From 54f478f7d3465125554baacb17b8ef06ef005e38 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 07:22:53 +0100 Subject: [PATCH 12/57] serial/remote: Added response constants and documented the markers --- src/serial/remote/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index a9734aa..0e792a1 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -6,10 +6,22 @@ /// firmware on the probe - 1KiB is all the buffer that could be spared. pub const REMOTE_MAX_MSG_SIZE: usize = 1024; +/// Start of message marker for the protocol pub const REMOTE_SOM: u8 = b'!'; +/// End of message marker for the protocol pub const REMOTE_EOM: u8 = b'#'; +/// Response marker for the protocol pub const REMOTE_RESP: u8 = b'&'; +/// Probe response was okay and the data returned is valid +pub const REMOTE_RESP_OK: u8 = b'K'; +/// Probe found an error with a request parameter +pub const REMOTE_RESP_PARERR: u8 = b'P'; +/// Probe encountered an error executing the request +pub const REMOTE_RESP_ERR: u8 = b'E'; +/// Probe does not support the request made +pub const REMOTE_RESP_NOTSUP: u8 = b'N'; + /// Types implementing this trait implement the common portion of the BMD remote protocol /// (this includes things like comms initialisation, and clock frequency control) pub trait BmdRemoteProtocol From 05f65739f227b779f740427dff9873aabfc1a79b Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 07:23:16 +0100 Subject: [PATCH 13/57] serial/remote: Implemented machinary for decoding a probe response to a number --- src/serial/remote/mod.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 0e792a1..095db39 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -55,3 +55,22 @@ pub struct JtagDev ir_prescan: u8, ir_postscan: u8, } + +pub fn decode_response(response: &str, digits: usize) -> u64 +{ + // Clamp the number of digits to the number actually available + let digits = if digits > response.len() { + response.len() + } else { + digits + }; + + let mut value = 0; + // For each byte in the response that we care about, un-hexify the byte + for byte in response[..digits].chars() { + value <<= 4; + value |= byte.to_digit(16).unwrap() as u64; + } + + value +} From a01234086785ed62b104c37c31fc634ee528a3ea Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 07:24:05 +0100 Subject: [PATCH 14/57] serial/bmd_rsp: Created a protocol versioning enum to describe what a probe talks --- src/serial/bmd_rsp.rs | 8 ++++---- src/serial/remote/mod.rs | 11 +++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 6b25f5e..ee657d3 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -9,12 +9,12 @@ use std::path::Path; use color_eyre::eyre::Result; use log::debug; -use crate::serial::remote::{REMOTE_EOM, REMOTE_MAX_MSG_SIZE, REMOTE_RESP}; +use crate::serial::remote::*; pub struct BmdRspInterface { handle: File, - protocol_version: u64, + protocol_version: ProtocolVersion, read_buffer: [u8; REMOTE_MAX_MSG_SIZE], read_buffer_fullness: usize, @@ -34,8 +34,8 @@ impl BmdRspInterface // Construct an interface object let mut result = Self { handle, - // Provide a dummy protocol version for the moment - protocol_version: u64::MAX, + // We start out by not knowing what version of protocol the probe talks + protocol_version: ProtocolVersion::Unknown, // Initialise an empty read buffer to use for more efficiently reading // probe responses, being mindful that there's no good way to find out diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 095db39..5da5c6a 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -56,6 +56,17 @@ pub struct JtagDev ir_postscan: u8, } +pub enum ProtocolVersion +{ + Unknown, + V0, + V0Plus, + V1, + V2, + V3, + V4, +} + pub fn decode_response(response: &str, digits: usize) -> u64 { // Clamp the number of digits to the number actually available From c2ae81397b7f8af6b9c47507ff431becf5870cdf Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 20 Jun 2025 07:24:39 +0100 Subject: [PATCH 15/57] serial/bmd_rsp: Implemented logic for reading out a probe's protocol version number and translating it into a protocol version enum value --- src/serial/bmd_rsp.rs | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index ee657d3..82dae30 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -6,7 +6,7 @@ use std::fs::File; use std::io::Write; use std::path::Path; -use color_eyre::eyre::Result; +use color_eyre::eyre::{Result, eyre}; use log::debug; use crate::serial::remote::*; @@ -22,6 +22,7 @@ pub struct BmdRspInterface } const REMOTE_START: &str = "+#!GA#"; +const REMOTE_HL_CHECK: &str = "!HC#"; impl BmdRspInterface { @@ -53,6 +54,47 @@ impl BmdRspInterface // Start remote protocol communications with the probe result.buffer_write(REMOTE_START)?; let buffer = result.buffer_read()?; + // Check if that failed for any reason + if buffer.is_empty() || buffer.as_bytes()[0] != REMOTE_RESP_OK { + let message = if buffer.len() > 1 { + &buffer[1..] + } else { + "unknown" + }; + return Err(eyre!("Remote protocol startup failed, error {}", message)); + } + // It did not, grand - we now have the firmware version string, so log it + debug!("Remote is {}", &buffer[1..]); + + // Next, ask the probe for its protocol version number. + // For historical reasons this is part of the "high level" protocol set, but is + // actually a general request. + result.buffer_write(REMOTE_HL_CHECK)?; + let buffer = result.buffer_read()?; + // Check for communication failures + if buffer.is_empty() { + return Err(eyre!("Probe failed to respond at all to protocol version request")); + } else if buffer.as_bytes()[0] != REMOTE_RESP_OK && buffer.as_bytes()[0] != REMOTE_RESP_NOTSUP { + // If the probe responded with anything other than OK or not supported, we're done + return Err(eyre!("Probe responded improperly to protocol version request with {}", buffer)); + } + // If the request failed by way of a not implemented response, we're on a v0 protocol probe + if buffer.as_bytes()[0] == REMOTE_RESP_NOTSUP { + result.protocol_version = ProtocolVersion::V0; + } else { + // Parse out the version number from the response + let version = decode_response(&buffer[1..], 8); + // Then decode/translate that to a protocol version enum value + result.protocol_version = match version { + // Protocol version number 0 coresponds to an enchanced v0 probe protocol ("v0+") + 0 => ProtocolVersion::V0Plus, + 1 => ProtocolVersion::V1, + 2 => ProtocolVersion::V2, + 3 => ProtocolVersion::V3, + 4 => ProtocolVersion::V4, + _ => return Err(eyre!("Unknown remote protocol version {}", version)), + }; + } // Now the object is ready to go, return it to the caller Ok(result) From d5b68fdcd395a228bbc8534f1f729784fcc8a76f Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 21 Jun 2025 05:33:24 +0100 Subject: [PATCH 16/57] serial/remote: Defined the SWD protocol interface as a trait --- src/serial/remote/mod.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 5da5c6a..cfba494 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -2,6 +2,8 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant +use color_eyre::eyre::Result; + /// This is the max possible size of a remote protocol packet which a hard limitation of the /// firmware on the probe - 1KiB is all the buffer that could be spared. pub const REMOTE_MAX_MSG_SIZE: usize = 1024; @@ -27,7 +29,7 @@ pub const REMOTE_RESP_NOTSUP: u8 = b'N'; pub trait BmdRemoteProtocol { // Comms protocol initialisation functions - fn swd_init(&self) -> bool; + fn swd_init(&self) -> Result>; fn jtag_init(&self) -> bool; // Higher level protocol initialisation functions fn adiv5_init(&self) -> bool; @@ -41,6 +43,15 @@ pub trait BmdRemoteProtocol fn target_clk_output_enable(&self, enable: bool); } +/// Types implementing this trait provide raw SWD access to targets over the BMD remote protocol +pub trait BmdSwdProtocol +{ + fn seq_in(&self, clock_cycles: usize) -> u32; + fn seq_in_parity(&self, clock_cycles: usize) -> Option; + fn seq_out(&self, value: u32, clock_cycles: usize); + fn seq_out_parity(&self, value: u32, clock_cycles: usize); +} + /// Structure representing a device on the JTAG scan chain #[allow(unused)] pub struct JtagDev From 871a074fb7d77b51ba9ac1e94ba44a0abf9cc567 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 21 Jun 2025 05:45:26 +0100 Subject: [PATCH 17/57] serial/remote: Defined the JTAG protocol interface as a trait --- src/serial/remote/mod.rs | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index cfba494..7cbec23 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -30,7 +30,7 @@ pub trait BmdRemoteProtocol { // Comms protocol initialisation functions fn swd_init(&self) -> Result>; - fn jtag_init(&self) -> bool; + fn jtag_init(&self) -> Result>; // Higher level protocol initialisation functions fn adiv5_init(&self) -> bool; fn adiv6_init(&self) -> bool; @@ -52,6 +52,43 @@ pub trait BmdSwdProtocol fn seq_out_parity(&self, value: u32, clock_cycles: usize); } +/// Types implementing this trait provide raw JTAG access to targets over the BMD remote protocol +pub trait BmdJtagProtocol +{ + // Note: signal names are as for the device under test. + + /// Executes a state machine reset to ensure a clean, known TAP state + fn tap_reset(&self); + /// Executes one state transition in the JTAG TAP state machine: + /// - Ensure TCK is low + /// - Assert the values of TMS and TDI + /// - Assert TCK (TMS and TDO are latched on rising edge) + /// - Capture the value of TDO + /// - Release TCK + fn tap_next(&self, tms: bool, tdi: bool) -> bool; + /// Performs a sequence of cycles with the provided bitstring of TMS states + fn tap_tms_seq(&self, tms_states: u32, clock_cycles: usize); + /// Shift out a sequence on TDI, capture data from TDO. Holds TMS low till the final cycle, + /// then uses the value of final_tms to determine what state to put TMS into. + /// - This is not endian safe: The first byte will always be shifted out first. + /// - The TDO buffer may be given as None to ignore captured data. + /// - The TDI buffer may be given as None to only capture result data (if no data is given, dummy data will be + /// synthesised for the request cycle) + fn tap_tdi_tdo_seq( + &self, + data_out: Option<&mut [u8]>, + final_tms: bool, + data_in: Option<&[u8]>, + clock_cycles: usize, + ); + /// Shift out a sequence on TDI. Holds TMS low till the final cycle, then uses the value + /// of final_tms to determine what state to put tMS into. + /// - This is not endian safe: The first byte will always be shifted out first. + fn tap_tdi_seq(&self, final_tms: bool, data_in: &[u8], clock_cycles: usize); + /// Perform a series of cycles on the state machine with TMS and TDI held in a set state + fn tap_cycle(&self, tms: bool, tdi: bool, clock_cycles: usize); +} + /// Structure representing a device on the JTAG scan chain #[allow(unused)] pub struct JtagDev From aeac1ee4f5383c7b2a169d947684f81367322db0 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 21 Jun 2025 07:49:26 +0100 Subject: [PATCH 18/57] serial/remote/protocol_v0: Created a stub implementation of the v0 remote protocol object --- src/serial/remote/mod.rs | 2 + src/serial/remote/protocol_v0.rs | 84 ++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/serial/remote/protocol_v0.rs diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 7cbec23..bfb8ec4 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -4,6 +4,8 @@ use color_eyre::eyre::Result; +mod protocol_v0; + /// This is the max possible size of a remote protocol packet which a hard limitation of the /// firmware on the probe - 1KiB is all the buffer that could be spared. pub const REMOTE_MAX_MSG_SIZE: usize = 1024; diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs new file mode 100644 index 0000000..33a2a33 --- /dev/null +++ b/src/serial/remote/protocol_v0.rs @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::sync::{Arc, Mutex}; + +use color_eyre::eyre::{Result, eyre}; +use log::warn; + +use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::{BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev}; + +pub struct RemoteV0 +{ + #[allow(unused)] + interface: Arc>, +} + +impl From>> for RemoteV0 +{ + fn from(interface: Arc>) -> Self + { + warn!( + "Probe firmware does not support the newer JTAG commands, ADIv5 acceleration, ADIv6 acceleration or \ + RISC-V JTAG acceleration, please update it" + ); + Self::new(interface) + } +} + +impl RemoteV0 +{ + pub(crate) fn new(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdRemoteProtocol for RemoteV0 +{ + fn jtag_init(&self) -> Result> + { + Err(eyre!("")) + } + + fn swd_init(&self) -> Result> + { + Err(eyre!("")) + } + + fn adiv5_init(&self) -> bool + { + false + } + + fn adiv6_init(&self) -> bool + { + false + } + + fn riscv_jtag_init(&self) -> bool + { + false + } + + fn add_jtag_dev(&self, _dev_index: u32, _jtag_dev: &JtagDev) {} + + fn get_comms_frequency(&self) -> u32 + { + u32::MAX + } + + fn set_comms_frequency(&self, _freq: u32) -> bool + { + false + } + + fn target_clk_output_enable(&self, _enable: bool) + { + // + } +} From 39129e644eda4f3dd2fd20af8e87981e358743fd Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 21 Jun 2025 07:58:58 +0100 Subject: [PATCH 19/57] serial/remote: Built machinary to allow a remote protocol implementation object to be retrieved from the BMD RSP interface object --- src/serial/bmd_rsp.rs | 9 +++++++++ src/serial/remote/mod.rs | 17 +++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 82dae30..200eec7 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -5,6 +5,7 @@ use std::fs::File; use std::io::Write; use std::path::Path; +use std::sync::{Arc, Mutex}; use color_eyre::eyre::{Result, eyre}; use log::debug; @@ -100,6 +101,14 @@ impl BmdRspInterface Ok(result) } + /// Extract the remote protocol object to use to talk with this probe + pub fn remote(self) -> Box + { + let interface = Arc::new(Mutex::new(self)); + let iface = interface.lock().unwrap(); + iface.protocol_version.protocol_impl(interface.clone()) + } + pub(crate) fn buffer_write(&mut self, message: &str) -> Result<()> { debug!("BMD RSP write: {}", message); diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index bfb8ec4..0a32f1e 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -2,8 +2,13 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant +use std::sync::{Arc, Mutex}; + use color_eyre::eyre::Result; +use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::protocol_v0::RemoteV0; + mod protocol_v0; /// This is the max possible size of a remote protocol packet which a hard limitation of the @@ -135,3 +140,15 @@ pub fn decode_response(response: &str, digits: usize) -> u64 value } + +impl ProtocolVersion +{ + /// Extract an instance of the BMD remote protocol communication object for this version of the protocol + pub fn protocol_impl(&self, interface: Arc>) -> Box + { + match self { + Self::V0 => Box::new(RemoteV0::from(interface)), + _ => todo!(), + } + } +} From d793fe64588e153b54b94fb01b106a18f74eae7b Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 21 Jun 2025 11:13:11 +0100 Subject: [PATCH 20/57] serial/remote/protocol_v0: Begun implementing handling for the JTAG protocol --- src/serial/remote/protocol_v0.rs | 89 ++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index 33a2a33..44b1466 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -2,20 +2,27 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; use color_eyre::eyre::{Result, eyre}; -use log::warn; +use log::{debug, warn}; use crate::serial::bmd_rsp::BmdRspInterface; -use crate::serial::remote::{BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev}; +use crate::serial::remote::{BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR}; pub struct RemoteV0 +{ + interface: Arc>, +} + +pub struct RemoteV0JTAG { #[allow(unused)] interface: Arc>, } +const REMOTE_JTAG_INIT: &str = "!JS#"; + impl From>> for RemoteV0 { fn from(interface: Arc>) -> Self @@ -36,13 +43,38 @@ impl RemoteV0 interface, } } + + fn interface(&self) -> MutexGuard<'_, BmdRspInterface> + { + self.interface.lock().unwrap() + } + + pub(crate) fn clone_interface(&self) -> Arc> + { + self.interface.clone() + } } impl BmdRemoteProtocol for RemoteV0 { fn jtag_init(&self) -> Result> { - Err(eyre!("")) + // Try to have the probe initialise JTAG comms to any connected targets + debug!("Remote JTAG init"); + self.interface().buffer_write(REMOTE_JTAG_INIT)?; + let buffer = self.interface().buffer_read()?; + // If that failed for some reason, report it and abort + if buffer.is_empty() || buffer.as_bytes()[0] == REMOTE_RESP_ERR { + let message = if buffer.len() > 1 { + &buffer[1..] + } else { + "unknown" + }; + Err(eyre!("Remote JTAG init failed, error {}", message)) + } else { + // Otherwise, return the v0 JTAG protocol implementation + Ok(Box::new(RemoteV0JTAG::from(self.clone_interface()))) + } } fn swd_init(&self) -> Result> @@ -82,3 +114,52 @@ impl BmdRemoteProtocol for RemoteV0 // } } + +impl From>> for RemoteV0JTAG +{ + fn from(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdJtagProtocol for RemoteV0JTAG +{ + fn tap_reset(&self) + { + // + } + + fn tap_next(&self, _tms: bool, _tdi: bool) -> bool + { + false + } + + fn tap_tms_seq(&self, _tms_states: u32, _clock_cycles: usize) + { + // + } + + fn tap_tdi_tdo_seq( + &self, + _data_out: Option<&mut [u8]>, + _final_tms: bool, + _data_in: Option<&[u8]>, + _clock_cycles: usize, + ) + { + // + } + + fn tap_tdi_seq(&self, _final_tms: bool, _data_in: &[u8], _clock_cycles: usize) + { + // + } + + fn tap_cycle(&self, _tms: bool, _tdi: bool, _clock_cycles: usize) + { + // + } +} From 0ef90d336fd1823394a5025568eb93ed0405ca7e Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 21 Jun 2025 11:20:59 +0100 Subject: [PATCH 21/57] serial/remote/protocol_v0: Begun implementing handling for the SWD protocol --- src/serial/remote/protocol_v0.rs | 56 +++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index 44b1466..d445454 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -21,6 +21,13 @@ pub struct RemoteV0JTAG interface: Arc>, } +pub struct RemoteV0SWD +{ + #[allow(unused)] + interface: Arc>, +} + +const REMOTE_SWD_INIT: &str = "!SS#"; const REMOTE_JTAG_INIT: &str = "!JS#"; impl From>> for RemoteV0 @@ -79,7 +86,21 @@ impl BmdRemoteProtocol for RemoteV0 fn swd_init(&self) -> Result> { - Err(eyre!("")) + debug!("Remote SWD init"); + self.interface().buffer_write(REMOTE_SWD_INIT)?; + let buffer = self.interface().buffer_read()?; + // If that failed for some reason, report it and abort + if buffer.is_empty() || buffer.as_bytes()[0] == REMOTE_RESP_ERR { + let message = if buffer.len() > 1 { + &buffer[1..] + } else { + "unknown" + }; + Err(eyre!("Remote SWD init failed, error {}", message)) + } else { + // Otherwise, return the v0 JTAG protocol implementation + Ok(Box::new(RemoteV0SWD::from(self.clone_interface()))) + } } fn adiv5_init(&self) -> bool @@ -163,3 +184,36 @@ impl BmdJtagProtocol for RemoteV0JTAG // } } + +impl From>> for RemoteV0SWD +{ + fn from(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdSwdProtocol for RemoteV0SWD +{ + fn seq_in(&self, _clock_cycles: usize) -> u32 + { + 0 + } + + fn seq_in_parity(&self, _clock_cycles: usize) -> Option + { + None + } + + fn seq_out(&self, _value: u32, _clock_cycles: usize) + { + // + } + + fn seq_out_parity(&self, _value: u32, _clock_cycles: usize) + { + // + } +} From 053ad3f551cb247ad6f49bb5d0dda88c1377096d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 00:32:51 +0100 Subject: [PATCH 22/57] serial/remote/protocol_v0: Created a type for the v0+ protocol which includes ADIv5 acceleration but is otherwise the same as v0 --- src/serial/remote/mod.rs | 3 +- src/serial/remote/protocol_v0.rs | 63 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 0a32f1e..5a4bbbb 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -7,7 +7,7 @@ use std::sync::{Arc, Mutex}; use color_eyre::eyre::Result; use crate::serial::bmd_rsp::BmdRspInterface; -use crate::serial::remote::protocol_v0::RemoteV0; +use crate::serial::remote::protocol_v0::{RemoteV0, RemoteV0Plus}; mod protocol_v0; @@ -148,6 +148,7 @@ impl ProtocolVersion { match self { Self::V0 => Box::new(RemoteV0::from(interface)), + Self::V0Plus => Box::new(RemoteV0Plus::from(interface)), _ => todo!(), } } diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index d445454..a87f003 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -15,6 +15,8 @@ pub struct RemoteV0 interface: Arc>, } +pub struct RemoteV0Plus(RemoteV0); + pub struct RemoteV0JTAG { #[allow(unused)] @@ -136,6 +138,67 @@ impl BmdRemoteProtocol for RemoteV0 } } +impl From>> for RemoteV0Plus +{ + fn from(interface: Arc>) -> Self + { + warn!( + "Probe firmware does not support the newer JTAG commands, ADIv6 acceleration or RISC-V JTAG acceleration, \ + please update it" + ); + Self(RemoteV0::new(interface)) + } +} + +impl BmdRemoteProtocol for RemoteV0Plus +{ + fn jtag_init(&self) -> Result> + { + self.0.jtag_init() + } + + fn swd_init(&self) -> Result> + { + self.0.swd_init() + } + + fn adiv5_init(&self) -> bool + { + warn!("Please update your probe's firmware for improved error handling"); + false + } + + fn adiv6_init(&self) -> bool + { + self.0.adiv6_init() + } + + fn riscv_jtag_init(&self) -> bool + { + self.0.riscv_jtag_init() + } + + fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev) + { + self.0.add_jtag_dev(dev_index, jtag_dev); + } + + fn get_comms_frequency(&self) -> u32 + { + self.0.get_comms_frequency() + } + + fn set_comms_frequency(&self, freq: u32) -> bool + { + self.0.set_comms_frequency(freq) + } + + fn target_clk_output_enable(&self, enable: bool) + { + self.0.target_clk_output_enable(enable); + } +} + impl From>> for RemoteV0JTAG { fn from(interface: Arc>) -> Self From ce0345df0ea2f0dc5f3695118d2549b9e80ee349 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 00:33:28 +0100 Subject: [PATCH 23/57] serial/remote/protocol_v0: Added the warnings for the acceleration interfaces that v0 doesn't implement --- src/serial/remote/protocol_v0.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index a87f003..75364a7 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -107,16 +107,22 @@ impl BmdRemoteProtocol for RemoteV0 fn adiv5_init(&self) -> bool { + warn!("Falling back to non-accelerated probe interface"); + warn!("Please update your probe's firmware for a substantial speed increase"); false } fn adiv6_init(&self) -> bool { + warn!("Falling back to non-accelerated probe interface"); + warn!("Please update your probe's firmware for a substantial speed increase"); false } fn riscv_jtag_init(&self) -> bool { + warn!("Falling back to non-accelerated probe interface"); + warn!("Please update your probe's firmware for a substantial speed increase"); false } From d5f5ae0b431a7bb8a5c7e79ed9bf394571b6275a Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 00:40:37 +0100 Subject: [PATCH 24/57] serial/remote: Cleaned up what is public and what is not from this module tree --- src/serial/remote/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 5a4bbbb..8ceaade 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -111,7 +111,7 @@ pub struct JtagDev ir_postscan: u8, } -pub enum ProtocolVersion +pub(crate) enum ProtocolVersion { Unknown, V0, From 34ceac990e3a91e35cc2776449d3d151cdf63828 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 01:54:47 +0100 Subject: [PATCH 25/57] serial/remote/adi: Defined structures for storing the details of ADIv5 APs and DPs --- src/serial/remote/adi.rs | 70 ++++++++++++++++++++++++++++++++++++++++ src/serial/remote/mod.rs | 1 + 2 files changed, 71 insertions(+) create mode 100644 src/serial/remote/adi.rs diff --git a/src/serial/remote/adi.rs b/src/serial/remote/adi.rs new file mode 100644 index 0000000..2215bb2 --- /dev/null +++ b/src/serial/remote/adi.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::sync::Arc; + +use crate::serial::remote::BmdAdiV5Protocol; + +type TargetAddr32 = u32; +type TargetAddr64 = u64; + +/// The ADIv5 debug port associated with a JTAG TAP or a SWD interface drop of an ARM debug based device +#[allow(unused)] +pub struct AdiV5DebugPort +{ + /// The index of the device on the JTAG chain or DP index on SWD + dev_index: u8, + /// Whether a fault has occured, and which one + fault: u8, + /// Bitfield of the DP's quirks such as if it's a minimal DP or has the duped AP bug + quirks: u8, + /// DP version + version: u8, + + /// DPv2+ specific target selection value + targetsel: u32, + + /// DP designer (not impplementer!) + designer_code: u16, + /// DP partno + partno: u16, + + /// TARGETID designer, present on DPv2+ + target_designer_code: u16, + /// TARGETID partno, present on DPv2+ + target_partno: u16, + + /// DPv3+ bus address width + address_width: u8, + + /// The remote protocol implementation to talk to the DP against + remote: Arc, +} + +/// An ADIv5 access port associated with an ADIv5 debug port on a device +#[allow(unused)] +pub struct AdiV5AccessPort +{ + /// The debug port this AP is asociated with + dp: Arc, + /// The AP's index on the DP + index: u8, + /// Flags associated with this AP such as whether the AP has system memory attached, + /// or is 64-bit instead of (the default of) 32-bit + flags: u8, + + /// The value read out from the ID register for this AP + idr: u32, + /// The base address of the ROM tables associated with this AP + base: TargetAddr64, + /// The Control and Status Word value associated with accessing this AP + csw: u32, + /// A copy of any attached Cortex-M core's DEMCR value when we first see the core + cortexm_demcr: u32, + + /// AP designer code + designer_code: u16, + /// AP partno + partno: u16, +} diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 8ceaade..6aea807 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -9,6 +9,7 @@ use color_eyre::eyre::Result; use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::protocol_v0::{RemoteV0, RemoteV0Plus}; +pub mod adi; mod protocol_v0; /// This is the max possible size of a remote protocol packet which a hard limitation of the From 80487696224c63c667121446de6ee7a839b0b898 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 02:14:44 +0100 Subject: [PATCH 26/57] serial/remote: Defined a trait for representing accelerated ADIv5 communications with a target --- src/serial/remote/adi.rs | 5 +---- src/serial/remote/mod.rs | 34 +++++++++++++++++++++++++++++++- src/serial/remote/protocol_v0.rs | 12 ++++++----- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/serial/remote/adi.rs b/src/serial/remote/adi.rs index 2215bb2..beca060 100644 --- a/src/serial/remote/adi.rs +++ b/src/serial/remote/adi.rs @@ -4,10 +4,7 @@ use std::sync::Arc; -use crate::serial::remote::BmdAdiV5Protocol; - -type TargetAddr32 = u32; -type TargetAddr64 = u64; +use crate::serial::remote::{BmdAdiV5Protocol, TargetAddr64}; /// The ADIv5 debug port associated with a JTAG TAP or a SWD interface drop of an ARM debug based device #[allow(unused)] diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 6aea807..1ad3f1b 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -7,6 +7,7 @@ use std::sync::{Arc, Mutex}; use color_eyre::eyre::Result; use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v0::{RemoteV0, RemoteV0Plus}; pub mod adi; @@ -32,6 +33,19 @@ pub const REMOTE_RESP_ERR: u8 = b'E'; /// Probe does not support the request made pub const REMOTE_RESP_NOTSUP: u8 = b'N'; +pub type TargetAddr32 = u32; +pub type TargetAddr64 = u64; + +/// Allignments available for use by memory accesses +#[repr(u8)] +pub enum Align +{ + As8Bit, + As16Bit, + As32Bit, + As64Bit, +} + /// Types implementing this trait implement the common portion of the BMD remote protocol /// (this includes things like comms initialisation, and clock frequency control) pub trait BmdRemoteProtocol @@ -40,7 +54,7 @@ pub trait BmdRemoteProtocol fn swd_init(&self) -> Result>; fn jtag_init(&self) -> Result>; // Higher level protocol initialisation functions - fn adiv5_init(&self) -> bool; + fn adiv5_init(&self) -> Option>; fn adiv6_init(&self) -> bool; fn riscv_jtag_init(&self) -> bool; @@ -97,6 +111,24 @@ pub trait BmdJtagProtocol fn tap_cycle(&self, tms: bool, tdi: bool, clock_cycles: usize); } +/// Types implementing this trait provide accelerated ADIv5 access to targets over the BMD remote protocol +pub trait BmdAdiV5Protocol +{ + /// Perform a raw AP or DP register access against the target, reporting the read result back + fn raw_access(&self, dp: AdiV5DebugPort, rnw: u8, addr: u16, value: u32) -> u32; + /// Read a DP (or AP*) register from the target + fn dp_read(&self, dp: AdiV5DebugPort, addr: u16) -> u32; + /// Read an AP register from the target + fn ap_read(&self, ap: AdiV5AccessPort, addr: u16) -> u32; + /// Write an AP register on the target + fn ap_write(&self, ap: AdiV5AccessPort, addr: u16, value: u32); + /// Read memory associated with an AP from the target into the buffer passed to dest + fn mem_read(&self, ap: AdiV5AccessPort, dest: &mut [u8], src: TargetAddr64); + /// Write memory associated with an AP to the target from the buffer passed in src and with the + /// access alignment given by align + fn mem_write(&self, ap: AdiV5AccessPort, dest: TargetAddr64, src: &[u8], align: Align); +} + /// Structure representing a device on the JTAG scan chain #[allow(unused)] pub struct JtagDev diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index 75364a7..45f50f2 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -8,7 +8,9 @@ use color_eyre::eyre::{Result, eyre}; use log::{debug, warn}; use crate::serial::bmd_rsp::BmdRspInterface; -use crate::serial::remote::{BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR}; +use crate::serial::remote::{ + BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, +}; pub struct RemoteV0 { @@ -105,11 +107,11 @@ impl BmdRemoteProtocol for RemoteV0 } } - fn adiv5_init(&self) -> bool + fn adiv5_init(&self) -> Option> { warn!("Falling back to non-accelerated probe interface"); warn!("Please update your probe's firmware for a substantial speed increase"); - false + None } fn adiv6_init(&self) -> bool @@ -168,10 +170,10 @@ impl BmdRemoteProtocol for RemoteV0Plus self.0.swd_init() } - fn adiv5_init(&self) -> bool + fn adiv5_init(&self) -> Option> { warn!("Please update your probe's firmware for improved error handling"); - false + None } fn adiv6_init(&self) -> bool From abf254446e81a308d7651e23e61e082f34a51ba6 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 02:18:18 +0100 Subject: [PATCH 27/57] serial/remote/protocol_v0: Begun implementing handling for the ADIv5 acceleration protocol --- src/serial/remote/protocol_v0.rs | 59 ++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index 45f50f2..d1cf8cf 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -8,8 +8,9 @@ use color_eyre::eyre::{Result, eyre}; use log::{debug, warn}; use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::{ - BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, + Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, TargetAddr64, }; pub struct RemoteV0 @@ -31,6 +32,12 @@ pub struct RemoteV0SWD interface: Arc>, } +pub struct RemoteV0ADIv5 +{ + #[allow(unused)] + interface: Arc>, +} + const REMOTE_SWD_INIT: &str = "!SS#"; const REMOTE_JTAG_INIT: &str = "!JS#"; @@ -158,6 +165,14 @@ impl From>> for RemoteV0Plus } } +impl RemoteV0Plus +{ + pub(crate) fn clone_interface(&self) -> Arc> + { + self.0.clone_interface() + } +} + impl BmdRemoteProtocol for RemoteV0Plus { fn jtag_init(&self) -> Result> @@ -173,7 +188,7 @@ impl BmdRemoteProtocol for RemoteV0Plus fn adiv5_init(&self) -> Option> { warn!("Please update your probe's firmware for improved error handling"); - None + Some(Arc::new(RemoteV0ADIv5::from(self.clone_interface()))) } fn adiv6_init(&self) -> bool @@ -288,3 +303,43 @@ impl BmdSwdProtocol for RemoteV0SWD // } } + +impl From>> for RemoteV0ADIv5 +{ + fn from(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdAdiV5Protocol for RemoteV0ADIv5 +{ + fn raw_access(&self, _dp: AdiV5DebugPort, _rnw: u8, _addr: u16, _value: u32) -> u32 + { + 0 + } + + fn dp_read(&self, _dp: AdiV5DebugPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_read(&self, _ap: AdiV5AccessPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_write(&self, _ap: AdiV5AccessPort, _addr: u16, _value: u32) {} + + fn mem_read(&self, _ap: AdiV5AccessPort, _dest: &mut [u8], _src: TargetAddr64) + { + // + } + + fn mem_write(&self, _ap: AdiV5AccessPort, _dest: TargetAddr64, _src: &[u8], _align: Align) + { + // + } +} From a19c57b1f64d1d681799cdeb74cb9d76cc7c0d23 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 04:04:18 +0100 Subject: [PATCH 28/57] serial/remote: Added more documentation to the traits defined for the remote protocol --- src/serial/remote/mod.rs | 9 +++++++++ src/serial/remote/protocol_v0.rs | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 1ad3f1b..cc801e4 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -68,9 +68,18 @@ pub trait BmdRemoteProtocol /// Types implementing this trait provide raw SWD access to targets over the BMD remote protocol pub trait BmdSwdProtocol { + /// Executes a read of the SWD bus for `clock_cycles` clock cycles, for up to 32 cycles, + /// and returns the result as a 32-bit integer fn seq_in(&self, clock_cycles: usize) -> u32; + /// The same as seq_in but then does one additional cycle to read a parity bit, checks + /// the parity bit's value, and then only returns the result if the parity check passes - + /// returns None otherwise fn seq_in_parity(&self, clock_cycles: usize) -> Option; + /// Executes a write to the SWD bus for `clock_cycles` clock cycles, for up to 32 cycles, + /// putting out the value provided to the bus fn seq_out(&self, value: u32, clock_cycles: usize); + /// The same as seq_out but then computes the parity bit for the provided value, and + /// does one additional cycle to write that parity bit out to thebus fn seq_out_parity(&self, value: u32, clock_cycles: usize); } diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index d1cf8cf..47c5505 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -135,6 +135,8 @@ impl BmdRemoteProtocol for RemoteV0 false } + /// This is intentionally a no-op on this version of the protocol as the probe has no idea what to do + /// with the information this would provide. Protocol v1 introduces this machinary fn add_jtag_dev(&self, _dev_index: u32, _jtag_dev: &JtagDev) {} fn get_comms_frequency(&self) -> u32 From 3bb1da49c506b89e3bd094feb6cc0d4ac24af114 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 05:31:51 +0100 Subject: [PATCH 29/57] serial/remote/protocol_v1: Created a stub implementation of the v1 remote protocol object --- src/serial/remote/mod.rs | 3 + src/serial/remote/protocol_v1.rs | 137 +++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 src/serial/remote/protocol_v1.rs diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index cc801e4..0cce1dc 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -9,9 +9,11 @@ use color_eyre::eyre::Result; use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v0::{RemoteV0, RemoteV0Plus}; +use crate::serial::remote::protocol_v1::RemoteV1; pub mod adi; mod protocol_v0; +mod protocol_v1; /// This is the max possible size of a remote protocol packet which a hard limitation of the /// firmware on the probe - 1KiB is all the buffer that could be spared. @@ -191,6 +193,7 @@ impl ProtocolVersion match self { Self::V0 => Box::new(RemoteV0::from(interface)), Self::V0Plus => Box::new(RemoteV0Plus::from(interface)), + Self::V1 => Box::new(RemoteV1::from(interface)), _ => todo!(), } } diff --git a/src/serial/remote/protocol_v1.rs b/src/serial/remote/protocol_v1.rs new file mode 100644 index 0000000..574d566 --- /dev/null +++ b/src/serial/remote/protocol_v1.rs @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::sync::{Arc, Mutex}; + +use color_eyre::eyre::Result; +use log::warn; + +use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; +use crate::serial::remote::protocol_v0::RemoteV0; +use crate::serial::remote::{ + Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, TargetAddr64, +}; + +pub struct RemoteV1(RemoteV0); + +pub struct RemoteV1ADIv5 +{ + #[allow(unused)] + interface: Arc>, +} + +impl From>> for RemoteV1 +{ + fn from(interface: Arc>) -> Self + { + warn!( + "Probe firmware does not support the newer JTAG commands, ADIv6 acceleration or RISC-V JTAG acceleration, \ + please update it" + ); + Self::new(interface) + } +} + +impl RemoteV1 +{ + pub(crate) fn new(interface: Arc>) -> Self + { + Self(RemoteV0::new(interface)) + } + + pub(crate) fn clone_interface(&self) -> Arc> + { + self.0.clone_interface() + } +} + +impl BmdRemoteProtocol for RemoteV1 +{ + fn jtag_init(&self) -> Result> + { + self.0.jtag_init() + } + + fn swd_init(&self) -> Result> + { + self.0.swd_init() + } + + fn adiv5_init(&self) -> Option> + { + warn!("Please update your probe's firmware for improved error handling"); + Some(Arc::new(RemoteV1ADIv5::from(self.clone_interface()))) + } + + fn adiv6_init(&self) -> bool + { + self.0.adiv6_init() + } + + fn riscv_jtag_init(&self) -> bool + { + self.0.riscv_jtag_init() + } + + fn add_jtag_dev(&self, _dev_index: u32, _jtag_dev: &JtagDev) + { + // + } + + fn get_comms_frequency(&self) -> u32 + { + self.0.get_comms_frequency() + } + + fn set_comms_frequency(&self, freq: u32) -> bool + { + self.0.set_comms_frequency(freq) + } + + fn target_clk_output_enable(&self, enable: bool) + { + self.0.target_clk_output_enable(enable); + } +} + +impl From>> for RemoteV1ADIv5 +{ + fn from(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdAdiV5Protocol for RemoteV1ADIv5 +{ + fn raw_access(&self, _dp: AdiV5DebugPort, _rnw: u8, _addr: u16, _value: u32) -> u32 + { + 0 + } + + fn dp_read(&self, _dp: AdiV5DebugPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_read(&self, _ap: AdiV5AccessPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_write(&self, _ap: AdiV5AccessPort, _addr: u16, _value: u32) {} + + fn mem_read(&self, _ap: AdiV5AccessPort, _dest: &mut [u8], _src: TargetAddr64) + { + // + } + + fn mem_write(&self, _ap: AdiV5AccessPort, _dest: TargetAddr64, _src: &[u8], _align: Align) + { + // + } +} From 202960721d70b4cc437bc5bb82d2b15eac554b54 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 22 Jun 2025 12:42:52 +0100 Subject: [PATCH 30/57] serial/remote/protocol_v2: Created a stub implementation of the v2 remote protocol object --- src/serial/remote/mod.rs | 3 + src/serial/remote/protocol_v0.rs | 2 +- src/serial/remote/protocol_v1.rs | 7 +- src/serial/remote/protocol_v2.rs | 156 +++++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 src/serial/remote/protocol_v2.rs diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 0cce1dc..1126be8 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -10,10 +10,12 @@ use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v0::{RemoteV0, RemoteV0Plus}; use crate::serial::remote::protocol_v1::RemoteV1; +use crate::serial::remote::protocol_v2::RemoteV2; pub mod adi; mod protocol_v0; mod protocol_v1; +mod protocol_v2; /// This is the max possible size of a remote protocol packet which a hard limitation of the /// firmware on the probe - 1KiB is all the buffer that could be spared. @@ -194,6 +196,7 @@ impl ProtocolVersion Self::V0 => Box::new(RemoteV0::from(interface)), Self::V0Plus => Box::new(RemoteV0Plus::from(interface)), Self::V1 => Box::new(RemoteV1::from(interface)), + Self::V2 => Box::new(RemoteV2::from(interface)), _ => todo!(), } } diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index 47c5505..7923db1 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -62,7 +62,7 @@ impl RemoteV0 } } - fn interface(&self) -> MutexGuard<'_, BmdRspInterface> + pub(crate) fn interface(&self) -> MutexGuard<'_, BmdRspInterface> { self.interface.lock().unwrap() } diff --git a/src/serial/remote/protocol_v1.rs b/src/serial/remote/protocol_v1.rs index 574d566..9fa40ae 100644 --- a/src/serial/remote/protocol_v1.rs +++ b/src/serial/remote/protocol_v1.rs @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; use color_eyre::eyre::Result; use log::warn; @@ -41,6 +41,11 @@ impl RemoteV1 Self(RemoteV0::new(interface)) } + pub(crate) fn interface(&self) -> MutexGuard + { + self.0.interface() + } + pub(crate) fn clone_interface(&self) -> Arc> { self.0.clone_interface() diff --git a/src/serial/remote/protocol_v2.rs b/src/serial/remote/protocol_v2.rs new file mode 100644 index 0000000..cadfbb0 --- /dev/null +++ b/src/serial/remote/protocol_v2.rs @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::sync::{Arc, Mutex, MutexGuard}; + +use color_eyre::eyre::{Result, eyre}; +use log::{debug, warn}; + +use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::protocol_v0::RemoteV0JTAG; +use crate::serial::remote::protocol_v1::RemoteV1; +use crate::serial::remote::{ + BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, +}; + +pub struct RemoteV2(RemoteV1); + +pub struct RemoteV2JTAG(RemoteV0JTAG); + +const REMOTE_JTAG_INIT: &str = "!JS#"; + +impl From>> for RemoteV2 +{ + fn from(interface: Arc>) -> Self + { + warn!("Probe firmware does not support ADIv6 acceleration or RISC-V JTAG acceleration, please update it"); + Self::new(interface) + } +} + +impl RemoteV2 +{ + pub(crate) fn new(interface: Arc>) -> Self + { + Self(RemoteV1::new(interface)) + } + + pub(crate) fn interface(&self) -> MutexGuard + { + self.0.interface() + } + + pub(crate) fn clone_interface(&self) -> Arc> + { + self.0.clone_interface() + } +} + +impl BmdRemoteProtocol for RemoteV2 +{ + fn jtag_init(&self) -> Result> + { + // Try to have the probe initialise JTAG comms to any connected targets + debug!("Remote JTAG init"); + self.interface().buffer_write(REMOTE_JTAG_INIT)?; + let buffer = self.interface().buffer_read()?; + // If that failed for some reason, report it and abort + if buffer.is_empty() || buffer.as_bytes()[0] == REMOTE_RESP_ERR { + let message = if buffer.len() > 1 { + &buffer[1..] + } else { + "unknown" + }; + Err(eyre!("Remote JTAG init failed, error {}", message)) + } else { + // Otherwise, return the v0 JTAG protocol implementation + Ok(Box::new(RemoteV2JTAG::from(self.clone_interface()))) + } + } + + fn swd_init(&self) -> Result> + { + self.0.swd_init() + } + + fn adiv5_init(&self) -> Option> + { + self.0.adiv5_init() + } + + fn adiv6_init(&self) -> bool + { + self.0.adiv6_init() + } + + fn riscv_jtag_init(&self) -> bool + { + self.0.riscv_jtag_init() + } + + fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev) + { + self.0.add_jtag_dev(dev_index, jtag_dev); + } + + fn get_comms_frequency(&self) -> u32 + { + u32::MAX + } + + fn set_comms_frequency(&self, _freq: u32) -> bool + { + false + } + + fn target_clk_output_enable(&self, _enable: bool) + { + // + } +} + +impl From>> for RemoteV2JTAG +{ + fn from(interface: Arc>) -> Self + { + Self(RemoteV0JTAG::from(interface)) + } +} + +/// v2 JTAG enhances v0 JTAG by adding a new command to the set - tap_cycle. +/// This command allows the probe to execute a whole sequence of transitions such as +/// idle cycles without needing each to be an invocation of tap_next, which has significant +/// overhead penalty thanks to USB turnaround times. +impl BmdJtagProtocol for RemoteV2JTAG +{ + fn tap_reset(&self) + { + self.0.tap_reset(); + } + + fn tap_next(&self, tms: bool, tdi: bool) -> bool + { + self.0.tap_next(tms, tdi) + } + + fn tap_tms_seq(&self, tms_states: u32, clock_cycles: usize) + { + self.0.tap_tms_seq(tms_states, clock_cycles); + } + + fn tap_tdi_tdo_seq(&self, data_out: Option<&mut [u8]>, final_tms: bool, data_in: Option<&[u8]>, clock_cycles: usize) + { + self.0.tap_tdi_tdo_seq(data_out, final_tms, data_in, clock_cycles); + } + + fn tap_tdi_seq(&self, final_tms: bool, data_in: &[u8], clock_cycles: usize) + { + self.0.tap_tdi_seq(final_tms, data_in, clock_cycles); + } + + fn tap_cycle(&self, _tms: bool, _tdi: bool, _clock_cycles: usize) + { + // + } +} From f90bfe3ce5f0587b7b581f7d339af48319a29095 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 04:05:26 +0100 Subject: [PATCH 31/57] usb: Fixed some clippy lints that we missed before --- src/usb.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/usb.rs b/src/usb.rs index aace313..7d0776e 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -259,19 +259,19 @@ impl PartialEq for PortId #[cfg(any(target_os = "linux", target_os = "android"))] fn eq(&self, other: &Self) -> bool { - return self.bus_number == other.bus_number && self.path == other.path; + self.bus_number == other.bus_number && self.path == other.path } #[cfg(target_os = "windows")] fn eq(&self, other: &Self) -> bool { - return self.bus_number == other.bus_number && self.port_number == other.port_number; + self.bus_number == other.bus_number && self.port_number == other.port_number } #[cfg(target_os = "macos")] fn eq(&self, other: &Self) -> bool { - return self.bus_number == other.bus_number && self.location == other.location; + self.bus_number == other.bus_number && self.location == other.location } } From afe92da482995c6a1568d41b7ad195b85dd56686 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 04:13:07 +0100 Subject: [PATCH 32/57] misc: Enabled format-on-save assuming that `rustfmt` is installed via rustup, and the nightly version is available --- .vscode/settings.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5e10c8f..d6baa31 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,4 +5,12 @@ "rust-analyzer.imports.granularity.group": "preserve", "rust-analyzer.checkOnSave": true, "rust-analyzer.check.command": "clippy", + "rust-analyzer.rustfmt.overrideCommand": [ + "rustfmt", + "+nightly", + ], + "[rust]": + { + "editor.formatOnSave": true, + }, } From f0adba523a5dcb86335e0553caf6b6b320a0949d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 04:50:25 +0100 Subject: [PATCH 33/57] serial/remote/protocol_v3: Created a stub implementation of the v3 remote protocol object --- src/serial/remote/mod.rs | 3 + src/serial/remote/protocol_v3.rs | 136 +++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 src/serial/remote/protocol_v3.rs diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 1126be8..b87c276 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -11,11 +11,13 @@ use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v0::{RemoteV0, RemoteV0Plus}; use crate::serial::remote::protocol_v1::RemoteV1; use crate::serial::remote::protocol_v2::RemoteV2; +use crate::serial::remote::protocol_v3::RemoteV3; pub mod adi; mod protocol_v0; mod protocol_v1; mod protocol_v2; +mod protocol_v3; /// This is the max possible size of a remote protocol packet which a hard limitation of the /// firmware on the probe - 1KiB is all the buffer that could be spared. @@ -197,6 +199,7 @@ impl ProtocolVersion Self::V0Plus => Box::new(RemoteV0Plus::from(interface)), Self::V1 => Box::new(RemoteV1::from(interface)), Self::V2 => Box::new(RemoteV2::from(interface)), + Self::V3 => Box::new(RemoteV3::from(interface)), _ => todo!(), } } diff --git a/src/serial/remote/protocol_v3.rs b/src/serial/remote/protocol_v3.rs new file mode 100644 index 0000000..0c19bb0 --- /dev/null +++ b/src/serial/remote/protocol_v3.rs @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::sync::{Arc, Mutex}; + +use color_eyre::eyre::Result; +use log::warn; + +use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; +use crate::serial::remote::protocol_v2::RemoteV2; +use crate::serial::remote::{ + Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, TargetAddr64, +}; + +pub struct RemoteV3(RemoteV2); + +pub struct RemoteV3ADIv5 +{ + #[allow(unused)] + interface: Arc>, +} + +impl From>> for RemoteV3 +{ + fn from(interface: Arc>) -> Self + { + warn!("Probe firmware does not support ADIv6 acceleration or RISC-V JTAG acceleration, please update it"); + Self::new(interface) + } +} + +impl RemoteV3 +{ + pub(crate) fn new(interface: Arc>) -> Self + { + Self(RemoteV2::new(interface)) + } + + pub(crate) fn clone_interface(&self) -> Arc> + { + self.0.clone_interface() + } +} + +impl BmdRemoteProtocol for RemoteV3 +{ + fn jtag_init(&self) -> Result> + { + self.0.jtag_init() + } + + fn swd_init(&self) -> Result> + { + self.0.swd_init() + } + + fn adiv5_init(&self) -> Option> + { + Some(Arc::new(RemoteV3ADIv5::from(self.clone_interface()))) + } + + fn adiv6_init(&self) -> bool + { + self.0.adiv6_init() + } + + fn riscv_jtag_init(&self) -> bool + { + self.0.riscv_jtag_init() + } + + fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev) + { + self.0.add_jtag_dev(dev_index, jtag_dev); + } + + fn get_comms_frequency(&self) -> u32 + { + self.0.get_comms_frequency() + } + + fn set_comms_frequency(&self, freq: u32) -> bool + { + self.0.set_comms_frequency(freq) + } + + fn target_clk_output_enable(&self, enable: bool) + { + self.0.target_clk_output_enable(enable); + } +} + +impl From>> for RemoteV3ADIv5 +{ + fn from(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdAdiV5Protocol for RemoteV3ADIv5 +{ + fn raw_access(&self, _dp: AdiV5DebugPort, _rnw: u8, _addr: u16, _value: u32) -> u32 + { + 0 + } + + fn dp_read(&self, _dp: AdiV5DebugPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_read(&self, _ap: AdiV5AccessPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_write(&self, _ap: AdiV5AccessPort, _addr: u16, _value: u32) + { + // + } + + fn mem_read(&self, _ap: AdiV5AccessPort, _dest: &mut [u8], _src: TargetAddr64) + { + // + } + + fn mem_write(&self, _ap: AdiV5AccessPort, _dest: TargetAddr64, _src: &[u8], _align: Align) + { + // + } +} From 6e5055d0dcbb9cf61d879f092d6d454e640ec138 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 04:58:53 +0100 Subject: [PATCH 34/57] serial/remote/protocol_v4: Created a stub implementation of the v4 remote protocol object --- src/serial/remote/mod.rs | 3 ++ src/serial/remote/protocol_v4.rs | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/serial/remote/protocol_v4.rs diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index b87c276..743ff46 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -12,12 +12,14 @@ use crate::serial::remote::protocol_v0::{RemoteV0, RemoteV0Plus}; use crate::serial::remote::protocol_v1::RemoteV1; use crate::serial::remote::protocol_v2::RemoteV2; use crate::serial::remote::protocol_v3::RemoteV3; +use crate::serial::remote::protocol_v4::RemoteV4; pub mod adi; mod protocol_v0; mod protocol_v1; mod protocol_v2; mod protocol_v3; +mod protocol_v4; /// This is the max possible size of a remote protocol packet which a hard limitation of the /// firmware on the probe - 1KiB is all the buffer that could be spared. @@ -200,6 +202,7 @@ impl ProtocolVersion Self::V1 => Box::new(RemoteV1::from(interface)), Self::V2 => Box::new(RemoteV2::from(interface)), Self::V3 => Box::new(RemoteV3::from(interface)), + Self::V4 => Box::new(RemoteV4::from(interface)), _ => todo!(), } } diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs new file mode 100644 index 0000000..02a06a7 --- /dev/null +++ b/src/serial/remote/protocol_v4.rs @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +use std::sync::{Arc, Mutex}; + +use color_eyre::eyre::Result; + +use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::protocol_v3::RemoteV3; +use crate::serial::remote::{BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev}; + +pub struct RemoteV4(RemoteV3); + +impl From>> for RemoteV4 +{ + fn from(interface: Arc>) -> Self + { + Self::new(interface) + } +} + +impl RemoteV4 +{ + pub(crate) fn new(interface: Arc>) -> Self + { + Self(RemoteV3::new(interface)) + } +} + +impl BmdRemoteProtocol for RemoteV4 +{ + fn jtag_init(&self) -> Result> + { + self.0.jtag_init() + } + + fn swd_init(&self) -> Result> + { + self.0.swd_init() + } + + fn adiv5_init(&self) -> Option> + { + None + } + + fn adiv6_init(&self) -> bool + { + false + } + + fn riscv_jtag_init(&self) -> bool + { + false + } + + fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev) + { + self.0.add_jtag_dev(dev_index, jtag_dev); + } + + fn get_comms_frequency(&self) -> u32 + { + self.0.get_comms_frequency() + } + + fn set_comms_frequency(&self, freq: u32) -> bool + { + self.0.set_comms_frequency(freq) + } + + fn target_clk_output_enable(&self, enable: bool) + { + self.0.target_clk_output_enable(enable); + } +} From 77c3ff00e0bf7412dbb03758edb2fb1fea0ce021 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 06:12:06 +0100 Subject: [PATCH 35/57] serial/remote/protocol_v4: Switched the remote protocol structure from a new-style structure to traditional style so we can add more members sensibly --- src/serial/remote/protocol_v4.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index 02a06a7..a94ebcb 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -10,7 +10,13 @@ use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::protocol_v3::RemoteV3; use crate::serial::remote::{BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev}; -pub struct RemoteV4(RemoteV3); +pub struct RemoteV4 +{ + /// We're a superset of the v3 protocol, this is an instance of that version of the protocol so we + /// can access the unchanged machinary from it such as the SWD and JTAG low-level protocol components. + /// This version of the protocol defines new high-level protocol components and support commands only. + inner_protocol: RemoteV3, +} impl From>> for RemoteV4 { @@ -24,7 +30,9 @@ impl RemoteV4 { pub(crate) fn new(interface: Arc>) -> Self { - Self(RemoteV3::new(interface)) + Self { + inner_protocol: RemoteV3::new(interface), + } } } @@ -32,12 +40,12 @@ impl BmdRemoteProtocol for RemoteV4 { fn jtag_init(&self) -> Result> { - self.0.jtag_init() + self.inner_protocol.jtag_init() } fn swd_init(&self) -> Result> { - self.0.swd_init() + self.inner_protocol.swd_init() } fn adiv5_init(&self) -> Option> @@ -57,21 +65,21 @@ impl BmdRemoteProtocol for RemoteV4 fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev) { - self.0.add_jtag_dev(dev_index, jtag_dev); + self.inner_protocol.add_jtag_dev(dev_index, jtag_dev); } fn get_comms_frequency(&self) -> u32 { - self.0.get_comms_frequency() + self.inner_protocol.get_comms_frequency() } fn set_comms_frequency(&self, freq: u32) -> bool { - self.0.set_comms_frequency(freq) + self.inner_protocol.set_comms_frequency(freq) } fn target_clk_output_enable(&self, enable: bool) { - self.0.target_clk_output_enable(enable); + self.inner_protocol.target_clk_output_enable(enable); } } From d00fe5c41525616ac5fbf653de389c52851b604f Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 06:39:47 +0100 Subject: [PATCH 36/57] serial/bmd_rsp: Fixed a bug in the implementation of BmdRspInterface.remote() which would prevent getting access to the comms interface from in the machinary to make an instance of a suitable remote protocol impl --- src/serial/bmd_rsp.rs | 9 ++++++--- src/serial/remote/mod.rs | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 200eec7..d8823b0 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -102,11 +102,14 @@ impl BmdRspInterface } /// Extract the remote protocol object to use to talk with this probe - pub fn remote(self) -> Box + pub fn remote(self) -> Result> { let interface = Arc::new(Mutex::new(self)); - let iface = interface.lock().unwrap(); - iface.protocol_version.protocol_impl(interface.clone()) + let protocol = interface + .lock() + .map_err(|_| eyre!("Failed to aquire lock on interface to access remote protocol"))? + .protocol_version; + Ok(protocol.protocol_impl(interface.clone())) } pub(crate) fn buffer_write(&mut self, message: &str) -> Result<()> diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 743ff46..45259d4 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -161,6 +161,7 @@ pub struct JtagDev ir_postscan: u8, } +#[derive(Copy, Clone)] pub(crate) enum ProtocolVersion { Unknown, From 72a4d02424464b0d29038a55682aa911e3cb1961 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 06:40:53 +0100 Subject: [PATCH 37/57] bmputil-cli: Aquire the remote protocol to talk to a probe with for `list_targets()` --- src/bin/bmputil-cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/bmputil-cli.rs b/src/bin/bmputil-cli.rs index f0323b1..d1b369f 100644 --- a/src/bin/bmputil-cli.rs +++ b/src/bin/bmputil-cli.rs @@ -378,7 +378,7 @@ fn display_releases(paths: &ProjectDirs) -> Result<()> fn list_targets(probe: BmpDevice) -> Result<()> { - let bmd_interface = probe.bmd_serial_interface()?; + let remote = probe.bmd_serial_interface()?.remote()?; Ok(()) } From e127dca9aa7d32b0ac1bda14e746c5be7027e64d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 06:42:09 +0100 Subject: [PATCH 38/57] serial/remote/protocol_v4: Implemented logic to ask a probe what accelerations it supports --- src/serial/bmd_rsp.rs | 2 +- src/serial/remote/mod.rs | 14 ++++++------ src/serial/remote/protocol_v4.rs | 37 ++++++++++++++++++++++++++------ 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index d8823b0..d74463e 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -109,7 +109,7 @@ impl BmdRspInterface .lock() .map_err(|_| eyre!("Failed to aquire lock on interface to access remote protocol"))? .protocol_version; - Ok(protocol.protocol_impl(interface.clone())) + protocol.protocol_impl(interface.clone()) } pub(crate) fn buffer_write(&mut self, message: &str) -> Result<()> diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 45259d4..0ac1d02 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -195,15 +195,15 @@ pub fn decode_response(response: &str, digits: usize) -> u64 impl ProtocolVersion { /// Extract an instance of the BMD remote protocol communication object for this version of the protocol - pub fn protocol_impl(&self, interface: Arc>) -> Box + pub fn protocol_impl(&self, interface: Arc>) -> Result> { match self { - Self::V0 => Box::new(RemoteV0::from(interface)), - Self::V0Plus => Box::new(RemoteV0Plus::from(interface)), - Self::V1 => Box::new(RemoteV1::from(interface)), - Self::V2 => Box::new(RemoteV2::from(interface)), - Self::V3 => Box::new(RemoteV3::from(interface)), - Self::V4 => Box::new(RemoteV4::from(interface)), + Self::V0 => Ok(Box::new(RemoteV0::from(interface))), + Self::V0Plus => Ok(Box::new(RemoteV0Plus::from(interface))), + Self::V1 => Ok(Box::new(RemoteV1::from(interface))), + Self::V2 => Ok(Box::new(RemoteV2::from(interface))), + Self::V3 => Ok(Box::new(RemoteV3::from(interface))), + Self::V4 => Ok(Box::new(RemoteV4::try_from(interface)?)), _ => todo!(), } } diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index a94ebcb..b004797 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -4,11 +4,13 @@ use std::sync::{Arc, Mutex}; -use color_eyre::eyre::Result; +use color_eyre::eyre::{Report, Result, eyre}; use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::protocol_v3::RemoteV3; -use crate::serial::remote::{BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev}; +use crate::serial::remote::{ + BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_OK, +}; pub struct RemoteV4 { @@ -18,9 +20,14 @@ pub struct RemoteV4 inner_protocol: RemoteV3, } -impl From>> for RemoteV4 +/// This command asks the probe what high-level protocol accelerations it supports +const REMOTE_HL_ACCEL: &str = "!HA#"; + +impl TryFrom>> for RemoteV4 { - fn from(interface: Arc>) -> Self + type Error = Report; + + fn try_from(interface: Arc>) -> Result { Self::new(interface) } @@ -28,11 +35,27 @@ impl From>> for RemoteV4 impl RemoteV4 { - pub(crate) fn new(interface: Arc>) -> Self + pub(crate) fn new(interface: Arc>) -> Result { - Self { - inner_protocol: RemoteV3::new(interface), + // Before we can create an instance of the remote protocol structure, we first need to ask + // the probe about supported accelerations as this determines the results of asking for the + // high-level accelerations below. Start by firing off the request to the probe + let mut iface = interface.lock().unwrap(); + iface.buffer_write(REMOTE_HL_ACCEL)?; + // Read back the result and relinquish our comms lock so structure creation can work + let buffer = iface.buffer_read()?; + drop(iface); + // Check for communication failures + if buffer.is_empty() || buffer.as_bytes()[0] != REMOTE_RESP_OK { + return Err(eyre!( + "Error talking with probe, expected OK response to supported accelerations query, got {:?}", + buffer + )); } + + Ok(Self { + inner_protocol: RemoteV3::new(interface), + }) } } From 0c6e2888b00977a1e71e799a3b0c4023ff20f45a Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 07:10:25 +0100 Subject: [PATCH 39/57] serial/remote/protocol_v4: Defined a bitmask enum for the supported accelerations a probe can report --- Cargo.lock | 11 +++++++++++ Cargo.toml | 1 + src/serial/remote/protocol_v4.rs | 22 +++++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 9c1ec40..4bf3822 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,16 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "bitmask-enum" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6cbbb8f56245b5a479b30a62cdc86d26e2f35c2b9f594bc4671654b03851380" +dependencies = [ + "quote", + "syn 2.0.104", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -214,6 +224,7 @@ version = "1.0.0-rc.1" dependencies = [ "anstyle", "anyhow", + "bitmask-enum", "bstr", "clap", "clap_complete", diff --git a/Cargo.toml b/Cargo.toml index cf25d52..92d7720 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ color-eyre = "0.6.3" tui-markdown = "0.3.3" ratatui = { version = "0.29.0", features = ["unstable-rendered-line-info"] } clap_complete = "4.5.52" +bitmask-enum = "2.2.5" [target.'cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))'.dependencies] termios = "0.3.3" diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index b004797..ba1e815 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -4,12 +4,14 @@ use std::sync::{Arc, Mutex}; +use bitmask_enum::bitmask; use color_eyre::eyre::{Report, Result, eyre}; +use log::debug; use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::protocol_v3::RemoteV3; use crate::serial::remote::{ - BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_OK, + BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_OK, decode_response, }; pub struct RemoteV4 @@ -18,6 +20,19 @@ pub struct RemoteV4 /// can access the unchanged machinary from it such as the SWD and JTAG low-level protocol components. /// This version of the protocol defines new high-level protocol components and support commands only. inner_protocol: RemoteV3, + /// Bitmask of the accelerations supported by this probe + #[allow(unused)] + accelerations: Acceleration, +} + +#[bitmask(u64)] +#[bitmask_config(vec_debug)] +enum Acceleration +{ + ADIv5, + CortexAR, + RiscV, + ADIv6, } /// This command asks the probe what high-level protocol accelerations it supports @@ -52,9 +67,14 @@ impl RemoteV4 buffer )); } + // Decode the response and translate the supported accelerations bitmask to our internal + // enumeration of accelerations + let accelerations = Acceleration::from(decode_response(&buffer[1..], 8)); + debug!("Probe supports the following accelerations: {:?}", accelerations); Ok(Self { inner_protocol: RemoteV3::new(interface), + accelerations, }) } } From 0e62ef21041e4e2569241f0edc243fde163d976f Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 07:14:14 +0100 Subject: [PATCH 40/57] serial/remote/protocol_v4: Implemented a stub for handling the ADIv5 acceleration protocol --- src/serial/remote/protocol_v4.rs | 64 +++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index ba1e815..62d76f0 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -9,9 +9,11 @@ use color_eyre::eyre::{Report, Result, eyre}; use log::debug; use crate::serial::bmd_rsp::BmdRspInterface; +use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v3::RemoteV3; use crate::serial::remote::{ - BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_OK, decode_response, + Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_OK, TargetAddr64, + decode_response, }; pub struct RemoteV4 @@ -25,6 +27,12 @@ pub struct RemoteV4 accelerations: Acceleration, } +pub struct RemoteV4ADIv5 +{ + #[allow(unused)] + interface: Arc>, +} + #[bitmask(u64)] #[bitmask_config(vec_debug)] enum Acceleration @@ -77,6 +85,11 @@ impl RemoteV4 accelerations, }) } + + pub(crate) fn clone_interface(&self) -> Arc> + { + self.inner_protocol.clone_interface() + } } impl BmdRemoteProtocol for RemoteV4 @@ -93,7 +106,11 @@ impl BmdRemoteProtocol for RemoteV4 fn adiv5_init(&self) -> Option> { - None + if self.accelerations.contains(Acceleration::ADIv5) { + Some(Arc::new(RemoteV4ADIv5::from(self.clone_interface()))) + } else { + None + } } fn adiv6_init(&self) -> bool @@ -126,3 +143,46 @@ impl BmdRemoteProtocol for RemoteV4 self.inner_protocol.target_clk_output_enable(enable); } } + +impl From>> for RemoteV4ADIv5 +{ + fn from(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdAdiV5Protocol for RemoteV4ADIv5 +{ + fn raw_access(&self, _dp: AdiV5DebugPort, _rnw: u8, _addr: u16, _value: u32) -> u32 + { + 0 + } + + fn dp_read(&self, _dp: AdiV5DebugPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_read(&self, _ap: AdiV5AccessPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_write(&self, _ap: AdiV5AccessPort, _addr: u16, _value: u32) + { + // + } + + fn mem_read(&self, _ap: AdiV5AccessPort, _dest: &mut [u8], _src: TargetAddr64) + { + // + } + + fn mem_write(&self, _ap: AdiV5AccessPort, _dest: TargetAddr64, _src: &[u8], _align: Align) + { + // + } +} From be9dec0c82f8700e69a56c0287207bca4ce1590e Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 07:42:01 +0100 Subject: [PATCH 41/57] serial/remote/protocol_v4: Implemented Display for Acceleration so it pretty prints nicely --- src/serial/remote/protocol_v4.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index 62d76f0..17ae7a0 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -2,6 +2,7 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant +use std::fmt::Display; use std::sync::{Arc, Mutex}; use bitmask_enum::bitmask; @@ -78,7 +79,7 @@ impl RemoteV4 // Decode the response and translate the supported accelerations bitmask to our internal // enumeration of accelerations let accelerations = Acceleration::from(decode_response(&buffer[1..], 8)); - debug!("Probe supports the following accelerations: {:?}", accelerations); + debug!("Probe supports the following accelerations: {}", accelerations); Ok(Self { inner_protocol: RemoteV3::new(interface), @@ -186,3 +187,24 @@ impl BmdAdiV5Protocol for RemoteV4ADIv5 // } } + +impl Display for Acceleration +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + let mut accelerations = Vec::with_capacity(4); + if self.contains(Self::ADIv5) { + accelerations.push("ADIv5"); + } + if self.contains(Self::ADIv6) { + accelerations.push("ADIv6"); + } + if self.contains(Self::RiscV) { + accelerations.push("RISC-V"); + } + if self.contains(Self::CortexAR) { + accelerations.push("Cortex-A/R"); + } + write!(fmt, "{}", accelerations.join(", ")) + } +} From 1310d3184616b9a2ca59a7fca8f4b48c1b83d039 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 09:43:34 +0100 Subject: [PATCH 42/57] serial/remote/adi: Defined the ADIv6 AP structure --- src/serial/remote/adi.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/serial/remote/adi.rs b/src/serial/remote/adi.rs index beca060..8ece26f 100644 --- a/src/serial/remote/adi.rs +++ b/src/serial/remote/adi.rs @@ -65,3 +65,12 @@ pub struct AdiV5AccessPort /// AP partno partno: u16, } + +/// An ADIv6 access port associated with an ADIv6 debug port on a device +/// NB: Uses the ADIv5 DP structure to represent the DP, and based on the ADIv5 AP structure +#[allow(unused)] +pub struct AdiV6AccessPort +{ + base: AdiV5AccessPort, + address: TargetAddr64, +} From d2f1e4c72fcc7539142e600c5842a693cd45c5e9 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 09:46:18 +0100 Subject: [PATCH 43/57] serial/remote: Corrected the return type for BmdRemoteProtocol::adiv6_init() now we have the necessary machinary in place --- src/serial/remote/mod.rs | 2 +- src/serial/remote/protocol_v0.rs | 6 +++--- src/serial/remote/protocol_v1.rs | 2 +- src/serial/remote/protocol_v2.rs | 2 +- src/serial/remote/protocol_v3.rs | 2 +- src/serial/remote/protocol_v4.rs | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 0ac1d02..8b277b2 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -63,7 +63,7 @@ pub trait BmdRemoteProtocol fn jtag_init(&self) -> Result>; // Higher level protocol initialisation functions fn adiv5_init(&self) -> Option>; - fn adiv6_init(&self) -> bool; + fn adiv6_init(&self) -> Option>; fn riscv_jtag_init(&self) -> bool; // Probe operation control functions diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index 7923db1..16f0892 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -121,11 +121,11 @@ impl BmdRemoteProtocol for RemoteV0 None } - fn adiv6_init(&self) -> bool + fn adiv6_init(&self) -> Option> { warn!("Falling back to non-accelerated probe interface"); warn!("Please update your probe's firmware for a substantial speed increase"); - false + None } fn riscv_jtag_init(&self) -> bool @@ -193,7 +193,7 @@ impl BmdRemoteProtocol for RemoteV0Plus Some(Arc::new(RemoteV0ADIv5::from(self.clone_interface()))) } - fn adiv6_init(&self) -> bool + fn adiv6_init(&self) -> Option> { self.0.adiv6_init() } diff --git a/src/serial/remote/protocol_v1.rs b/src/serial/remote/protocol_v1.rs index 9fa40ae..3afab72 100644 --- a/src/serial/remote/protocol_v1.rs +++ b/src/serial/remote/protocol_v1.rs @@ -70,7 +70,7 @@ impl BmdRemoteProtocol for RemoteV1 Some(Arc::new(RemoteV1ADIv5::from(self.clone_interface()))) } - fn adiv6_init(&self) -> bool + fn adiv6_init(&self) -> Option> { self.0.adiv6_init() } diff --git a/src/serial/remote/protocol_v2.rs b/src/serial/remote/protocol_v2.rs index cadfbb0..4f4c24f 100644 --- a/src/serial/remote/protocol_v2.rs +++ b/src/serial/remote/protocol_v2.rs @@ -79,7 +79,7 @@ impl BmdRemoteProtocol for RemoteV2 self.0.adiv5_init() } - fn adiv6_init(&self) -> bool + fn adiv6_init(&self) -> Option> { self.0.adiv6_init() } diff --git a/src/serial/remote/protocol_v3.rs b/src/serial/remote/protocol_v3.rs index 0c19bb0..908af3a 100644 --- a/src/serial/remote/protocol_v3.rs +++ b/src/serial/remote/protocol_v3.rs @@ -61,7 +61,7 @@ impl BmdRemoteProtocol for RemoteV3 Some(Arc::new(RemoteV3ADIv5::from(self.clone_interface()))) } - fn adiv6_init(&self) -> bool + fn adiv6_init(&self) -> Option> { self.0.adiv6_init() } diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index 17ae7a0..f637a63 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -114,9 +114,9 @@ impl BmdRemoteProtocol for RemoteV4 } } - fn adiv6_init(&self) -> bool + fn adiv6_init(&self) -> Option> { - false + None } fn riscv_jtag_init(&self) -> bool From 1b78e81756894e0b9468dc65a0f9431c7d3bdf2b Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 09:47:49 +0100 Subject: [PATCH 44/57] serial/remote/protocol_v4: Implemented a stub for handling the ADIv6 acceleration protocol --- src/serial/remote/protocol_v4.rs | 55 +++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index f637a63..30d0fb0 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -34,6 +34,12 @@ pub struct RemoteV4ADIv5 interface: Arc>, } +pub struct RemoteV4ADIv6 +{ + #[allow(unused)] + interface: Arc>, +} + #[bitmask(u64)] #[bitmask_config(vec_debug)] enum Acceleration @@ -116,7 +122,11 @@ impl BmdRemoteProtocol for RemoteV4 fn adiv6_init(&self) -> Option> { - None + if self.accelerations.contains(Acceleration::ADIv6) { + Some(Arc::new(RemoteV4ADIv6::from(self.clone_interface()))) + } else { + None + } } fn riscv_jtag_init(&self) -> bool @@ -188,6 +198,49 @@ impl BmdAdiV5Protocol for RemoteV4ADIv5 } } +impl From>> for RemoteV4ADIv6 +{ + fn from(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdAdiV5Protocol for RemoteV4ADIv6 +{ + fn raw_access(&self, _dp: AdiV5DebugPort, _rnw: u8, _addr: u16, _value: u32) -> u32 + { + 0 + } + + fn dp_read(&self, _dp: AdiV5DebugPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_read(&self, _ap: AdiV5AccessPort, _addr: u16) -> u32 + { + 0 + } + + fn ap_write(&self, _ap: AdiV5AccessPort, _addr: u16, _value: u32) + { + // + } + + fn mem_read(&self, _ap: AdiV5AccessPort, _dest: &mut [u8], _src: TargetAddr64) + { + // + } + + fn mem_write(&self, _ap: AdiV5AccessPort, _dest: TargetAddr64, _src: &[u8], _align: Align) + { + // + } +} + impl Display for Acceleration { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result From 2bf46e705c6718690494f2b28eaefdc30087cf39 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 10:01:33 +0100 Subject: [PATCH 45/57] serial/remote/riscv_debug: Defined structures and a trait for holding information about the DMI attached to a RISC-V Debug DTM and how to access it --- src/serial/remote/mod.rs | 10 +++++++++- src/serial/remote/riscv_debug.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/serial/remote/riscv_debug.rs diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 8b277b2..2565388 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -13,6 +13,7 @@ use crate::serial::remote::protocol_v1::RemoteV1; use crate::serial::remote::protocol_v2::RemoteV2; use crate::serial::remote::protocol_v3::RemoteV3; use crate::serial::remote::protocol_v4::RemoteV4; +use crate::serial::remote::riscv_debug::RiscvDmi; pub mod adi; mod protocol_v0; @@ -20,6 +21,7 @@ mod protocol_v1; mod protocol_v2; mod protocol_v3; mod protocol_v4; +pub mod riscv_debug; /// This is the max possible size of a remote protocol packet which a hard limitation of the /// firmware on the probe - 1KiB is all the buffer that could be spared. @@ -44,7 +46,7 @@ pub const REMOTE_RESP_NOTSUP: u8 = b'N'; pub type TargetAddr32 = u32; pub type TargetAddr64 = u64; -/// Allignments available for use by memory accesses +/// Alignments available for use by memory accesses #[repr(u8)] pub enum Align { @@ -146,6 +148,12 @@ pub trait BmdAdiV5Protocol fn mem_write(&self, ap: AdiV5AccessPort, dest: TargetAddr64, src: &[u8], align: Align); } +pub trait BmdRiscvProtocol +{ + fn dmi_read(&self, dmi: RiscvDmi, address: u32) -> Option; + fn dmi_write(&self, dmi: RiscvDmi, address: u32, value: u32) -> bool; +} + /// Structure representing a device on the JTAG scan chain #[allow(unused)] pub struct JtagDev diff --git a/src/serial/remote/riscv_debug.rs b/src/serial/remote/riscv_debug.rs new file mode 100644 index 0000000..1841c93 --- /dev/null +++ b/src/serial/remote/riscv_debug.rs @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: 2025 1BitSquared +// SPDX-FileContributor: Written by Rachel Mant + +/// A version-agnostic Debug Module Interface on a RISC-V device +#[allow(unused)] +pub struct RiscvDmi +{ + /// DMI designer code + designer_code: u16, + /// Versioon of the spec this DMI implements + version: RiscvDebugVersion, + + /// The index of this DMI on the JTAG chain if JTAG + dev_index: u8, + /// The number of bus idle cycles this DMI needs to complete transactions + idle_cycles: u8, + /// The address width of the DMI bus this DMI connects us to + address_width: u8, + /// Whether a fault has occured on the bus, and which one + fault: u8, +} + +/// RISC-V Debug spec versions that we know about +pub enum RiscvDebugVersion +{ + Unknown, + Unimplemented, + V0_11, + V0_13, + V1_0, +} From 7b9f26223833f35df406309df816783c581df8d6 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 10:03:40 +0100 Subject: [PATCH 46/57] serial/remote: Corrected the return type for BmdRemoteProtocol::riscv_jtag_init() now we have the necessary machinary in place --- src/serial/remote/mod.rs | 2 +- src/serial/remote/protocol_v0.rs | 9 +++++---- src/serial/remote/protocol_v1.rs | 5 +++-- src/serial/remote/protocol_v2.rs | 4 ++-- src/serial/remote/protocol_v3.rs | 5 +++-- src/serial/remote/protocol_v4.rs | 8 ++++---- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 2565388..77cbcf6 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -66,7 +66,7 @@ pub trait BmdRemoteProtocol // Higher level protocol initialisation functions fn adiv5_init(&self) -> Option>; fn adiv6_init(&self) -> Option>; - fn riscv_jtag_init(&self) -> bool; + fn riscv_jtag_init(&self) -> Option>; // Probe operation control functions fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev); diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index 16f0892..fc61f1b 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -10,7 +10,8 @@ use log::{debug, warn}; use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::{ - Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, TargetAddr64, + Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, + REMOTE_RESP_ERR, TargetAddr64, }; pub struct RemoteV0 @@ -128,11 +129,11 @@ impl BmdRemoteProtocol for RemoteV0 None } - fn riscv_jtag_init(&self) -> bool + fn riscv_jtag_init(&self) -> Option> { warn!("Falling back to non-accelerated probe interface"); warn!("Please update your probe's firmware for a substantial speed increase"); - false + None } /// This is intentionally a no-op on this version of the protocol as the probe has no idea what to do @@ -198,7 +199,7 @@ impl BmdRemoteProtocol for RemoteV0Plus self.0.adiv6_init() } - fn riscv_jtag_init(&self) -> bool + fn riscv_jtag_init(&self) -> Option> { self.0.riscv_jtag_init() } diff --git a/src/serial/remote/protocol_v1.rs b/src/serial/remote/protocol_v1.rs index 3afab72..7529ec6 100644 --- a/src/serial/remote/protocol_v1.rs +++ b/src/serial/remote/protocol_v1.rs @@ -11,7 +11,8 @@ use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v0::RemoteV0; use crate::serial::remote::{ - Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, TargetAddr64, + Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, + TargetAddr64, }; pub struct RemoteV1(RemoteV0); @@ -75,7 +76,7 @@ impl BmdRemoteProtocol for RemoteV1 self.0.adiv6_init() } - fn riscv_jtag_init(&self) -> bool + fn riscv_jtag_init(&self) -> Option> { self.0.riscv_jtag_init() } diff --git a/src/serial/remote/protocol_v2.rs b/src/serial/remote/protocol_v2.rs index 4f4c24f..1a7a7a3 100644 --- a/src/serial/remote/protocol_v2.rs +++ b/src/serial/remote/protocol_v2.rs @@ -11,7 +11,7 @@ use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::protocol_v0::RemoteV0JTAG; use crate::serial::remote::protocol_v1::RemoteV1; use crate::serial::remote::{ - BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, + BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, }; pub struct RemoteV2(RemoteV1); @@ -84,7 +84,7 @@ impl BmdRemoteProtocol for RemoteV2 self.0.adiv6_init() } - fn riscv_jtag_init(&self) -> bool + fn riscv_jtag_init(&self) -> Option> { self.0.riscv_jtag_init() } diff --git a/src/serial/remote/protocol_v3.rs b/src/serial/remote/protocol_v3.rs index 908af3a..fc0694a 100644 --- a/src/serial/remote/protocol_v3.rs +++ b/src/serial/remote/protocol_v3.rs @@ -11,7 +11,8 @@ use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v2::RemoteV2; use crate::serial::remote::{ - Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, TargetAddr64, + Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, + TargetAddr64, }; pub struct RemoteV3(RemoteV2); @@ -66,7 +67,7 @@ impl BmdRemoteProtocol for RemoteV3 self.0.adiv6_init() } - fn riscv_jtag_init(&self) -> bool + fn riscv_jtag_init(&self) -> Option> { self.0.riscv_jtag_init() } diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index 30d0fb0..b69866a 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -13,8 +13,8 @@ use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v3::RemoteV3; use crate::serial::remote::{ - Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_OK, TargetAddr64, - decode_response, + Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, + REMOTE_RESP_OK, TargetAddr64, decode_response, }; pub struct RemoteV4 @@ -129,9 +129,9 @@ impl BmdRemoteProtocol for RemoteV4 } } - fn riscv_jtag_init(&self) -> bool + fn riscv_jtag_init(&self) -> Option> { - false + None } fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev) From 9c556e029a1df6bc4e1f6710e258d5c22c013626 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 23 Jun 2025 10:07:45 +0100 Subject: [PATCH 47/57] serial/remote/protocol_v4: Implemented a stub for handling the RISC-V Debug JTAG acceleration protocol --- src/serial/remote/protocol_v4.rs | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index b69866a..11b5431 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -12,6 +12,7 @@ use log::debug; use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v3::RemoteV3; +use crate::serial::remote::riscv_debug::RiscvDmi; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_OK, TargetAddr64, decode_response, @@ -40,6 +41,12 @@ pub struct RemoteV4ADIv6 interface: Arc>, } +pub struct RemoteV4RiscvJtag +{ + #[allow(unused)] + interface: Arc>, +} + #[bitmask(u64)] #[bitmask_config(vec_debug)] enum Acceleration @@ -131,7 +138,11 @@ impl BmdRemoteProtocol for RemoteV4 fn riscv_jtag_init(&self) -> Option> { - None + if self.accelerations.contains(Acceleration::RiscV) { + Some(Arc::new(RemoteV4RiscvJtag::from(self.clone_interface()))) + } else { + None + } } fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev) @@ -241,6 +252,29 @@ impl BmdAdiV5Protocol for RemoteV4ADIv6 } } +impl From>> for RemoteV4RiscvJtag +{ + fn from(interface: Arc>) -> Self + { + Self { + interface, + } + } +} + +impl BmdRiscvProtocol for RemoteV4RiscvJtag +{ + fn dmi_read(&self, _dmi: RiscvDmi, _address: u32) -> Option + { + None + } + + fn dmi_write(&self, _dmi: RiscvDmi, _address: u32, _value: u32) -> bool + { + false + } +} + impl Display for Acceleration { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result From bb650bb53367397a80b2be7fddf3620ef6644976 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 24 Jun 2025 12:34:13 +0100 Subject: [PATCH 48/57] serial/remote: Defined a set of bitmask types to represent the possible supported target architectures and families a probe can report --- src/serial/remote/mod.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 77cbcf6..5618774 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -4,6 +4,7 @@ use std::sync::{Arc, Mutex}; +use bitmask_enum::bitmask; use color_eyre::eyre::Result; use crate::serial::bmd_rsp::BmdRspInterface; @@ -56,6 +57,40 @@ pub enum Align As64Bit, } +#[bitmask(u64)] +pub enum TargetArchitecture +{ + CortexM, + CortexAR, + RiscV32, + RiscV64, +} + +#[bitmask(u64)] +pub enum TargetFamily +{ + AT32, + Apollo3, + CH32, + CH579, + EFM, + GD32, + HC32, + LPC, + MM32, + NRF, + NXPKinetis, + Puya, + RenesasRZ, + RenesasRA, + RP, + SAM, + STM, + TI, + Xilinx, + NXPiMXRT, +} + /// Types implementing this trait implement the common portion of the BMD remote protocol /// (this includes things like comms initialisation, and clock frequency control) pub trait BmdRemoteProtocol From 46c62ed0b183dcfcb155af8a1de02fdaaadc8c30 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 24 Jun 2025 13:39:42 +0100 Subject: [PATCH 49/57] serial/remote: Defined and implemented a trait function for extracting the supported target architectures from a probe in BmdRemoteProtocol --- src/serial/remote/mod.rs | 1 + src/serial/remote/protocol_v0.rs | 12 +++++++++- src/serial/remote/protocol_v1.rs | 7 +++++- src/serial/remote/protocol_v2.rs | 6 +++++ src/serial/remote/protocol_v3.rs | 14 +++++++++-- src/serial/remote/protocol_v4.rs | 40 +++++++++++++++++++++++++++++--- 6 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 5618774..2878e19 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -108,6 +108,7 @@ pub trait BmdRemoteProtocol fn get_comms_frequency(&self) -> u32; fn set_comms_frequency(&self, freq: u32) -> bool; fn target_clk_output_enable(&self, enable: bool); + fn supported_architectures(&self) -> Result>; } /// Types implementing this trait provide raw SWD access to targets over the BMD remote protocol diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index fc61f1b..a453e34 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -11,7 +11,7 @@ use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, - REMOTE_RESP_ERR, TargetAddr64, + REMOTE_RESP_ERR, TargetAddr64, TargetArchitecture, }; pub struct RemoteV0 @@ -154,6 +154,11 @@ impl BmdRemoteProtocol for RemoteV0 { // } + + fn supported_architectures(&self) -> Result> + { + Ok(None) + } } impl From>> for RemoteV0Plus @@ -223,6 +228,11 @@ impl BmdRemoteProtocol for RemoteV0Plus { self.0.target_clk_output_enable(enable); } + + fn supported_architectures(&self) -> Result> + { + self.0.supported_architectures() + } } impl From>> for RemoteV0JTAG diff --git a/src/serial/remote/protocol_v1.rs b/src/serial/remote/protocol_v1.rs index 7529ec6..2f5c7da 100644 --- a/src/serial/remote/protocol_v1.rs +++ b/src/serial/remote/protocol_v1.rs @@ -12,7 +12,7 @@ use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v0::RemoteV0; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, - TargetAddr64, + TargetAddr64, TargetArchitecture, }; pub struct RemoteV1(RemoteV0); @@ -100,6 +100,11 @@ impl BmdRemoteProtocol for RemoteV1 { self.0.target_clk_output_enable(enable); } + + fn supported_architectures(&self) -> Result> + { + self.0.supported_architectures() + } } impl From>> for RemoteV1ADIv5 diff --git a/src/serial/remote/protocol_v2.rs b/src/serial/remote/protocol_v2.rs index 1a7a7a3..b4a0bdb 100644 --- a/src/serial/remote/protocol_v2.rs +++ b/src/serial/remote/protocol_v2.rs @@ -12,6 +12,7 @@ use crate::serial::remote::protocol_v0::RemoteV0JTAG; use crate::serial::remote::protocol_v1::RemoteV1; use crate::serial::remote::{ BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, + TargetArchitecture, }; pub struct RemoteV2(RemoteV1); @@ -108,6 +109,11 @@ impl BmdRemoteProtocol for RemoteV2 { // } + + fn supported_architectures(&self) -> Result> + { + self.0.supported_architectures() + } } impl From>> for RemoteV2JTAG diff --git a/src/serial/remote/protocol_v3.rs b/src/serial/remote/protocol_v3.rs index fc0694a..2731457 100644 --- a/src/serial/remote/protocol_v3.rs +++ b/src/serial/remote/protocol_v3.rs @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; use color_eyre::eyre::Result; use log::warn; @@ -12,7 +12,7 @@ use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v2::RemoteV2; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, - TargetAddr64, + TargetAddr64, TargetArchitecture, }; pub struct RemoteV3(RemoteV2); @@ -39,6 +39,11 @@ impl RemoteV3 Self(RemoteV2::new(interface)) } + pub(crate) fn interface(&self) -> MutexGuard<'_, BmdRspInterface> + { + self.0.interface() + } + pub(crate) fn clone_interface(&self) -> Arc> { self.0.clone_interface() @@ -91,6 +96,11 @@ impl BmdRemoteProtocol for RemoteV3 { self.0.target_clk_output_enable(enable); } + + fn supported_architectures(&self) -> Result> + { + self.0.supported_architectures() + } } impl From>> for RemoteV3ADIv5 diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index 11b5431..f59ef99 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -3,11 +3,11 @@ // SPDX-FileContributor: Written by Rachel Mant use std::fmt::Display; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, MutexGuard}; use bitmask_enum::bitmask; use color_eyre::eyre::{Report, Result, eyre}; -use log::debug; +use log::{debug, warn}; use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; @@ -15,7 +15,7 @@ use crate::serial::remote::protocol_v3::RemoteV3; use crate::serial::remote::riscv_debug::RiscvDmi; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, - REMOTE_RESP_OK, TargetAddr64, decode_response, + REMOTE_RESP_NOTSUP, REMOTE_RESP_OK, TargetAddr64, TargetArchitecture, decode_response, }; pub struct RemoteV4 @@ -59,6 +59,10 @@ enum Acceleration /// This command asks the probe what high-level protocol accelerations it supports const REMOTE_HL_ACCEL: &str = "!HA#"; +/// This command asks the probe what target architectures the firmware build supports +const REMOTE_HL_ARCHS: &str = "!Ha#"; +/// This command asks the probe what target families the firmware build supports +const REMOTE_HL_FAMILIES: &str = "!HF#"; impl TryFrom>> for RemoteV4 { @@ -100,6 +104,11 @@ impl RemoteV4 }) } + pub(crate) fn interface(&self) -> MutexGuard<'_, BmdRspInterface> + { + self.inner_protocol.interface() + } + pub(crate) fn clone_interface(&self) -> Arc> { self.inner_protocol.clone_interface() @@ -164,6 +173,31 @@ impl BmdRemoteProtocol for RemoteV4 { self.inner_protocol.target_clk_output_enable(enable); } + + fn supported_architectures(&self) -> Result> + { + // Send the request to the probe + self.interface().buffer_write(REMOTE_HL_ARCHS)?; + let buffer = self.interface().buffer_read()?; + // Check too see if that failed for some reason + if buffer.is_empty() || (buffer.as_bytes()[0] != REMOTE_RESP_OK && buffer.as_bytes()[0] != REMOTE_RESP_NOTSUP) { + let message = if buffer.len() > 1 { + &buffer[1..] + } else { + "unknown" + }; + Err(eyre!("Supported architectures request failed, error {}", message)) + } else if buffer.as_bytes()[0] == REMOTE_RESP_NOTSUP { + // If we get here, the probe talks v4 but doesn't know this command - meaning pre-v2.0.0 firmware + // but post-v1.10.2. Ask the user to upgrade off development firmware onto the release or later. + warn!("Please upgrade your firmware to allow checking supported target architectures to work properly"); + Ok(None) + } else { + // We got a good response, decode it and turn the value into a bitfield return + let architectures = decode_response(&buffer[1..], 8); + Ok(Some(architectures.into())) + } + } } impl From>> for RemoteV4ADIv5 From 78991096d3644083053e2b1edac1c055bf01367c Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 25 Jun 2025 03:14:03 +0100 Subject: [PATCH 50/57] serial/remote: Defined and implemented a trait function for extracting the supported target families from a probe in BmdRemoteProtocol --- src/serial/remote/mod.rs | 1 + src/serial/remote/protocol_v0.rs | 12 +++++++++++- src/serial/remote/protocol_v1.rs | 7 ++++++- src/serial/remote/protocol_v2.rs | 7 ++++++- src/serial/remote/protocol_v3.rs | 7 ++++++- src/serial/remote/protocol_v4.rs | 27 ++++++++++++++++++++++++++- 6 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 2878e19..b21f75c 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -109,6 +109,7 @@ pub trait BmdRemoteProtocol fn set_comms_frequency(&self, freq: u32) -> bool; fn target_clk_output_enable(&self, enable: bool); fn supported_architectures(&self) -> Result>; + fn supported_families(&self) -> Result>; } /// Types implementing this trait provide raw SWD access to targets over the BMD remote protocol diff --git a/src/serial/remote/protocol_v0.rs b/src/serial/remote/protocol_v0.rs index a453e34..4e004af 100644 --- a/src/serial/remote/protocol_v0.rs +++ b/src/serial/remote/protocol_v0.rs @@ -11,7 +11,7 @@ use crate::serial::bmd_rsp::BmdRspInterface; use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, - REMOTE_RESP_ERR, TargetAddr64, TargetArchitecture, + REMOTE_RESP_ERR, TargetAddr64, TargetArchitecture, TargetFamily, }; pub struct RemoteV0 @@ -159,6 +159,11 @@ impl BmdRemoteProtocol for RemoteV0 { Ok(None) } + + fn supported_families(&self) -> Result> + { + Ok(None) + } } impl From>> for RemoteV0Plus @@ -233,6 +238,11 @@ impl BmdRemoteProtocol for RemoteV0Plus { self.0.supported_architectures() } + + fn supported_families(&self) -> Result> + { + self.0.supported_families() + } } impl From>> for RemoteV0JTAG diff --git a/src/serial/remote/protocol_v1.rs b/src/serial/remote/protocol_v1.rs index 2f5c7da..96ac3da 100644 --- a/src/serial/remote/protocol_v1.rs +++ b/src/serial/remote/protocol_v1.rs @@ -12,7 +12,7 @@ use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v0::RemoteV0; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, - TargetAddr64, TargetArchitecture, + TargetAddr64, TargetArchitecture, TargetFamily, }; pub struct RemoteV1(RemoteV0); @@ -105,6 +105,11 @@ impl BmdRemoteProtocol for RemoteV1 { self.0.supported_architectures() } + + fn supported_families(&self) -> Result> + { + self.0.supported_families() + } } impl From>> for RemoteV1ADIv5 diff --git a/src/serial/remote/protocol_v2.rs b/src/serial/remote/protocol_v2.rs index b4a0bdb..831b0da 100644 --- a/src/serial/remote/protocol_v2.rs +++ b/src/serial/remote/protocol_v2.rs @@ -12,7 +12,7 @@ use crate::serial::remote::protocol_v0::RemoteV0JTAG; use crate::serial::remote::protocol_v1::RemoteV1; use crate::serial::remote::{ BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, REMOTE_RESP_ERR, - TargetArchitecture, + TargetArchitecture, TargetFamily, }; pub struct RemoteV2(RemoteV1); @@ -114,6 +114,11 @@ impl BmdRemoteProtocol for RemoteV2 { self.0.supported_architectures() } + + fn supported_families(&self) -> Result> + { + self.0.supported_families() + } } impl From>> for RemoteV2JTAG diff --git a/src/serial/remote/protocol_v3.rs b/src/serial/remote/protocol_v3.rs index 2731457..c76f21b 100644 --- a/src/serial/remote/protocol_v3.rs +++ b/src/serial/remote/protocol_v3.rs @@ -12,7 +12,7 @@ use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort}; use crate::serial::remote::protocol_v2::RemoteV2; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, - TargetAddr64, TargetArchitecture, + TargetAddr64, TargetArchitecture, TargetFamily, }; pub struct RemoteV3(RemoteV2); @@ -101,6 +101,11 @@ impl BmdRemoteProtocol for RemoteV3 { self.0.supported_architectures() } + + fn supported_families(&self) -> Result> + { + self.0.supported_families() + } } impl From>> for RemoteV3ADIv5 diff --git a/src/serial/remote/protocol_v4.rs b/src/serial/remote/protocol_v4.rs index f59ef99..9b8d01c 100644 --- a/src/serial/remote/protocol_v4.rs +++ b/src/serial/remote/protocol_v4.rs @@ -15,7 +15,7 @@ use crate::serial::remote::protocol_v3::RemoteV3; use crate::serial::remote::riscv_debug::RiscvDmi; use crate::serial::remote::{ Align, BmdAdiV5Protocol, BmdJtagProtocol, BmdRemoteProtocol, BmdRiscvProtocol, BmdSwdProtocol, JtagDev, - REMOTE_RESP_NOTSUP, REMOTE_RESP_OK, TargetAddr64, TargetArchitecture, decode_response, + REMOTE_RESP_NOTSUP, REMOTE_RESP_OK, TargetAddr64, TargetArchitecture, TargetFamily, decode_response, }; pub struct RemoteV4 @@ -198,6 +198,31 @@ impl BmdRemoteProtocol for RemoteV4 Ok(Some(architectures.into())) } } + + fn supported_families(&self) -> Result> + { + // Send the request to the probe + self.interface().buffer_write(REMOTE_HL_FAMILIES)?; + let buffer = self.interface().buffer_read()?; + // Check too see if that failed for some reason + if buffer.is_empty() || (buffer.as_bytes()[0] != REMOTE_RESP_OK && buffer.as_bytes()[0] != REMOTE_RESP_NOTSUP) { + let message = if buffer.len() > 1 { + &buffer[1..] + } else { + "unknown" + }; + Err(eyre!("Supported architectures request failed, error {}", message)) + } else if buffer.as_bytes()[0] == REMOTE_RESP_NOTSUP { + // If we get here, the probe talks v4 but doesn't know this command - meaning pre-v2.0.0 firmware + // but post-v1.10.2. Ask the user to upgrade off development firmware onto the release or later. + warn!("Please upgrade your firmware to allow checking supported target families to work properly"); + Ok(None) + } else { + // We got a good response, decode it and turn the value into a bitfield return + let families = decode_response(&buffer[1..], 8); + Ok(Some(families.into())) + } + } } impl From>> for RemoteV4ADIv5 From 207adbb31f7be103910a66187f1004694259e929 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 25 Jun 2025 03:48:53 +0100 Subject: [PATCH 51/57] serial/remote: Implemented Display for TargetArchitecture --- src/serial/remote/mod.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index b21f75c..5ba132e 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -2,6 +2,7 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant +use std::fmt::Display; use std::sync::{Arc, Mutex}; use bitmask_enum::bitmask; @@ -253,3 +254,24 @@ impl ProtocolVersion } } } + +impl Display for TargetArchitecture +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + let mut architectures = Vec::with_capacity(4); + if self.contains(Self::CortexM) { + architectures.push("ARM Cortex-M"); + } + if self.contains(Self::CortexAR) { + architectures.push("ARM Cortex-A/R"); + } + if self.contains(Self::RiscV32) { + architectures.push("RISC-V 32-bit"); + } + if self.contains(Self::RiscV64) { + architectures.push("RISC-V 64-bit"); + } + write!(fmt, "{}", architectures.join(", ")) + } +} From 5f88600027367988a28132cb637d46ddf4f94520 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 25 Jun 2025 04:11:08 +0100 Subject: [PATCH 52/57] serial/remote: Implemented Display for TargetFamily --- src/serial/remote/mod.rs | 69 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index 5ba132e..a7ebc9a 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -275,3 +275,72 @@ impl Display for TargetArchitecture write!(fmt, "{}", architectures.join(", ")) } } + +impl Display for TargetFamily +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + let mut families = Vec::with_capacity(64); + if self.contains(Self::AT32) { + families.push("AteryTek AT32"); + } + if self.contains(Self::Apollo3) { + families.push("Ambiq Apollo3"); + } + if self.contains(Self::CH32) { + families.push("WinChipHead CH32"); + } + if self.contains(Self::CH579) { + families.push("WinChipHead CH579"); + } + if self.contains(Self::EFM) { + families.push("Energy Micro EFM32/EFR32/EZR32"); + } + if self.contains(Self::GD32) { + families.push("GigaDevice GD32"); + } + if self.contains(Self::HC32) { + families.push("HDSC HC32"); + } + if self.contains(Self::LPC) { + families.push("NXP LPC"); + } + if self.contains(Self::MM32) { + families.push("MindMotion MM32"); + } + if self.contains(Self::NRF) { + families.push("Nordi Semi nRF"); + } + if self.contains(Self::NXPKinetis) { + families.push("NXP/Freescale Kinetis"); + } + if self.contains(Self::NXPiMXRT) { + families.push("NXP i.MXRT"); + } + if self.contains(Self::Puya) { + families.push("Puya PY32"); + } + if self.contains(Self::RenesasRA) { + families.push("Renesas RA"); + } + if self.contains(Self::RenesasRZ) { + families.push("Renesas RZ"); + } + if self.contains(Self::RP) { + families.push("RPi Foundation RP2040/RP2350"); + } + if self.contains(Self::SAM) { + families.push("Atmel/Microchip ATSAM"); + } + if self.contains(Self::STM) { + families.push("ST Micro STM32"); + } + if self.contains(Self::TI) { + families.push("TI MSP432 and LM3S/TM4C"); + } + if self.contains(Self::Xilinx) { + families.push("Xilinx Zynq"); + } + write!(fmt, "{}", families.join(", ")) + } +} From a01b81a642830ff45f63fe34c8f0cc6945062a75 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 25 Jun 2025 04:11:56 +0100 Subject: [PATCH 53/57] bmputil-cli: Implemented the guts of list_targets() --- src/bin/bmputil-cli.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bin/bmputil-cli.rs b/src/bin/bmputil-cli.rs index d1b369f..8d3ed08 100644 --- a/src/bin/bmputil-cli.rs +++ b/src/bin/bmputil-cli.rs @@ -378,7 +378,22 @@ fn display_releases(paths: &ProjectDirs) -> Result<()> fn list_targets(probe: BmpDevice) -> Result<()> { + // Extract the remote protocol interface for the probe let remote = probe.bmd_serial_interface()?.remote()?; + // Ask it what architectures it supports, and display that + let archs = remote.supported_architectures()?; + if let Some(archs) = archs { + info!("Probe supports the following target architectures: {}", archs); + } else { + info!("Could not determine what target architectures your probe supports - please upgrade your firmware."); + } + // Ask it what target families it supports, and display that + let families = remote.supported_families()?; + if let Some(families) = families { + info!("Probe supports the following target families: {}", families); + } else { + info!("Could not determine what target families your probe supports - please upgrade your firmware."); + } Ok(()) } From 5c6fcc40fb7f6475531f6de6ce689dc61bab6845 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 25 Jun 2025 10:18:08 +0100 Subject: [PATCH 54/57] serial/bmd_rsp: Implemented BmdRspInterface::init_handle() for Windows --- Cargo.lock | 88 +++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/serial/bmd_rsp.rs | 78 +++++++++++++++++++++++++++++++++++++- 3 files changed, 165 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bf3822..3673ac1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,6 +256,7 @@ dependencies = [ "url", "wdi", "winapi", + "windows", "windows-registry", "winreg", ] @@ -3752,12 +3753,90 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "windows-link" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link", +] + [[package]] name = "windows-registry" version = "0.5.2" @@ -3870,6 +3949,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" diff --git a/Cargo.toml b/Cargo.toml index 92d7720..a92af46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ deelevate = "0.2.0" libc = "0.2.132" lazy_static = "1.4.0" winreg = "0.10.1" +windows = { version = "0.61.3", features = ["Win32_Devices_Communication"] } windows-registry = "0.5.2" [target.'cfg(windows)'.dependencies.winapi] diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index d74463e..2e9d5a4 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -4,6 +4,7 @@ use std::fs::File; use std::io::Write; +use std::mem::MaybeUninit; use std::path::Path; use std::sync::{Arc, Mutex}; @@ -211,7 +212,6 @@ impl BmdRspInterface fn read_more_data(&mut self) -> Result<()> { use std::io::Read; - use std::mem::MaybeUninit; use std::os::fd::AsRawFd; use std::ptr::null_mut; @@ -251,4 +251,78 @@ impl BmdRspInterface } #[cfg(target_os = "windows")] -impl BmdRspInterface {} +impl BmdRspInterface +{ + const DCB_CHECK_PARITY: u32 = 1 << 1; + const DCB_DSR_SENSITIVE: u32 = 1 << 6; + const DCB_DTR_CONTROL_ENABLE: u32 = 1 << 4; + const DCB_DTR_CONTROL_MASK: u32 = 3 << 4; + const DCB_RTS_CONTROL_DISABLE: u32 = 0 << 12; + const DCB_RTS_CONTROL_MASK: u32 = 3 << 12; + const DCB_USE_CTS: u32 = 1 << 2; + const DCB_USE_DSR: u32 = 1 << 3; + const DCB_USE_XOFF: u32 = 1 << 9; + const DCB_USE_XON: u32 = 1 << 8; + + fn init_handle(&self) -> Result<()> + { + use std::os::windows::io::AsRawHandle; + + use windows::Win32::Devices::Communication::{ + COMMTIMEOUTS, DCB, GetCommState, NOPARITY, PURGE_RXCLEAR, PurgeComm, SetCommState, SetCommTimeouts, + }; + use windows::Win32::Foundation::HANDLE; + + // Extract the current CommState for the handle + let handle = HANDLE(self.handle.as_raw_handle()); + let mut serial_params = MaybeUninit::::uninit(); + let mut serial_params = unsafe { + GetCommState(handle, serial_params.as_mut_ptr())?; + serial_params.assume_init() + }; + + // Reconfigure and adjust device state to disable hardware flow control and + // get it into the right mode for communications to work properly + serial_params.ByteSize = 8; + serial_params.Parity = NOPARITY; + // The windows-rs crate exposes the bitfield parameters to us as a nebulous thing.. + // we hold local definitions for each of the values so we can turn them on and off + // appropriately here. See + // for where these values come from. When reading this particular bitfield, assume LSb to MSb + // as one traverses down the structure. + serial_params._bitfield &= !(Self::DCB_CHECK_PARITY | + Self::DCB_USE_CTS | + Self::DCB_USE_DSR | + Self::DCB_DTR_CONTROL_MASK | + Self::DCB_DSR_SENSITIVE | + Self::DCB_USE_XOFF | + Self::DCB_USE_XON | + Self::DCB_RTS_CONTROL_MASK); + serial_params._bitfield |= Self::DCB_DTR_CONTROL_ENABLE | Self::DCB_RTS_CONTROL_DISABLE; + + // Reconfigure the handle with the new communications state + unsafe { SetCommState(handle, &serial_params)? }; + + let timeouts = COMMTIMEOUTS { + // Turn off read timeouts so that ReadFile() underlying File's read calls instantly returns + // even if there's o data waiting (we implement our own mechanism below for that case as we + // only want to wait if we get no data) + ReadIntervalTimeout: u32::MAX, + ReadTotalTimeoutMultiplier: 0, + ReadTotalTimeoutConstant: 0, + // Configure an exactly 100ms write timeout - we want this triggering to be fatal as something + // has gone very wrong if we ever hit this. + WriteTotalTimeoutMultiplier: 0, + WriteTotalTimeoutConstant: 100, + }; + unsafe { + SetCommTimeouts(handle, &timeouts)?; + + // Having adjusted the line state, discard anything sat in the receive buffer + PurgeComm(handle, PURGE_RXCLEAR)?; + } + + // Let the caller know that we successfully got done + Ok(()) + } +} From 7c10fd7304744ec6e2904f9460d4040cd77fd2f8 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 25 Jun 2025 10:28:56 +0100 Subject: [PATCH 55/57] serial/bmd_rsp: Implemented BmdRspInterface::read_more_data() for Windows --- Cargo.lock | 1 + Cargo.toml | 3 ++- src/serial/bmd_rsp.rs | 25 +++++++++++++++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3673ac1..8f89399 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -258,6 +258,7 @@ dependencies = [ "winapi", "windows", "windows-registry", + "windows-result", "winreg", ] diff --git a/Cargo.toml b/Cargo.toml index a92af46..e81ba69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,8 +45,9 @@ deelevate = "0.2.0" libc = "0.2.132" lazy_static = "1.4.0" winreg = "0.10.1" -windows = { version = "0.61.3", features = ["Win32_Devices_Communication"] } +windows = { version = "0.61.3", features = ["Win32_Devices_Communication", "Win32_System_Threading"] } windows-registry = "0.5.2" +windows-result = "0.3.4" [target.'cfg(windows)'.dependencies.winapi] version = "0.3.9" diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 2e9d5a4..45c6345 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -3,7 +3,7 @@ // SPDX-FileContributor: Written by Rachel Mant use std::fs::File; -use std::io::Write; +use std::io::{Read, Write}; use std::mem::MaybeUninit; use std::path::Path; use std::sync::{Arc, Mutex}; @@ -211,7 +211,6 @@ impl BmdRspInterface fn read_more_data(&mut self) -> Result<()> { - use std::io::Read; use std::os::fd::AsRawFd; use std::ptr::null_mut; @@ -325,4 +324,26 @@ impl BmdRspInterface // Let the caller know that we successfully got done Ok(()) } + + fn read_more_data(&mut self) -> Result<()> + { + use std::os::windows::io::AsRawHandle; + + use windows::Win32::Foundation::{HANDLE, WAIT_OBJECT_0}; + use windows::Win32::System::Threading::WaitForSingleObject; + use windows_result::Error; + + // Try to wait for up to 100ms for data to become available + let handle = HANDLE(self.handle.as_raw_handle()); + if unsafe { WaitForSingleObject(handle, 100) } != WAIT_OBJECT_0 { + return Err(eyre!("Timeout while waiting for BMD RSP response: {}", Error::from_win32())); + } + + // Now we know there's data, so try to fill the read buffer + let bytes_received = self.handle.read(&mut self.read_buffer)?; + // Now we have more data, so update the read buffer counters + self.read_buffer_fullness = bytes_received; + self.read_buffer_offset = 0; + Ok(()) + } } From df2383806124631d2138dd56cc2154d377ac953a Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 25 Jun 2025 12:25:19 +0100 Subject: [PATCH 56/57] serial/remote: Implemented Display for ProtocolVersion --- src/serial/remote/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/serial/remote/mod.rs b/src/serial/remote/mod.rs index a7ebc9a..2f70add 100644 --- a/src/serial/remote/mod.rs +++ b/src/serial/remote/mod.rs @@ -255,6 +255,22 @@ impl ProtocolVersion } } +impl Display for ProtocolVersion +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + match self { + Self::Unknown => write!(fmt, ""), + Self::V0 => write!(fmt, "v0"), + Self::V0Plus => write!(fmt, "v0+"), + Self::V1 => write!(fmt, "v1"), + Self::V2 => write!(fmt, "v2"), + Self::V3 => write!(fmt, "v3"), + Self::V4 => write!(fmt, "v4"), + } + } +} + impl Display for TargetArchitecture { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result From cebacb0af221151a70d7a18878b6696eafa967ac Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 25 Jun 2025 12:25:45 +0100 Subject: [PATCH 57/57] serial/bmd_rsp: Added some tracing information to aid with debugging RSP problems --- src/serial/bmd_rsp.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/serial/bmd_rsp.rs b/src/serial/bmd_rsp.rs index 45c6345..08bf5b2 100644 --- a/src/serial/bmd_rsp.rs +++ b/src/serial/bmd_rsp.rs @@ -9,7 +9,7 @@ use std::path::Path; use std::sync::{Arc, Mutex}; use color_eyre::eyre::{Result, eyre}; -use log::debug; +use log::{debug, trace}; use crate::serial::remote::*; @@ -97,6 +97,7 @@ impl BmdRspInterface _ => return Err(eyre!("Unknown remote protocol version {}", version)), }; } + trace!("Probe talks BMD RSP {}", result.protocol_version); // Now the object is ready to go, return it to the caller Ok(result) @@ -206,6 +207,7 @@ impl BmdRspInterface tcsetattr(fd, TCSANOW, &attrs)?; // Let the caller know that we successfully got done + trace!("Configured comms handle to probe remote serial interface"); Ok(()) } @@ -241,6 +243,7 @@ impl BmdRspInterface } else { // Otherwise we now know there's data, so try to fill the read buffer let bytes_received = self.handle.read(&mut self.read_buffer)?; + trace!("Read {} bytes from probe", bytes_received); // Now we have more data, so update the read buffer counters self.read_buffer_fullness = bytes_received; self.read_buffer_offset = 0; @@ -322,6 +325,7 @@ impl BmdRspInterface } // Let the caller know that we successfully got done + trace!("Configured comms handle to probe remote serial interface"); Ok(()) } @@ -341,6 +345,7 @@ impl BmdRspInterface // Now we know there's data, so try to fill the read buffer let bytes_received = self.handle.read(&mut self.read_buffer)?; + trace!("Read {} bytes from probe", bytes_received); // Now we have more data, so update the read buffer counters self.read_buffer_fullness = bytes_received; self.read_buffer_offset = 0;