1use std::{
3 char,
4 io::{BufReader, BufWriter, Read, Write},
5 net::SocketAddr,
6 sync::Arc,
7 time::Duration,
8};
9
10use crate::{
11 architecture::{
12 arm::{
13 ArmCommunicationInterface, ArmDebugInterface, ArmError,
14 communication_interface::DapProbe, sequences::ArmDebugSequence,
15 },
16 riscv::{
17 communication_interface::{RiscvError, RiscvInterfaceBuilder},
18 dtm::jtag_dtm::JtagDtmBuilder,
19 },
20 xtensa::communication_interface::{
21 XtensaCommunicationInterface, XtensaDebugInterfaceState, XtensaError,
22 },
23 },
24 probe::{
25 AutoImplementJtagAccess, DebugProbe, DebugProbeError, DebugProbeInfo, DebugProbeSelector,
26 IoSequenceItem, JtagAccess, JtagDriverState, ProbeCreationError, ProbeError, ProbeFactory,
27 ProbeStatistics, RawJtagIo, RawSwdIo, SwdSettings, WireProtocol,
28 blackmagic::arm::BlackMagicProbeArmDebug,
29 },
30};
31use bitvec::vec::BitVec;
32use serialport::{SerialPortType, available_ports};
33
34const BLACK_MAGIC_PROBE_VID: u16 = 0x1d50;
35const BLACK_MAGIC_PROBE_PID: u16 = 0x6018;
36const BLACK_MAGIC_PROBE: (u16, u16) = (BLACK_MAGIC_PROBE_VID, BLACK_MAGIC_PROBE_PID);
37const BLACK_MAGIC_PROTOCOL_RESPONSE_START: u8 = b'&';
38const BLACK_MAGIC_PROTOCOL_RESPONSE_END: u8 = b'#';
39pub(crate) const BLACK_MAGIC_REMOTE_SIZE_MAX: usize = 1024;
40
41mod arm;
42
43#[derive(Debug)]
45pub struct BlackMagicProbeFactory;
46
47#[derive(PartialEq)]
48enum ProtocolVersion {
49 V0,
50 V0P,
51 V1,
52 V2,
53 V3,
54 V4,
55}
56
57#[derive(Debug, Copy, Clone)]
58pub(crate) enum Align {
59 U8 = 0,
60 U16 = 1,
61 U32 = 2,
62 U64 = 3,
63}
64
65impl core::fmt::Display for ProtocolVersion {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(
68 f,
69 "{}",
70 match self {
71 Self::V0 => "V0",
72 Self::V0P => "V0P",
73 Self::V1 => "V1",
74 Self::V2 => "V2",
75 Self::V3 => "V3",
76 Self::V4 => "V4",
77 }
78 )
79 }
80}
81
82#[expect(dead_code)]
83#[derive(Debug)]
84enum RemoteCommand<'a> {
85 Handshake(&'a mut [u8]),
86 GetAccelerators,
87 HighLevelCheck,
88 GetVoltage,
89 GetSpeedKhz,
90 SetNrst(bool),
91 SetPower(bool),
92 TargetClockOutput {
93 enable: bool,
94 },
95 SetSpeedHz(u32),
96 SpeedKhz,
97 TargetReset(bool),
98 RawAccessV0P {
99 rnw: u8,
100 addr: u8,
101 value: u32,
102 },
103 ReadDpV0P {
104 addr: u8,
105 },
106 ReadApV0P {
107 apsel: u8,
108 addr: u8,
109 },
110 WriteApV0P {
111 apsel: u8,
112 addr: u8,
113 value: u32,
114 },
115 MemReadV0P {
116 apsel: u8,
117 csw: u32,
118 offset: u32,
119 data: &'a mut [u8],
120 },
121 MemWriteV0P {
122 apsel: u8,
123 csw: u32,
124 align: Align,
125 offset: u32,
126 data: &'a [u8],
127 },
128 RawAccessV1 {
129 index: u8,
130 rnw: u8,
131 addr: u8,
132 value: u32,
133 },
134 ReadDpV1 {
135 index: u8,
136 addr: u8,
137 },
138 ReadApV1 {
139 index: u8,
140 apsel: u8,
141 addr: u8,
142 },
143 WriteApV1 {
144 index: u8,
145 apsel: u8,
146 addr: u8,
147 value: u32,
148 },
149 MemReadV1 {
150 index: u8,
151 apsel: u8,
152 csw: u32,
153 offset: u32,
154 data: &'a mut [u8],
155 },
156 MemWriteV1 {
157 index: u8,
158 apsel: u8,
159 csw: u32,
160 align: Align,
161 offset: u32,
162 data: &'a [u8],
163 },
164 RawAccessV3 {
165 index: u8,
166 rnw: u8,
167 addr: u8,
168 value: u32,
169 },
170 ReadDpV3 {
171 index: u8,
172 addr: u8,
173 },
174 ReadApV3 {
175 index: u8,
176 apsel: u8,
177 addr: u8,
178 },
179 WriteApV3 {
180 index: u8,
181 apsel: u8,
182 addr: u8,
183 value: u32,
184 },
185 MemReadV3 {
186 index: u8,
187 apsel: u8,
188 csw: u32,
189 offset: u32,
190 data: &'a mut [u8],
191 },
192 MemWriteV3 {
193 index: u8,
194 apsel: u8,
195 csw: u32,
196 align: Align,
197 offset: u32,
198 data: &'a [u8],
199 },
200 MemReadV4 {
201 index: u8,
202 apsel: u8,
203 csw: u32,
204 offset: u64,
205 data: &'a mut [u8],
206 },
207 MemWriteV4 {
208 index: u8,
209 apsel: u8,
210 csw: u32,
211 align: Align,
212 offset: u64,
213 data: &'a [u8],
214 },
215 JtagNext {
216 tms: bool,
217 tdi: bool,
218 },
219 JtagTms {
220 bits: u32,
221 length: usize,
222 },
223 JtagTdi {
224 bits: u32,
225 length: usize,
226 tms: bool,
227 },
228 JtagInit,
229 JtagReset,
230 JtagAddDevice {
231 index: u8,
232 dr_prescan: u8,
233 dr_postscan: u8,
234 ir_len: u8,
235 ir_prescan: u8,
236 ir_postscan: u8,
237 current_ir: u32,
238 },
239 SwdInit,
240 SwdIn {
241 length: usize,
242 },
243 SwdInParity {
244 length: usize,
245 },
246 SwdOut {
247 value: u32,
248 length: usize,
249 },
250 SwdOutParity {
251 value: u32,
252 length: usize,
253 },
254}
255
256impl RemoteCommand<'_> {
257 fn response_buffer(&mut self) -> Option<&mut [u8]> {
260 match self {
261 RemoteCommand::Handshake(data) => Some(data),
262 RemoteCommand::MemReadV0P { data, .. } => Some(data),
263 RemoteCommand::MemReadV1 { data, .. } => Some(data),
264 RemoteCommand::MemReadV3 { data, .. } => Some(data),
265 RemoteCommand::MemReadV4 { data, .. } => Some(data),
266 _ => None,
267 }
268 }
269
270 fn decode_hex(&self) -> bool {
272 matches!(
273 self,
274 RemoteCommand::MemReadV0P { .. }
275 | RemoteCommand::MemReadV1 { .. }
276 | RemoteCommand::MemReadV3 { .. }
277 | RemoteCommand::MemReadV4 { .. }
278 )
279 }
280}
281
282#[expect(clippy::to_string_trait_impl)]
285impl std::string::ToString for RemoteCommand<'_> {
286 fn to_string(&self) -> String {
287 match self {
288 RemoteCommand::Handshake(_) => "+#!GA#".to_string(),
289 RemoteCommand::GetVoltage => " !GV#".to_string(),
290 RemoteCommand::GetSpeedKhz => "!Gf#".to_string(),
291 RemoteCommand::SetSpeedHz(speed) => {
292 format!("!GF{speed:08x}#")
293 }
294 RemoteCommand::HighLevelCheck => "!HC#".to_string(),
295 RemoteCommand::SetNrst(set) => format!("!GZ{}#", if *set { '1' } else { '0' }),
296 RemoteCommand::SetPower(set) => format!("!GP{}#", if *set { '1' } else { '0' }),
297 RemoteCommand::TargetClockOutput { enable } => {
298 format!("!GE{}#", if *enable { '1' } else { '0' })
299 }
300 RemoteCommand::SpeedKhz => "!Gf#".to_string(),
301 RemoteCommand::RawAccessV0P { rnw, addr, value } => {
302 format!("!HL{rnw:02x}{addr:04x}{value:08x}#")
303 }
304 RemoteCommand::ReadDpV0P { addr } => {
305 format!("!Hdff{addr:04x}#")
306 }
307 RemoteCommand::ReadApV0P { apsel, addr } => {
308 format!("!Ha{:02x}{:04x}#", apsel, 0x100 | *addr as u16)
309 }
310 RemoteCommand::WriteApV0P { apsel, addr, value } => {
311 format!("!HA{:02x}{:04x}{:08x}#", apsel, 0x100 | *addr as u16, value)
312 }
313 RemoteCommand::MemReadV0P {
314 apsel,
315 csw,
316 offset,
317 data,
318 } => format!(
319 "!HM{:02x}{:08x}{:08x}{:08x}#",
320 apsel,
321 csw,
322 offset,
323 data.len()
324 ),
325 RemoteCommand::MemWriteV0P {
326 apsel,
327 csw,
328 align,
329 offset,
330 data,
331 } => {
332 let mut s = format!(
333 "!Hm{:02x}{:08x}{:02x}{:08x}{:08x}",
334 apsel,
335 csw,
336 *align as u8,
337 offset,
338 data.len(),
339 );
340 for b in data.iter() {
341 s.push_str(&format!("{b:02x}"));
342 }
343 s.push('#');
344 s
345 }
346
347 RemoteCommand::RawAccessV1 {
348 index,
349 rnw,
350 addr,
351 value,
352 } => {
353 format!("!HL{index:02x}{rnw:02x}{addr:04x}{value:08x}#")
354 }
355 RemoteCommand::ReadDpV1 { index, addr } => {
356 format!("!Hd{index:02x}ff{addr:04x}#")
357 }
358 RemoteCommand::ReadApV1 { index, apsel, addr } => {
359 format!("!Ha{:02x}{:02x}{:04x}#", index, apsel, 0x100 | *addr as u16)
360 }
361 RemoteCommand::WriteApV1 {
362 index,
363 apsel,
364 addr,
365 value,
366 } => format!(
367 "!HA{:02x}{:02x}{:04x}{:08x}#",
368 index,
369 apsel,
370 0x100 | *addr as u16,
371 value
372 ),
373 RemoteCommand::MemReadV1 {
374 index,
375 apsel,
376 csw,
377 offset,
378 data,
379 } => format!(
380 "!HM{:02x}{:02x}{:08x}{:08x}{:08x}#",
381 index,
382 apsel,
383 csw,
384 offset,
385 data.len()
386 ),
387 RemoteCommand::MemWriteV1 {
388 index,
389 apsel,
390 csw,
391 align,
392 offset,
393 data,
394 } => {
395 let mut s = format!(
396 "!Hm{:02x}{:02x}{:08x}{:02x}{:08x}{:08x}",
397 index,
398 apsel,
399 csw,
400 *align as u8,
401 offset,
402 data.len()
403 );
404 for b in data.iter() {
405 s.push_str(&format!("{b:02x}"));
406 }
407 s.push('#');
408 s
409 }
410
411 RemoteCommand::RawAccessV3 {
412 index,
413 rnw,
414 addr,
415 value,
416 } => {
417 format!("!AR{index:02x}{rnw:02x}{addr:04x}{value:08x}#")
418 }
419 RemoteCommand::ReadDpV3 { index, addr } => {
420 format!("!Ad{index:02x}ff{addr:04x}#")
421 }
422 RemoteCommand::ReadApV3 { index, apsel, addr } => {
423 format!("!Aa{:02x}{:02x}{:04x}#", index, apsel, 0x100 | *addr as u16)
424 }
425 RemoteCommand::WriteApV3 {
426 index,
427 apsel,
428 addr,
429 value,
430 } => format!(
431 "!AA{:02x}{:02x}{:04x}{:08x}#",
432 index,
433 apsel,
434 0x100 | *addr as u16,
435 value.to_be()
436 ),
437 RemoteCommand::MemReadV3 {
438 index,
439 apsel,
440 csw,
441 offset,
442 data,
443 } => format!(
444 "!Am{:02x}{:02x}{:08x}{:08x}{:08x}#",
445 index,
446 apsel,
447 csw,
448 offset,
449 data.len()
450 ),
451 RemoteCommand::MemWriteV3 {
452 index,
453 apsel,
454 csw,
455 align,
456 offset,
457 data,
458 } => {
459 let mut s = format!(
460 "!AM{:02x}{:02x}{:08x}{:02x}{:08x}{:08x}",
461 index,
462 apsel,
463 csw,
464 *align as u8,
465 offset,
466 data.len()
467 );
468 for b in data.iter() {
469 s.push_str(&format!("{b:02x}"));
470 }
471 s.push('#');
472 s
473 }
474
475 RemoteCommand::MemReadV4 {
476 index,
477 apsel,
478 csw,
479 offset,
480 data,
481 } => format!(
482 "!Am{:02x}{:02x}{:08x}{:016x}{:08x}#",
483 index,
484 apsel,
485 csw,
486 offset,
487 data.len()
488 ),
489 RemoteCommand::MemWriteV4 {
490 index,
491 apsel,
492 csw,
493 align,
494 offset,
495 data,
496 } => {
497 let mut s = format!(
498 "!AM{:02x}{:02x}{:08x}{:02x}{:016x}{:08x}",
499 index,
500 apsel,
501 csw,
502 *align as u8,
503 offset,
504 data.len()
505 );
506 for b in data.iter() {
507 s.push_str(&format!("{b:02x}"));
508 }
509 s.push('#');
510 s
511 }
512
513 RemoteCommand::JtagNext { tms, tdi } => format!(
514 "!JN{}{}#",
515 if *tms { '1' } else { '0' },
516 if *tdi { '1' } else { '0' }
517 ),
518 RemoteCommand::JtagInit => "+#!JS#".to_string(),
519 RemoteCommand::JtagReset => "+#!JR#".to_string(),
520 RemoteCommand::JtagTms { bits, length } => {
521 format!("!JT{:02x}{:x}#", *length, *bits)
522 }
523 RemoteCommand::JtagTdi { bits, length, tms } => format!(
524 "!J{}{:02x}{:x}#",
525 if *tms { 'D' } else { 'd' },
526 *length,
527 *bits
528 ),
529 RemoteCommand::JtagAddDevice {
530 index,
531 dr_prescan,
532 dr_postscan,
533 ir_len,
534 ir_prescan,
535 ir_postscan,
536 current_ir,
537 } => format!(
538 "!HJ{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:08x}#",
539 *index, *dr_prescan, *dr_postscan, *ir_len, *ir_prescan, *ir_postscan, *current_ir
540 ),
541 RemoteCommand::SwdInit => "!SS#".to_string(),
542 RemoteCommand::SwdIn { length: bits } => {
543 format!("!Si{:02x}#", *bits)
544 }
545 RemoteCommand::SwdInParity { length } => {
546 format!("!SI{:02x}#", *length)
547 }
548 RemoteCommand::SwdOut { value, length } => {
549 format!("!So{:02x}{:x}#", *length, *value)
550 }
551 RemoteCommand::SwdOutParity { value, length } => {
552 format!("!SO{:02x}{:x}#", *length, *value)
553 }
554 RemoteCommand::TargetReset(reset) => {
555 format!("!GZ{}#", if *reset { '1' } else { '0' })
556 }
557 RemoteCommand::GetAccelerators => "!HA#".to_string(),
558 }
559 }
560}
561
562#[derive(Debug, thiserror::Error)]
563enum RemoteError {
564 ParameterError(u64),
565 Error(u64),
566 Unsupported(u64),
567 ProbeError(std::io::Error),
568 UnsupportedVersion(u64),
569}
570
571impl core::fmt::Display for RemoteError {
572 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
573 match self {
574 Self::ParameterError(e) => write!(f, "Remote paramater error with result {:016x}", *e),
575 Self::Error(e) => write!(f, "Remote error with result {:016x}", *e),
576 Self::Unsupported(e) => write!(f, "Remote command unsupported with result {:016x}", *e),
577 Self::ProbeError(e) => write!(f, "Probe error {e}"),
578 Self::UnsupportedVersion(e) => write!(f, "Only versions 0-4 are supported, not {e}"),
579 }
580 }
581}
582
583impl ProbeError for RemoteError {}
584
585struct RemoteResponse(u64);
586
587#[derive(PartialEq, Copy, Clone)]
588enum SwdDirection {
589 Input,
590 Output,
591}
592
593impl From<bool> for SwdDirection {
594 fn from(value: bool) -> Self {
595 if value {
596 SwdDirection::Output
597 } else {
598 SwdDirection::Input
599 }
600 }
601}
602
603impl From<IoSequenceItem> for SwdDirection {
604 fn from(value: IoSequenceItem) -> Self {
605 match value {
606 IoSequenceItem::Input => SwdDirection::Input,
607 IoSequenceItem::Output(_) => SwdDirection::Output,
608 }
609 }
610}
611
612pub struct BlackMagicProbe {
614 reader: BufReader<Box<dyn Read + Send>>,
615 writer: BufWriter<Box<dyn Write + Send>>,
616 protocol: Option<WireProtocol>,
617 version: String,
618 remote_protocol: ProtocolVersion,
619 speed_khz: u32,
620 jtag_state: JtagDriverState,
621 probe_statistics: ProbeStatistics,
622 swd_settings: SwdSettings,
623 in_bits: BitVec,
624 swd_direction: SwdDirection,
625}
626
627impl core::fmt::Debug for BlackMagicProbe {
628 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
629 write!(
630 f,
631 "Black Magic Probe {} with remote protocol {}",
632 self.version, self.remote_protocol
633 )
634 }
635}
636
637impl core::fmt::Display for BlackMagicProbeFactory {
638 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
639 write!(f, "Black Magic Probe")
640 }
641}
642
643impl BlackMagicProbe {
644 fn new(
645 reader: Box<dyn Read + Send>,
646 writer: Box<dyn Write + Send>,
647 ) -> Result<Self, DebugProbeError> {
648 let mut reader = BufReader::new(reader);
649 let mut writer = BufWriter::new(writer);
650
651 let mut handshake_response = [0u8; 1024];
652 Self::send(
653 &mut writer,
654 &RemoteCommand::Handshake(&mut handshake_response),
655 )?;
656 let response_len = Self::recv(&mut reader, Some(&mut handshake_response), false)
657 .map_err(|e| {
658 tracing::error!("Unable to receive command: {:?}", e);
659 DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
660 })?
661 .0;
662 let version =
663 String::from_utf8_lossy(&handshake_response[0..response_len as usize]).to_string();
664 tracing::info!("Probe version {}", version);
665
666 Self::send(&mut writer, &RemoteCommand::HighLevelCheck)?;
667 let remote_protocol = if let Ok(response) = Self::recv(&mut reader, None, false) {
668 match response.0 {
669 0 => ProtocolVersion::V0P,
670 1 => ProtocolVersion::V1,
671 2 => ProtocolVersion::V2,
672 3 => ProtocolVersion::V3,
673 4 => ProtocolVersion::V4,
674 version => {
675 return Err(DebugProbeError::ProbeCouldNotBeCreated(
676 ProbeCreationError::ProbeSpecific(
677 RemoteError::UnsupportedVersion(version).into(),
678 ),
679 ));
680 }
681 }
682 } else {
683 ProtocolVersion::V0
684 };
685
686 tracing::info!("Using BMP protocol {}", remote_protocol);
687
688 let mut probe = Self {
689 reader,
690 writer,
691 protocol: None,
692 version,
693 speed_khz: 0,
694 remote_protocol,
695 jtag_state: JtagDriverState::default(),
696 swd_settings: SwdSettings::default(),
697 probe_statistics: ProbeStatistics::default(),
698 in_bits: BitVec::new(),
699 swd_direction: SwdDirection::Output,
700 };
701
702 probe.command(RemoteCommand::SetNrst(false)).ok();
703 probe.command(RemoteCommand::GetVoltage).ok();
704 probe.command(RemoteCommand::SetSpeedHz(400_0000)).ok();
705 probe.command(RemoteCommand::GetSpeedKhz).ok();
706
707 Ok(probe)
708 }
709
710 fn command(&mut self, mut command: RemoteCommand) -> Result<RemoteResponse, RemoteError> {
711 let result = Self::send(&mut self.writer, &command);
712 if let Err(e) = result {
713 tracing::error!("Error sending command: {:?}", e);
714 return Err(e);
715 }
716 let should_decode = command.decode_hex();
717
718 Self::recv(&mut self.reader, command.response_buffer(), should_decode)
719 }
720
721 fn send(
722 writer: &mut BufWriter<Box<dyn Write + Send>>,
723 command: &RemoteCommand,
724 ) -> Result<(), RemoteError> {
725 let s = command.to_string();
726 tracing::debug!(" > {}", s);
727 write!(writer, "{s}").map_err(RemoteError::ProbeError)?;
728 writer.flush().map_err(RemoteError::ProbeError)
729 }
730
731 fn hex_val(c: u8) -> Result<u8, char> {
732 match c {
733 b'A'..=b'F' => Ok(c - b'A' + 10),
734 b'a'..=b'f' => Ok(c - b'a' + 10),
735 b'0'..=b'9' => Ok(c - b'0'),
736 _ => Err(c as char),
737 }
738 }
739
740 fn from_hex_u64(hex: &[u8]) -> Result<u64, ()> {
741 let hex = if hex.first() == Some(&b'0')
743 && (hex.get(1) == Some(&b'x') || hex.get(1) == Some(&b'X'))
744 {
745 &hex[2..]
746 } else {
747 hex
748 };
749
750 let mut val = 0u64;
751
752 for (index, c) in hex.iter().rev().enumerate() {
753 let decoded_val: u64 = Self::hex_val(*c).or(Err(()))?.into();
754 val += decoded_val << (index * 4);
755 }
756 Ok(val)
757 }
758
759 fn recv_u64(reader: &mut BufReader<Box<dyn Read + Send>>) -> Result<u64, RemoteError> {
760 let mut response_buffer = [0u8; 16];
761 let mut response_len = 0;
762 for dest in response_buffer.iter_mut() {
763 let mut byte = [0u8; 1];
764 reader
765 .read_exact(&mut byte)
766 .map_err(RemoteError::ProbeError)?;
767 if byte[0] == BLACK_MAGIC_PROTOCOL_RESPONSE_END {
768 break;
769 }
770 *dest = byte[0];
771 response_len += 1;
772 }
773 Self::from_hex_u64(&response_buffer[0..response_len])
775 .or(Err(RemoteError::ParameterError(0)))
776 }
777
778 fn recv(
779 reader: &mut BufReader<Box<dyn Read + Send>>,
780 buffer: Option<&mut [u8]>,
781 decode_hex: bool,
782 ) -> Result<RemoteResponse, RemoteError> {
783 loop {
785 let mut byte = [0u8; 1];
786 reader
787 .read_exact(&mut byte)
788 .map_err(RemoteError::ProbeError)?;
789 if byte[0] == BLACK_MAGIC_PROTOCOL_RESPONSE_START {
790 break;
791 }
792 }
793 let mut response_code = [0u8; 1];
794 reader
795 .read_exact(&mut response_code)
796 .map_err(RemoteError::ProbeError)?;
797 let response_code = response_code[0];
798
799 if response_code == b'K' {
803 let Some(buffer) = buffer else {
804 let response = Self::recv_u64(reader)?;
805 tracing::trace!(" < K{:x}", response);
806 return Ok(RemoteResponse(response));
807 };
808 let mut output_count = 0;
809 for dest in buffer.iter_mut() {
810 let mut byte = [0u8; 1];
811
812 reader
814 .read_exact(&mut byte)
815 .map_err(RemoteError::ProbeError)?;
816 if byte[0] == BLACK_MAGIC_PROTOCOL_RESPONSE_END {
817 break;
818 }
819
820 output_count += 1;
823
824 if decode_hex {
825 *dest = Self::hex_val(byte[0])
826 .or(Err(RemoteError::ParameterError(byte[0] as _)))?;
827
828 reader
830 .read_exact(&mut byte)
831 .map_err(RemoteError::ProbeError)?;
832 if byte[0] == BLACK_MAGIC_PROTOCOL_RESPONSE_END {
833 break;
834 }
835
836 *dest = (*dest << 4)
837 | Self::hex_val(byte[0])
838 .or(Err(RemoteError::ParameterError(byte[0] as _)))?;
839 } else {
840 *dest = byte[0];
841 }
842 }
843 tracing::trace!(" < K{:x?}", &buffer[0..output_count as usize]);
844 Ok(RemoteResponse(output_count))
845 } else {
846 let response = Self::recv_u64(reader)?;
847 tracing::trace!(" < {}{:x}", char::from(response_code), response);
848 if response_code == b'E' {
849 Err(RemoteError::Error(response))
850 } else if response_code == b'P' {
851 Err(RemoteError::ParameterError(response))
852 } else {
853 Err(RemoteError::Unsupported(response))
854 }
855 }
856 }
857
858 fn get_speed(&mut self) -> Result<u32, DebugProbeError> {
859 let speed = self.command(RemoteCommand::SpeedKhz)?.0.try_into().unwrap();
860 Ok(speed)
861 }
862
863 fn drain_swd_accumulator(
864 &mut self,
865 output: &mut Vec<bool>,
866 accumulator: u32,
867 accumulator_length: usize,
868 ) -> Result<(), DebugProbeError> {
869 if self.swd_direction == SwdDirection::Output {
870 match self.command(RemoteCommand::SwdOut {
871 value: accumulator,
872 length: accumulator_length,
873 }) {
874 Ok(response) => tracing::debug!(
875 "Doing SWD out of {} bits: {:x} -- {}",
876 accumulator_length,
877 accumulator,
878 response.0
879 ),
880 Err(e) => tracing::error!(
881 "Error doing SWD OUT of {} bits ({:x}) -- {}",
882 accumulator_length,
883 accumulator,
884 e
885 ),
886 }
887 for bit in 0..accumulator_length {
888 output.push(accumulator & (1 << bit) != 0);
889 }
890 } else {
891 let result = self.command(RemoteCommand::SwdIn {
892 length: accumulator_length,
893 });
894 match &result {
895 Ok(response) => {
896 let response = response.0;
897 tracing::debug!(
898 "Doing SWD in of {} bits: {:x}",
899 accumulator_length,
900 response
901 );
902 for bit in 0..accumulator_length {
903 output.push(response & (1 << bit) != 0);
904 }
905 }
906 Err(e) => tracing::error!(
907 "Error doing SWD IN operation of {} bits: {}",
908 accumulator_length,
909 e
910 ),
911 }
912 }
913 Ok(())
914 }
915
916 fn perform_swdio_transfer<S>(&mut self, swdio: S) -> Result<Vec<bool>, DebugProbeError>
918 where
919 S: IntoIterator<Item = IoSequenceItem>,
920 {
921 let swdio_sequence = swdio.into_iter();
922 let mut output = vec![];
923
924 let mut accumulator = 0u32;
925 let mut accumulator_length = 0;
926
927 for swdio in swdio_sequence {
928 let dir: SwdDirection = swdio.into();
929 if dir != self.swd_direction
930 || accumulator_length >= core::mem::size_of_val(&accumulator) * 8
931 {
932 if self.swd_direction == SwdDirection::Input && dir == SwdDirection::Output {
936 accumulator_length -= 2;
937 }
938
939 self.drain_swd_accumulator(&mut output, accumulator, accumulator_length)?;
942
943 if self.swd_direction == SwdDirection::Input && dir == SwdDirection::Output {
945 output.push(false);
946 output.push(false);
947 }
948
949 accumulator = 0;
950 accumulator_length = 0;
951 }
952 self.swd_direction = dir;
953 accumulator |= if let IoSequenceItem::Output(true) = swdio {
954 1 << accumulator_length
955 } else {
956 0
957 };
958 accumulator_length += 1;
959 }
960
961 if accumulator_length > 0 {
962 self.drain_swd_accumulator(&mut output, accumulator, accumulator_length)?;
963 }
964
965 Ok(output)
966 }
967
968 fn drain_jtag_accumulator(
969 &mut self,
970 accumulator: u32,
971 mut accumulator_length: usize,
972 final_tms: bool,
973 capture: bool,
974 final_transaction: bool,
975 ) -> Result<(), DebugProbeError> {
976 let response = self.command(RemoteCommand::JtagTdi {
977 bits: accumulator,
978 length: accumulator_length,
979 tms: final_tms && final_transaction,
980 })?;
981
982 if capture {
983 if capture && final_transaction {
985 accumulator_length -= 1;
986 }
987 let value = response.0;
988 for bit in 0..accumulator_length {
989 self.in_bits.push(value & (1 << bit) != 0);
990 }
991 }
992 Ok(())
993 }
994
995 fn perform_jtag_transfer(
996 &mut self,
997 transaction: Vec<(bool, bool, bool)>,
998 final_tms: bool,
999 capture: bool,
1000 ) -> Result<(), DebugProbeError> {
1001 let mut accumulator = 0;
1002 let mut accumulator_length = 0;
1003 let bit_count = transaction.len();
1004
1005 for (index, (_, tdi, _)) in transaction.into_iter().enumerate() {
1006 accumulator |= if tdi { 1 << accumulator_length } else { 0 };
1007 accumulator_length += 1;
1008 if accumulator_length >= core::mem::size_of_val(&accumulator) * 8 {
1009 let is_final = index + 1 >= bit_count;
1010 self.drain_jtag_accumulator(
1011 accumulator,
1012 accumulator_length,
1013 final_tms,
1014 capture,
1015 is_final,
1016 )?;
1017 accumulator = 0;
1018 accumulator_length = 0;
1019 }
1020 }
1021
1022 if accumulator_length > 0 {
1023 self.drain_jtag_accumulator(accumulator, accumulator_length, final_tms, capture, true)?;
1024 }
1025 Ok(())
1026 }
1027}
1028
1029impl DebugProbe for BlackMagicProbe {
1030 fn get_name(&self) -> &str {
1031 "Black Magic probe"
1032 }
1033
1034 fn speed_khz(&self) -> u32 {
1035 self.speed_khz
1036 }
1037
1038 fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
1039 self.command(RemoteCommand::SetSpeedHz(speed_khz * 1000))?;
1040 self.speed_khz = self.get_speed()?;
1041 Ok(self.speed_khz)
1042 }
1043
1044 fn attach(&mut self) -> Result<(), DebugProbeError> {
1045 tracing::debug!("Attaching with protocol '{:?}'", self.protocol);
1046
1047 if let ProtocolVersion::V2 | ProtocolVersion::V3 | ProtocolVersion::V4 =
1049 self.remote_protocol
1050 {
1051 self.command(RemoteCommand::TargetClockOutput { enable: true })
1052 .ok();
1053 }
1054
1055 match self.protocol {
1056 Some(WireProtocol::Jtag) => {
1057 self.select_target(0)?;
1058
1059 if let ProtocolVersion::V1
1060 | ProtocolVersion::V2
1061 | ProtocolVersion::V3
1062 | ProtocolVersion::V4 = self.remote_protocol
1063 {
1064 let sc = &self.jtag_state.chain_params;
1065 self.command(RemoteCommand::JtagAddDevice {
1066 index: 0,
1067 dr_prescan: sc.drpre.try_into().unwrap(),
1068 dr_postscan: sc.drpost.try_into().unwrap(),
1069 ir_len: sc.irlen.try_into().unwrap(),
1070 ir_prescan: sc.irpre.try_into().unwrap(),
1071 ir_postscan: sc.irpost.try_into().unwrap(),
1072 current_ir: u32::MAX,
1073 })?;
1074 }
1075 Ok(())
1076 }
1077 Some(WireProtocol::Swd) => Ok(()),
1078 _ => Err(DebugProbeError::InterfaceNotAvailable {
1079 interface_name: "no protocol specified",
1080 }),
1081 }
1082 }
1083
1084 fn detach(&mut self) -> Result<(), crate::Error> {
1085 Ok(())
1086 }
1087
1088 fn target_reset(&mut self) -> Result<(), DebugProbeError> {
1089 Err(DebugProbeError::NotImplemented {
1092 function_name: "target_reset",
1093 })
1094 }
1095
1096 fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
1097 self.command(RemoteCommand::TargetReset(true))?;
1098 Ok(())
1099 }
1100
1101 fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
1102 self.command(RemoteCommand::TargetReset(false))?;
1103 Ok(())
1104 }
1105
1106 fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
1107 self.protocol = Some(protocol);
1108
1109 tracing::debug!("Switching to protocol {}", protocol);
1110 match protocol {
1111 WireProtocol::Jtag => {
1112 self.command(RemoteCommand::JtagInit)?;
1113 self.command(RemoteCommand::JtagReset)?;
1114 }
1115 WireProtocol::Swd => {
1116 self.command(RemoteCommand::SwdInit)?;
1117 }
1118 }
1119 Ok(())
1120 }
1121
1122 fn active_protocol(&self) -> Option<WireProtocol> {
1123 self.protocol
1124 }
1125
1126 fn try_as_jtag_probe(&mut self) -> Option<&mut dyn JtagAccess> {
1127 Some(self)
1128 }
1129
1130 fn try_get_riscv_interface_builder<'probe>(
1131 &'probe mut self,
1132 ) -> Result<Box<dyn RiscvInterfaceBuilder<'probe> + 'probe>, RiscvError> {
1133 Ok(Box::new(JtagDtmBuilder::new(self)))
1134 }
1135
1136 fn has_riscv_interface(&self) -> bool {
1137 true
1138 }
1139
1140 fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
1141 self
1142 }
1143
1144 fn try_get_arm_debug_interface<'probe>(
1146 mut self: Box<Self>,
1147 sequence: Arc<dyn ArmDebugSequence>,
1148 ) -> Result<Box<dyn ArmDebugInterface + 'probe>, (Box<dyn DebugProbe>, ArmError)> {
1149 let has_adiv5 = match self.remote_protocol {
1150 ProtocolVersion::V0 => false,
1151 ProtocolVersion::V0P
1152 | ProtocolVersion::V1
1153 | ProtocolVersion::V2
1154 | ProtocolVersion::V3 => true,
1155 ProtocolVersion::V4 => {
1156 if let Ok(accelerators) = self.command(RemoteCommand::GetAccelerators) {
1157 accelerators.0 & 1 != 0
1158 } else {
1159 false
1160 }
1161 }
1162 };
1163
1164 if has_adiv5 {
1165 match BlackMagicProbeArmDebug::new(self, sequence) {
1166 Ok(interface) => Ok(Box::new(interface)),
1167 Err((probe, err)) => Err((probe.into_probe(), err)),
1168 }
1169 } else {
1170 Ok(ArmCommunicationInterface::create(self, sequence, true)) }
1172 }
1173
1174 fn has_arm_interface(&self) -> bool {
1175 true
1176 }
1177
1178 fn try_get_xtensa_interface<'probe>(
1179 &'probe mut self,
1180 state: &'probe mut XtensaDebugInterfaceState,
1181 ) -> Result<XtensaCommunicationInterface<'probe>, XtensaError> {
1182 Ok(XtensaCommunicationInterface::new(self, state))
1183 }
1184
1185 fn has_xtensa_interface(&self) -> bool {
1186 true
1187 }
1188}
1189
1190impl AutoImplementJtagAccess for BlackMagicProbe {}
1191impl DapProbe for BlackMagicProbe {}
1192
1193impl RawSwdIo for BlackMagicProbe {
1194 fn swd_io<S>(&mut self, swdio: S) -> Result<Vec<bool>, DebugProbeError>
1195 where
1196 S: IntoIterator<Item = IoSequenceItem>,
1197 {
1198 self.probe_statistics.report_io();
1199 self.perform_swdio_transfer(swdio)
1200 }
1201
1202 fn swj_pins(
1203 &mut self,
1204 pin_out: u32,
1205 pin_select: u32,
1206 _pin_wait: u32,
1207 ) -> Result<u32, DebugProbeError> {
1208 if pin_select & 0x2f != 0 {
1211 return Err(DebugProbeError::CommandNotSupportedByProbe {
1212 command_name: "swj_pins",
1213 });
1214 }
1215 if pin_select & 0x80 != 0 {
1217 self.command(RemoteCommand::TargetReset(pin_out & 0x80 == 0))?;
1218 }
1219 Ok(pin_out)
1220 }
1221
1222 fn swd_settings(&self) -> &SwdSettings {
1223 &self.swd_settings
1224 }
1225
1226 fn probe_statistics(&mut self) -> &mut ProbeStatistics {
1227 &mut self.probe_statistics
1228 }
1229}
1230
1231impl RawJtagIo for BlackMagicProbe {
1232 fn shift_bit(
1233 &mut self,
1234 tms: bool,
1235 tdi: bool,
1236 capture_tdo: bool,
1237 ) -> Result<(), DebugProbeError> {
1238 self.jtag_state.state.update(tms);
1239 let response = self.command(RemoteCommand::JtagNext { tms, tdi }).unwrap();
1240 if capture_tdo {
1241 self.in_bits.push(response.0 != 0);
1242 }
1243 Ok(())
1244 }
1245
1246 fn shift_bits(
1247 &mut self,
1248 tms: impl IntoIterator<Item = bool>,
1249 tdi: impl IntoIterator<Item = bool>,
1250 cap: impl IntoIterator<Item = bool>,
1251 ) -> Result<(), DebugProbeError> {
1252 let mut transaction = vec![];
1253 let mut last_tms = false;
1254 let mut last_cap = false;
1255
1256 let mut special_transaction = false;
1257 let mut tms_true_count = 0;
1258 let mut cap_count = 0;
1259 for (tms, (tdi, cap)) in tms.into_iter().zip(tdi.into_iter().zip(cap)) {
1260 if tms {
1261 tms_true_count += 1;
1262 }
1263 if cap {
1264 cap_count += 1;
1265 }
1266 last_tms = tms;
1267 last_cap = cap;
1268 transaction.push((tms, tdi, cap));
1269 }
1270
1271 if (cap_count != 0 && (cap_count + 1 != transaction.len())) || last_cap {
1274 special_transaction = true;
1275 }
1276
1277 if tms_true_count > 1 || (tms_true_count == 1 && !last_tms) {
1279 special_transaction = true;
1280 }
1281
1282 if special_transaction {
1283 for (tms, tdi, cap) in transaction {
1284 self.shift_bit(tms, tdi, cap)?;
1285 }
1286 } else {
1287 self.jtag_state.state.update(tms_true_count > 0);
1288 self.perform_jtag_transfer(transaction, tms_true_count > 0, cap_count > 0)?;
1289 }
1290
1291 Ok(())
1292 }
1293
1294 fn read_captured_bits(&mut self) -> Result<BitVec, DebugProbeError> {
1295 tracing::trace!("reading captured bits");
1296 Ok(std::mem::take(&mut self.in_bits))
1297 }
1298
1299 fn state_mut(&mut self) -> &mut JtagDriverState {
1300 &mut self.jtag_state
1301 }
1302
1303 fn state(&self) -> &JtagDriverState {
1304 &self.jtag_state
1305 }
1306}
1307
1308fn black_magic_debug_port_info(
1312 port_type: SerialPortType,
1313 port_name: &str,
1314) -> Option<DebugProbeInfo> {
1315 if cfg!(target_os = "macos") && !port_name.contains("/cu.") {
1318 tracing::trace!(
1319 "{}: port name doesn't contain `/cu.` -- skipping",
1320 port_name
1321 );
1322 return None;
1323 }
1324
1325 let (vendor_id, product_id, serial_number, mut interface, identifier) = match port_type {
1326 SerialPortType::UsbPort(info) => (
1327 info.vid,
1328 info.pid,
1329 info.serial_number.map(|s| s.to_string()),
1330 info.interface,
1331 info.product
1332 .unwrap_or_else(|| "Black Magic Probe".to_string()),
1333 ),
1334 _ => {
1335 tracing::trace!(
1336 "{}: serial port {:?} is not USB -- skipping",
1337 port_name,
1338 port_type,
1339 );
1340 return None;
1341 }
1342 };
1343
1344 if vendor_id != BLACK_MAGIC_PROBE_VID {
1345 tracing::trace!(
1346 "{}: vid is {:04x}, not {:04x} -- skipping",
1347 port_name,
1348 vendor_id,
1349 BLACK_MAGIC_PROBE_VID
1350 );
1351 return None;
1352 }
1353
1354 if product_id != BLACK_MAGIC_PROBE_PID {
1355 tracing::trace!(
1356 "{}: pid is {:04x}, not {:04x} -- skipping",
1357 port_name,
1358 product_id,
1359 BLACK_MAGIC_PROBE_PID
1360 );
1361 return None;
1362 }
1363
1364 if cfg!(target_os = "macos") && interface.is_none() {
1368 tracing::warn!(
1369 "{}: interface number is `None` -- applying interface number workaround",
1370 port_name
1371 );
1372 interface = port_name.as_bytes().last().map(|v| *v - b'0');
1373 }
1374
1375 if interface != Some(0) && interface != Some(1) {
1378 tracing::trace!(
1379 "{}: interface is {:?}, not Some(0) or Some(1) -- skipping",
1380 port_name,
1381 interface
1382 );
1383 return None;
1384 }
1385
1386 tracing::debug!(
1387 "{}: returning port {}:{}:{:?}",
1388 port_name,
1389 vendor_id,
1390 product_id,
1391 serial_number
1392 );
1393 Some(DebugProbeInfo {
1394 identifier,
1395 vendor_id,
1396 product_id,
1397 serial_number,
1398 probe_factory: &BlackMagicProbeFactory,
1399 interface,
1400 is_hid_interface: false,
1401 })
1402}
1403
1404impl ProbeFactory for BlackMagicProbeFactory {
1405 fn open(
1406 &self,
1407 selector: &super::DebugProbeSelector,
1408 ) -> Result<Box<dyn DebugProbe>, DebugProbeError> {
1409 if selector.vendor_id != BLACK_MAGIC_PROBE_VID
1411 || selector.product_id != BLACK_MAGIC_PROBE_PID
1412 {
1413 tracing::trace!(
1414 "{:04x}:{:04x} doesn't match BMP VID/PID {:04x}:{:04x}",
1415 selector.vendor_id,
1416 selector.product_id,
1417 BLACK_MAGIC_PROBE_VID,
1418 BLACK_MAGIC_PROBE_PID
1419 );
1420 return Err(DebugProbeError::ProbeCouldNotBeCreated(
1421 ProbeCreationError::NotFound,
1422 ));
1423 }
1424
1425 if let Some(serial_number) = &selector.serial_number
1428 && let Ok(connection) = std::net::TcpStream::connect(serial_number)
1429 {
1430 let reader = connection;
1431 let writer = reader
1432 .try_clone()
1433 .map_err(|e| DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::Usb(e)))?;
1434 return BlackMagicProbe::new(Box::new(reader), Box::new(writer))
1435 .map(|p| Box::new(p) as Box<dyn DebugProbe>);
1436 }
1437
1438 let Ok(ports) = available_ports() else {
1440 tracing::trace!("unable to get available serial ports");
1441 return Err(DebugProbeError::ProbeCouldNotBeCreated(
1442 ProbeCreationError::CouldNotOpen,
1443 ));
1444 };
1445
1446 for port_description in ports {
1447 let Some(info) = black_magic_debug_port_info(
1448 port_description.port_type,
1449 &port_description.port_name,
1450 ) else {
1451 continue;
1452 };
1453
1454 if selector.serial_number.is_some() && selector.serial_number != info.serial_number {
1455 tracing::trace!(
1456 "serial number {:?} doesn't match requested number {:?}",
1457 info.serial_number,
1458 selector.serial_number
1459 );
1460 continue;
1461 }
1462
1463 let mut port = serialport::new(port_description.port_name, 115200)
1466 .timeout(std::time::Duration::from_secs(1))
1467 .open()
1468 .map_err(|_| {
1469 DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
1470 })?;
1471
1472 port.write_data_terminal_ready(true).map_err(|_| {
1474 DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
1475 })?;
1476 std::thread::sleep(Duration::from_millis(250));
1478 let reader = port;
1479 let writer = reader.try_clone().map_err(|_| {
1480 DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
1481 })?;
1482 return BlackMagicProbe::new(Box::new(reader), Box::new(writer))
1483 .map(|p| Box::new(p) as Box<dyn DebugProbe>);
1484 }
1485
1486 tracing::trace!("unable to find port {:?}", selector);
1487 Err(DebugProbeError::ProbeCouldNotBeCreated(
1488 ProbeCreationError::NotFound,
1489 ))
1490 }
1491
1492 fn list_probes(&self) -> Vec<super::DebugProbeInfo> {
1493 let mut probes = vec![];
1494 let ports = match available_ports() {
1495 Ok(ports) => ports,
1496 Err(e) => {
1497 tracing::trace!("Unable to enumerate serial ports: {}", e);
1498 return probes;
1499 }
1500 };
1501
1502 for port in ports {
1503 let Some(info) = black_magic_debug_port_info(port.port_type, &port.port_name) else {
1504 continue;
1505 };
1506 probes.push(info);
1507 }
1508 probes
1509 }
1510
1511 fn list_probes_filtered(&self, selector: Option<&DebugProbeSelector>) -> Vec<DebugProbeInfo> {
1512 let Some(selector) = selector else {
1514 return self.list_probes();
1515 };
1516
1517 let vid_pid = (selector.vendor_id, selector.product_id);
1518
1519 let Some(serial) = selector.serial_number.as_deref() else {
1520 if vid_pid != BLACK_MAGIC_PROBE {
1521 return vec![];
1523 }
1524 return self.list_probes();
1526 };
1527
1528 let Ok(ip_port) = serial.parse::<SocketAddr>() else {
1530 if vid_pid != BLACK_MAGIC_PROBE {
1531 return vec![];
1533 }
1534 return self
1536 .list_probes()
1537 .into_iter()
1538 .filter(|probe| selector.matches_probe(probe))
1539 .collect();
1540 };
1541
1542 if vid_pid != BLACK_MAGIC_PROBE && vid_pid != (0, 0) {
1543 return vec![];
1545 }
1546
1547 vec![DebugProbeInfo {
1549 identifier: format!("{}:{}", ip_port.ip(), ip_port.port()),
1550 vendor_id: BLACK_MAGIC_PROBE_VID,
1551 product_id: BLACK_MAGIC_PROBE_PID,
1552 serial_number: Some(ip_port.to_string()),
1553 probe_factory: &BlackMagicProbeFactory,
1554 interface: None,
1555 is_hid_interface: false,
1556 }]
1557 }
1558}