probe_rs/probe/stlink/
mod.rs

1//! ST-Link probe implementation.
2
3mod constants;
4mod tools;
5mod usb_interface;
6
7use crate::{
8    MemoryInterface,
9    architecture::arm::{
10        ArmError, DapAccess, FullyQualifiedApAddress, Pins, SwoAccess, SwoConfig, SwoMode,
11        ap::{
12            AccessPortType,
13            memory_ap::{MemoryAp, MemoryApType},
14            v1::valid_access_ports,
15        },
16        communication_interface::{ArmDebugInterface, DapProbe, SwdSequence},
17        dp::{DpAddress, DpRegisterAddress},
18        memory::ArmMemoryInterface,
19        sequences::ArmDebugSequence,
20        valid_32bit_arm_address,
21    },
22    probe::{
23        DebugProbe, DebugProbeError, DebugProbeInfo, DebugProbeSelector, Probe, ProbeError,
24        ProbeFactory, WireProtocol,
25    },
26};
27
28use scroll::{BE, LE, Pread, Pwrite};
29
30use std::collections::BTreeSet;
31use std::thread;
32use std::{cmp::Ordering, sync::Arc, time::Duration};
33
34use constants::{JTagFrequencyToDivider, Mode, Status, SwdFrequencyToDelayCount, commands};
35use usb_interface::{StLinkUsb, StLinkUsbDevice, TIMEOUT};
36
37/// Maximum length of 32 bit reads in bytes.
38///
39/// Length has been determined by experimenting with
40/// a ST-Link v2.
41const STLINK_MAX_READ_LEN: usize = 6144;
42
43/// Maximum length of 32 bit writes in bytes.
44/// The length is limited to the largest 16-bit value which
45/// is also a multiple of 4.
46const STLINK_MAX_WRITE_LEN: usize = 0xFFFC;
47
48const DP_PORT: u16 = 0xFFFF;
49
50/// A factory for creating [`StLink`] probes.
51#[derive(Debug)]
52pub struct StLinkFactory;
53
54impl std::fmt::Display for StLinkFactory {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        f.write_str("ST-LINK")
57    }
58}
59
60impl ProbeFactory for StLinkFactory {
61    fn open(&self, selector: &DebugProbeSelector) -> Result<Box<dyn DebugProbe>, DebugProbeError> {
62        tracing::debug!("Opening ST-Link: {selector:?}");
63        let device = StLinkUsbDevice::new_from_selector(selector)?;
64        let mut stlink = StLink {
65            name: format!("ST-Link {}", &device.info.version_name),
66            device,
67            hw_version: 0,
68            jtag_version: 0,
69            protocol: WireProtocol::Swd,
70            swd_speed_khz: 1_800,
71            jtag_speed_khz: 1_120,
72            swo_enabled: false,
73
74            opened_aps: vec![],
75        };
76
77        stlink.init()?;
78
79        Ok(Box::new(stlink))
80    }
81
82    fn list_probes(&self) -> Vec<DebugProbeInfo> {
83        tools::list_stlink_devices()
84    }
85}
86
87/// An ST-Link debugger and programmer.
88#[derive(Debug)]
89pub struct StLink<D: StLinkUsb> {
90    device: D,
91    name: String,
92    hw_version: u8,
93    jtag_version: u8,
94    protocol: WireProtocol,
95    swd_speed_khz: u32,
96    jtag_speed_khz: u32,
97    swo_enabled: bool,
98
99    /// List of opened APs
100    opened_aps: Vec<u8>,
101}
102
103impl DebugProbe for StLink<StLinkUsbDevice> {
104    fn get_name(&self) -> &str {
105        &self.name
106    }
107
108    fn speed_khz(&self) -> u32 {
109        match self.protocol {
110            WireProtocol::Swd => self.swd_speed_khz,
111            WireProtocol::Jtag => self.jtag_speed_khz,
112        }
113    }
114
115    fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
116        match self.hw_version.cmp(&3) {
117            Ordering::Less => match self.protocol {
118                WireProtocol::Swd => {
119                    let actual_speed = SwdFrequencyToDelayCount::find_setting(speed_khz);
120
121                    if let Some(actual_speed) = actual_speed {
122                        self.set_swd_frequency(actual_speed)?;
123
124                        self.swd_speed_khz = actual_speed.to_khz();
125
126                        Ok(actual_speed.to_khz())
127                    } else {
128                        Err(DebugProbeError::UnsupportedSpeed(speed_khz))
129                    }
130                }
131                WireProtocol::Jtag => {
132                    let actual_speed = JTagFrequencyToDivider::find_setting(speed_khz);
133
134                    if let Some(actual_speed) = actual_speed {
135                        self.set_jtag_frequency(actual_speed)?;
136
137                        self.jtag_speed_khz = actual_speed.to_khz();
138
139                        Ok(actual_speed.to_khz())
140                    } else {
141                        Err(DebugProbeError::UnsupportedSpeed(speed_khz))
142                    }
143                }
144            },
145            Ordering::Equal | Ordering::Greater => {
146                let (available, _) = self.get_communication_frequencies(self.protocol)?;
147
148                let actual_speed_khz = available
149                    .into_iter()
150                    .filter(|speed| *speed <= speed_khz)
151                    .max()
152                    .ok_or(DebugProbeError::UnsupportedSpeed(speed_khz))?;
153
154                self.set_communication_frequency(self.protocol, actual_speed_khz)?;
155
156                match self.protocol {
157                    WireProtocol::Swd => self.swd_speed_khz = actual_speed_khz,
158                    WireProtocol::Jtag => self.jtag_speed_khz = actual_speed_khz,
159                }
160
161                Ok(actual_speed_khz)
162            }
163        }
164    }
165
166    #[tracing::instrument(skip(self))]
167    fn attach(&mut self) -> Result<(), DebugProbeError> {
168        self.enter_idle()?;
169
170        let param = match self.protocol {
171            WireProtocol::Jtag => {
172                tracing::debug!("Switching protocol to JTAG");
173                commands::JTAG_ENTER_JTAG_NO_CORE_RESET
174            }
175            WireProtocol::Swd => {
176                tracing::debug!("Switching protocol to SWD");
177                commands::JTAG_ENTER_SWD
178            }
179        };
180
181        // Check and report the target voltage.
182        let target_voltage = self
183            .get_target_voltage()?
184            .expect("The ST-Link returned None when it should only be able to return Some(f32) or an error. Please report this bug!");
185        if target_voltage < crate::probe::LOW_TARGET_VOLTAGE_WARNING_THRESHOLD {
186            tracing::warn!(
187                "Target voltage (VAPP) is {:2.2} V. Is your target device powered?",
188                target_voltage
189            );
190        } else {
191            tracing::info!("Target voltage (VAPP): {:2.2} V", target_voltage);
192        }
193
194        let mut buf = [0; 2];
195        self.send_jtag_command(
196            &[commands::JTAG_COMMAND, commands::JTAG_ENTER2, param, 0],
197            &[],
198            &mut buf,
199            TIMEOUT,
200        )?;
201
202        tracing::debug!("Successfully initialized {}.", self.protocol);
203
204        // If the speed is not manually set, the probe will
205        // use whatever speed has been configured before.
206        //
207        // To ensure the default speed is used if not changed,
208        // we set the speed again here.
209        match self.protocol {
210            WireProtocol::Jtag => {
211                self.set_speed(self.jtag_speed_khz)?;
212            }
213            WireProtocol::Swd => {
214                self.set_speed(self.swd_speed_khz)?;
215            }
216        }
217
218        Ok(())
219    }
220
221    fn detach(&mut self) -> Result<(), crate::Error> {
222        tracing::debug!("Detaching from STLink.");
223        if self.swo_enabled {
224            self.disable_swo().map_err(crate::Error::Arm)?;
225        }
226        self.enter_idle()
227            .map_err(|e| DebugProbeError::from(e).into())
228    }
229
230    fn target_reset(&mut self) -> Result<(), DebugProbeError> {
231        let mut buf = [0; 2];
232        self.send_jtag_command(
233            &[
234                commands::JTAG_COMMAND,
235                commands::JTAG_DRIVE_NRST,
236                commands::JTAG_DRIVE_NRST_PULSE,
237            ],
238            &[],
239            &mut buf,
240            TIMEOUT,
241        )?;
242
243        Ok(())
244    }
245
246    fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
247        let mut buf = [0; 2];
248        self.send_jtag_command(
249            &[
250                commands::JTAG_COMMAND,
251                commands::JTAG_DRIVE_NRST,
252                commands::JTAG_DRIVE_NRST_LOW,
253            ],
254            &[],
255            &mut buf,
256            TIMEOUT,
257        )?;
258
259        Ok(())
260    }
261
262    fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
263        let mut buf = [0; 2];
264        self.send_jtag_command(
265            &[
266                commands::JTAG_COMMAND,
267                commands::JTAG_DRIVE_NRST,
268                commands::JTAG_DRIVE_NRST_HIGH,
269            ],
270            &[],
271            &mut buf,
272            TIMEOUT,
273        )?;
274
275        Ok(())
276    }
277
278    fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
279        match protocol {
280            WireProtocol::Jtag => self.protocol = WireProtocol::Jtag,
281            WireProtocol::Swd => self.protocol = WireProtocol::Swd,
282        }
283        Ok(())
284    }
285
286    fn active_protocol(&self) -> Option<WireProtocol> {
287        Some(self.protocol)
288    }
289
290    fn get_swo_interface(&self) -> Option<&dyn SwoAccess> {
291        Some(self as _)
292    }
293
294    fn get_swo_interface_mut(&mut self) -> Option<&mut dyn SwoAccess> {
295        Some(self as _)
296    }
297
298    fn has_arm_interface(&self) -> bool {
299        true
300    }
301
302    fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
303        self
304    }
305
306    fn try_get_arm_debug_interface<'probe>(
307        self: Box<Self>,
308        _sequence: Arc<dyn ArmDebugSequence>,
309    ) -> Result<Box<dyn ArmDebugInterface + 'probe>, (Box<dyn DebugProbe>, ArmError)> {
310        let interface = StlinkArmDebug::new(self);
311
312        Ok(Box::new(interface))
313    }
314
315    fn get_target_voltage(&mut self) -> Result<Option<f32>, DebugProbeError> {
316        let mut buf = [0; 8];
317        self.device
318            .write(&[commands::GET_TARGET_VOLTAGE], &[], &mut buf, TIMEOUT)
319            .and_then(|_| {
320                // The next two unwraps are safe!
321                let a0 = buf[0..4].pread_with::<u32>(0, LE).unwrap();
322                let a1 = buf[4..8].pread_with::<u32>(0, LE).unwrap();
323                if a0 != 0 {
324                    Ok(Some(2. * (a1 as f32) * 1.2 / (a0 as f32)))
325                } else {
326                    // Should never happen
327                    Err(StlinkError::VoltageDivisionByZero)
328                }
329            })
330            .map_err(|e| e.into())
331    }
332}
333
334impl<D: StLinkUsb> Drop for StLink<D> {
335    fn drop(&mut self) {
336        // We ignore the error cases as we can't do much about it anyways.
337        if self.swo_enabled {
338            let _ = self.disable_swo();
339        }
340        let _ = self.enter_idle();
341    }
342}
343
344impl StLink<StLinkUsbDevice> {
345    fn swj_pins(
346        &mut self,
347        pin_out: u32,
348        pin_select: u32,
349        pin_wait: u32,
350    ) -> Result<u32, DebugProbeError> {
351        let mut nreset = Pins(0);
352        nreset.set_nreset(true);
353        let nreset_mask = nreset.0 as u32;
354
355        // If only the reset pin is selected we perform the reset.
356        // If something else is selected return an error as this is not supported on ST-Links.
357        if pin_select == nreset_mask {
358            if Pins(pin_out as u8).nreset() {
359                self.target_reset_deassert()?;
360            } else {
361                self.target_reset_assert()?;
362            }
363
364            // Normally this would be the timeout we pass to the probe to settle the pins.
365            // The ST-Link is not capable of this, so we just wait for this time on the host
366            // and assume it has settled until then.
367            thread::sleep(Duration::from_micros(pin_wait as u64));
368
369            // We signal that we cannot read the pin state.
370            Ok(0xFFFF_FFFF)
371        } else {
372            // This is not supported for ST-Links, unfortunately.
373            Err(DebugProbeError::CommandNotSupportedByProbe {
374                command_name: "swj_pins",
375            })
376        }
377    }
378}
379
380impl<D: StLinkUsb> StLink<D> {
381    /// Maximum number of bytes to send or receive for 32- and 16- bit transfers.
382    ///
383    /// 8-bit transfers have a maximum size of the maximum USB packet size (64 bytes for full speed).
384    const _MAXIMUM_TRANSFER_SIZE: u32 = 1024;
385
386    /// Minimum required STLink firmware version.
387    const MIN_JTAG_VERSION: u8 = 26;
388
389    /// Minimum required STLink V3 firmware version.
390    ///
391    /// Version 2 of the firmware (V3J2M1) has problems switching communication protocols.
392    const MIN_JTAG_VERSION_V3: u8 = 3;
393
394    /// Firmware version that adds multiple AP support.
395    const MIN_JTAG_VERSION_MULTI_AP: u8 = 28;
396
397    /// Firmware version which supports banked DP registers.
398    ///
399    /// This only applies to HW version 2, for version 3 we only support
400    /// FW versions where this is supported.
401    const MIN_JTAG_VERSION_DP_BANK_SEL: u8 = 32;
402
403    /// Get the current mode of the ST-Link
404    fn get_current_mode(&mut self) -> Result<Mode, StlinkError> {
405        tracing::trace!("Getting current mode of device...");
406        let mut buf = [0; 2];
407        self.device
408            .write(&[commands::GET_CURRENT_MODE], &[], &mut buf, TIMEOUT)?;
409
410        let mode = match buf[0] {
411            0 => Mode::Dfu,
412            1 => Mode::MassStorage,
413            2 => Mode::Jtag,
414            3 => Mode::Swim,
415            _ => return Err(StlinkError::UnknownMode),
416        };
417
418        tracing::debug!("Current device mode: {:?}", mode);
419
420        Ok(mode)
421    }
422
423    /// Check if selecting different banks in the DP is supported.
424    ///
425    /// If this is not supported, some DP registers cannot be accessed.
426    fn supports_dp_bank_selection(&self) -> bool {
427        (self.hw_version == 2 && self.jtag_version >= Self::MIN_JTAG_VERSION_DP_BANK_SEL)
428            || self.hw_version >= 3
429    }
430
431    /// Commands the ST-Link to enter idle mode.
432    /// Internal helper.
433    fn enter_idle(&mut self) -> Result<(), StlinkError> {
434        let mode = self.get_current_mode()?;
435
436        match mode {
437            Mode::Jtag => self.device.write(
438                &[commands::JTAG_COMMAND, commands::JTAG_EXIT],
439                &[],
440                &mut [],
441                TIMEOUT,
442            ),
443            Mode::Dfu => self.device.write(
444                &[commands::DFU_COMMAND, commands::DFU_EXIT],
445                &[],
446                &mut [],
447                TIMEOUT,
448            ),
449            Mode::Swim => self.device.write(
450                &[commands::SWIM_COMMAND, commands::SWIM_EXIT],
451                &[],
452                &mut [],
453                TIMEOUT,
454            ),
455            _ => Ok(()),
456        }
457    }
458
459    /// Reads the ST-Link's version.
460    /// Returns a tuple (hardware version, firmware version).
461    /// This method stores the version data on the struct to make later use of it.
462    fn get_version(&mut self) -> Result<(u8, u8), StlinkError> {
463        const HW_VERSION_SHIFT: u8 = 12;
464        const HW_VERSION_MASK: u8 = 0x0F;
465        const JTAG_VERSION_SHIFT: u8 = 6;
466        const JTAG_VERSION_MASK: u8 = 0x3F;
467        // GET_VERSION response structure:
468        //   Byte 0-1:
469        //     [15:12] Major/HW version
470        //     [11:6]  JTAG/SWD version
471        //     [5:0]   SWIM or MSC version
472        //   Byte 2-3: ST_VID
473        //   Byte 4-5: STLINK_PID
474        let mut buf = [0; 6];
475        self.device
476            .write(&[commands::GET_VERSION], &[], &mut buf, TIMEOUT)
477            .map(|_| {
478                let version: u16 = buf[0..2].pread_with(0, BE).unwrap();
479                self.hw_version = (version >> HW_VERSION_SHIFT) as u8 & HW_VERSION_MASK;
480                self.jtag_version = (version >> JTAG_VERSION_SHIFT) as u8 & JTAG_VERSION_MASK;
481            })?;
482
483        // For the STLinkV3 we must use the extended get version command.
484        if self.hw_version >= 3 {
485            // GET_VERSION_EXT response structure (byte offsets)
486            //  0: HW version
487            //  1: SWIM version
488            //  2: JTAG/SWD version
489            //  3: MSC/VCP version
490            //  4: Bridge version
491            //  5: Power version
492            //  6-7: reserved
493            //  8-9: ST_VID
494            //  10-11: STLINK_PID
495            let mut buf = [0; 12];
496            self.device
497                .write(&[commands::GET_VERSION_EXT], &[], &mut buf, TIMEOUT)
498                .map(|_| {
499                    let version: u8 = buf[2..3].pread_with(0, LE).unwrap();
500                    self.jtag_version = version;
501                })?;
502        }
503
504        // Make sure everything is okay with the firmware we use.
505        if self.jtag_version == 0 {
506            Err(StlinkError::JTAGNotSupportedOnProbe)
507        } else if self.hw_version < 3 && self.jtag_version < Self::MIN_JTAG_VERSION {
508            Err(StlinkError::ProbeFirmwareOutdated(Self::MIN_JTAG_VERSION))
509        } else if self.hw_version == 3 && self.jtag_version < Self::MIN_JTAG_VERSION_V3 {
510            Err(StlinkError::ProbeFirmwareOutdated(
511                Self::MIN_JTAG_VERSION_V3,
512            ))
513        } else {
514            Ok((self.hw_version, self.jtag_version))
515        }
516    }
517
518    /// Opens the ST-Link USB device and tries to identify the ST-Links version and its target voltage.
519    /// Internal helper.
520    fn init(&mut self) -> Result<(), StlinkError> {
521        tracing::debug!("Initializing STLink...");
522
523        if let Err(e) = self.enter_idle() {
524            match e {
525                StlinkError::Usb(_) => {
526                    // Reset the device, and try to enter idle mode again
527                    self.device.reset()?;
528
529                    self.enter_idle()?;
530                }
531                // Other error occurred, return it
532                _ => return Err(e),
533            }
534        }
535
536        let version = self.get_version()?;
537        tracing::debug!("STLink version: {:?}", version);
538
539        if self.hw_version >= 3 {
540            let (_, current) = self.get_communication_frequencies(WireProtocol::Swd)?;
541            self.swd_speed_khz = current;
542
543            let (_, current) = self.get_communication_frequencies(WireProtocol::Jtag)?;
544            self.jtag_speed_khz = current;
545        }
546
547        Ok(())
548    }
549
550    /// sets the SWD frequency.
551    pub fn set_swd_frequency(
552        &mut self,
553        frequency: SwdFrequencyToDelayCount,
554    ) -> Result<(), DebugProbeError> {
555        let mut buf = [0; 2];
556        self.send_jtag_command(
557            &[
558                commands::JTAG_COMMAND,
559                commands::SWD_SET_FREQ,
560                frequency as u8,
561            ],
562            &[],
563            &mut buf,
564            TIMEOUT,
565        )?;
566
567        Ok(())
568    }
569
570    /// Sets the JTAG frequency.
571    pub fn set_jtag_frequency(
572        &mut self,
573        frequency: JTagFrequencyToDivider,
574    ) -> Result<(), DebugProbeError> {
575        let mut buf = [0; 2];
576        self.send_jtag_command(
577            &[
578                commands::JTAG_COMMAND,
579                commands::JTAG_SET_FREQ,
580                frequency as u8,
581            ],
582            &[],
583            &mut buf,
584            TIMEOUT,
585        )?;
586
587        Ok(())
588    }
589
590    /// Sets the communication frequency (V3 only)
591    fn set_communication_frequency(
592        &mut self,
593        protocol: WireProtocol,
594        frequency_khz: u32,
595    ) -> Result<(), DebugProbeError> {
596        if self.hw_version < 3 {
597            return Err(DebugProbeError::CommandNotSupportedByProbe {
598                command_name: "set_communication_frequency",
599            });
600        }
601
602        let cmd_proto = match protocol {
603            WireProtocol::Swd => 0,
604            WireProtocol::Jtag => 1,
605        };
606
607        let mut command = vec![commands::JTAG_COMMAND, commands::SET_COM_FREQ, cmd_proto, 0];
608        command.extend_from_slice(&frequency_khz.to_le_bytes());
609
610        let mut buf = [0; 8];
611        self.send_jtag_command(&command, &[], &mut buf, TIMEOUT)?;
612
613        Ok(())
614    }
615
616    /// Returns the current and available communication frequencies (V3 only)
617    fn get_communication_frequencies(
618        &mut self,
619        protocol: WireProtocol,
620    ) -> Result<(Vec<u32>, u32), StlinkError> {
621        let cmd_proto = match protocol {
622            WireProtocol::Swd => 0,
623            WireProtocol::Jtag => 1,
624        };
625
626        let mut buf = [0; 52];
627        self.send_jtag_command(
628            &[commands::JTAG_COMMAND, commands::GET_COM_FREQ, cmd_proto],
629            &[],
630            &mut buf,
631            TIMEOUT,
632        )?;
633
634        let mut values = buf
635            .chunks(4)
636            .map(|chunk| chunk.pread_with::<u32>(0, LE).unwrap())
637            .collect::<Vec<u32>>();
638
639        let current = values[1];
640        let n = std::cmp::min(values[2], 10) as usize;
641
642        values.rotate_left(3);
643        values.truncate(n);
644
645        Ok((values, current))
646    }
647
648    /// Select an AP to use
649    ///
650    /// On newer ST-Links (JTAG Version >= 28), multiple APs are supported.
651    /// To switch between APs, dedicated commands have to be used. For older
652    /// ST-Links, we can only use AP 0. If an AP other than 0 is used on these
653    /// probes, an error is returned.
654    fn select_ap(&mut self, ap: u8) -> Result<(), DebugProbeError> {
655        // Check if we can use APs other an AP 0.
656        // Older versions of the ST-Link software don't support this.
657        if self.hw_version < 3 && self.jtag_version < Self::MIN_JTAG_VERSION_MULTI_AP {
658            if ap != 0 {
659                return Err(
660                    StlinkError::ProbeFirmwareOutdated(Self::MIN_JTAG_VERSION_MULTI_AP).into(),
661                );
662            }
663        } else if !self.opened_aps.contains(&ap) {
664            tracing::debug!("Opening AP {}", ap);
665            self.open_ap(ap)?;
666            self.opened_aps.push(ap);
667        } else {
668            tracing::trace!("AP {} already open.", ap);
669        }
670
671        Ok(())
672    }
673
674    /// Open a specific AP, which will be used for all future commands.
675    ///
676    /// This is only supported on ST-Link V3, or older ST-Links with
677    /// a JTAG version >= `MIN_JTAG_VERSION_MULTI_AP`.
678    fn open_ap(&mut self, apsel: u8) -> Result<(), DebugProbeError> {
679        // Ensure this command is actually supported
680        if self.hw_version < 3 && self.jtag_version < Self::MIN_JTAG_VERSION_MULTI_AP {
681            return Err(DebugProbeError::CommandNotSupportedByProbe {
682                command_name: "open_ap",
683            });
684        }
685
686        let mut buf = [0; 2];
687        tracing::trace!("JTAG_INIT_AP {}", apsel);
688        retry_on_wait(|| {
689            self.send_jtag_command(
690                &[commands::JTAG_COMMAND, commands::JTAG_INIT_AP, apsel],
691                &[],
692                &mut buf,
693                TIMEOUT,
694            )
695        })?;
696
697        Ok(())
698    }
699
700    /// Close a specific AP, which was opened with `open_ap`.
701    ///
702    /// This is only supported on ST-Link V3, or older ST-Links with
703    /// a JTAG version >= `MIN_JTAG_VERSION_MULTI_AP`.
704    fn _close_ap(&mut self, apsel: u8) -> Result<(), DebugProbeError> {
705        // Ensure this command is actually supported
706        if self.hw_version < 3 && self.jtag_version < Self::MIN_JTAG_VERSION_MULTI_AP {
707            return Err(DebugProbeError::CommandNotSupportedByProbe {
708                command_name: "close_ap",
709            });
710        }
711
712        let mut buf = [0; 2];
713        tracing::trace!("JTAG_CLOSE_AP {}", apsel);
714        retry_on_wait(|| {
715            self.send_jtag_command(
716                &[commands::JTAG_COMMAND, commands::JTAG_CLOSE_AP_DBG, apsel],
717                &[],
718                &mut buf,
719                TIMEOUT,
720            )
721        })?;
722
723        Ok(())
724    }
725
726    fn send_jtag_command(
727        &mut self,
728        cmd: &[u8],
729        write_data: &[u8],
730        read_data: &mut [u8],
731        timeout: Duration,
732    ) -> Result<(), StlinkError> {
733        self.device.write(cmd, write_data, read_data, timeout)?;
734        match Status::from(read_data[0]) {
735            Status::JtagOk => Ok(()),
736            status => {
737                tracing::warn!("send_jtag_command {} failed: {:?}", cmd[0], status);
738                Err(StlinkError::CommandFailed(status))
739            }
740        }
741    }
742
743    /// Starts reading SWO trace data.
744    pub fn start_trace_reception(&mut self, config: &SwoConfig) -> Result<(), DebugProbeError> {
745        let mut buf = [0; 2];
746        let bufsize = 4096u16.to_le_bytes();
747        let baud = config.baud().to_le_bytes();
748        let mut command = vec![commands::JTAG_COMMAND, commands::SWO_START_TRACE_RECEPTION];
749        command.extend_from_slice(&bufsize);
750        command.extend_from_slice(&baud);
751
752        self.send_jtag_command(&command, &[], &mut buf, TIMEOUT)?;
753
754        self.swo_enabled = true;
755
756        Ok(())
757    }
758
759    /// Stops reading SWO trace data.
760    pub fn stop_trace_reception(&mut self) -> Result<(), DebugProbeError> {
761        let mut buf = [0; 2];
762
763        self.send_jtag_command(
764            &[commands::JTAG_COMMAND, commands::SWO_STOP_TRACE_RECEPTION],
765            &[],
766            &mut buf,
767            TIMEOUT,
768        )?;
769
770        self.swo_enabled = false;
771
772        Ok(())
773    }
774
775    /// Gets the SWO count from the ST-Link probe.
776    fn read_swo_available_byte_count(&mut self) -> Result<usize, DebugProbeError> {
777        let mut buf = [0; 2];
778        self.device.write(
779            &[
780                commands::JTAG_COMMAND,
781                commands::SWO_GET_TRACE_NEW_RECORD_NB,
782            ],
783            &[],
784            &mut buf,
785            TIMEOUT,
786        )?;
787        Ok(buf.pread::<u16>(0).unwrap() as usize)
788    }
789
790    /// Reads the actual data from the SWO buffer on the ST-Link.
791    fn read_swo_data(&mut self, timeout: Duration) -> Result<Vec<u8>, DebugProbeError> {
792        // The byte count always needs to be polled first, otherwise
793        // the ST-Link won't return any data.
794        let mut buf = vec![0; self.read_swo_available_byte_count()?];
795        let bytes_read = self.device.read_swo(&mut buf, timeout)?;
796        buf.truncate(bytes_read);
797        Ok(buf)
798    }
799
800    #[tracing::instrument(level = "trace", skip(self))]
801    fn get_last_rw_status(&mut self) -> Result<(), StlinkError> {
802        let mut receive_buffer = [0u8; 12];
803
804        self.send_jtag_command(
805            &[commands::JTAG_COMMAND, commands::JTAG_GETLASTRWSTATUS2],
806            &[],
807            &mut receive_buffer,
808            TIMEOUT,
809        )?;
810
811        Ok(())
812    }
813
814    /// Reads the DAP register on the specified port and address.
815    fn read_register(&mut self, port: u16, addr: u8) -> Result<u32, DebugProbeError> {
816        let port = port.to_le_bytes();
817
818        let cmd = &[
819            commands::JTAG_COMMAND,
820            commands::JTAG_READ_DAP_REG,
821            port[0],
822            port[1],
823            addr,
824            0, // Maximum address for DAP registers is 0xFC
825        ];
826        let mut buf = [0; 8];
827        retry_on_wait(|| self.send_jtag_command(cmd, &[], &mut buf, TIMEOUT))?;
828        // Unwrap is ok!
829        Ok(buf[4..8].pread_with(0, LE).unwrap())
830    }
831
832    /// Writes a value to the DAP register on the specified port and address.
833    fn write_register(&mut self, port: u16, addr: u8, value: u32) -> Result<(), DebugProbeError> {
834        let port = port.to_le_bytes();
835        let bytes = value.to_le_bytes();
836
837        let cmd = &[
838            commands::JTAG_COMMAND,
839            commands::JTAG_WRITE_DAP_REG,
840            port[0],
841            port[1],
842            addr,
843            0, // Maximum address for DAP registers is 0xFC
844            bytes[0],
845            bytes[1],
846            bytes[2],
847            bytes[3],
848        ];
849        let mut buf = [0; 2];
850
851        retry_on_wait(|| self.send_jtag_command(cmd, &[], &mut buf, TIMEOUT))?;
852
853        Ok(())
854    }
855
856    // Limit log verbosity to "trace", to avoid spamming the log with read/write operations.
857    #[tracing::instrument(level="trace", skip(self, data, apsel), fields(ap=apsel, length= data.len()))]
858    fn read_mem_32bit(
859        &mut self,
860        address: u32,
861        data: &mut [u8],
862        apsel: u8,
863    ) -> Result<(), DebugProbeError> {
864        // Do not attempt to read if there is no data to read.
865        if data.is_empty() {
866            return Ok(());
867        }
868
869        self.select_ap(apsel)?;
870
871        // Ensure maximum read length is not exceeded.
872        assert!(
873            data.len() <= STLINK_MAX_READ_LEN,
874            "Maximum read length for STLink is {STLINK_MAX_READ_LEN} bytes"
875        );
876
877        assert!(
878            data.len().is_multiple_of(4),
879            "Data length has to be a multiple of 4 for 32 bit reads"
880        );
881
882        if !address.is_multiple_of(4) {
883            return Err(DebugProbeError::from(StlinkError::UnalignedAddress));
884        }
885
886        retry_on_wait(|| {
887            self.device.write(
888                &memory_command(commands::JTAG_READMEM_32BIT, address, data.len(), apsel),
889                &[],
890                data,
891                TIMEOUT,
892            )?;
893
894            self.get_last_rw_status()
895        })?;
896
897        tracing::trace!("Read ok");
898
899        Ok(())
900    }
901
902    #[tracing::instrument(level="trace", skip(self, data, apsel), fields(ap=apsel, length= data.len()))]
903    fn read_mem_16bit(
904        &mut self,
905        address: u32,
906        data: &mut [u8],
907        apsel: u8,
908    ) -> Result<(), DebugProbeError> {
909        // Do not attempt to read if there is no data to read.
910        if data.is_empty() {
911            return Ok(());
912        }
913
914        self.select_ap(apsel)?;
915
916        // TODO what is the max length?
917
918        assert!(
919            data.len().is_multiple_of(2),
920            "Data length has to be a multiple of 2 for 16 bit reads"
921        );
922
923        if !address.is_multiple_of(2) {
924            return Err(DebugProbeError::from(StlinkError::UnalignedAddress));
925        }
926
927        retry_on_wait(|| {
928            self.device.write(
929                &memory_command(commands::JTAG_READMEM_16BIT, address, data.len(), apsel),
930                &[],
931                data,
932                TIMEOUT,
933            )?;
934
935            self.get_last_rw_status()
936        })?;
937
938        tracing::trace!("Read ok");
939
940        Ok(())
941    }
942
943    fn read_mem_8bit(
944        &mut self,
945        address: u32,
946        length: u16,
947        apsel: u8,
948    ) -> Result<Vec<u8>, DebugProbeError> {
949        // Do not attempt to read if there is no data to read.
950        if length == 0 {
951            return Ok(vec![]);
952        }
953
954        self.select_ap(apsel)?;
955
956        tracing::trace!("read_mem_8bit");
957
958        if self.hw_version < 3 {
959            assert!(
960                length <= 64,
961                "8-Bit reads are limited to 64 bytes on ST-Link v2"
962            );
963        } else {
964            // This 255 byte limitation was empirically derived by @disasm @diondokter and @Yatekii
965            // on various STM32 chips and different ST-Linkv3 versions (J5, J7).
966            // It works until 255. 256 and above fail. Apparently it *should* work with up to
967            // 512 bytes but those tries were not fruitful.
968            assert!(
969                length <= 255,
970                "8-Bit reads are limited to 255 bytes on ST-Link v3"
971            );
972        }
973
974        // The receive buffer must be at least two bytes in size, otherwise
975        // a USB overflow error occurs.
976        let buffer_len = length.max(2) as usize;
977
978        let mut receive_buffer = vec![0u8; buffer_len];
979
980        tracing::trace!("Read mem 8 bit, address={:08x}, length={}", address, length);
981
982        retry_on_wait(|| {
983            self.device.write(
984                &memory_command(commands::JTAG_READMEM_8BIT, address, length as usize, apsel),
985                &[],
986                &mut receive_buffer,
987                TIMEOUT,
988            )?;
989
990            if length == 1 {
991                receive_buffer.resize(length as usize, 0)
992            }
993
994            self.get_last_rw_status()
995        })?;
996
997        Ok(receive_buffer)
998    }
999
1000    fn write_mem_32bit(
1001        &mut self,
1002        address: u32,
1003        data: &[u8],
1004        apsel: u8,
1005    ) -> Result<(), DebugProbeError> {
1006        // Do not attempt to write if there is no data.
1007        if data.is_empty() {
1008            return Ok(());
1009        }
1010
1011        self.select_ap(apsel)?;
1012
1013        tracing::trace!("write_mem_32bit");
1014        let length = data.len();
1015
1016        // Maximum supported read length is 2^16 bytes.
1017        assert!(
1018            length <= STLINK_MAX_WRITE_LEN,
1019            "Maximum write length for STLink is {STLINK_MAX_WRITE_LEN} bytes"
1020        );
1021
1022        assert!(
1023            data.len().is_multiple_of(4),
1024            "Data length has to be a multiple of 4 for 32 bit writes"
1025        );
1026
1027        if !address.is_multiple_of(4) {
1028            return Err(DebugProbeError::from(StlinkError::UnalignedAddress));
1029        }
1030
1031        retry_on_wait(|| {
1032            self.device.write(
1033                &memory_command(commands::JTAG_WRITEMEM_32BIT, address, data.len(), apsel),
1034                data,
1035                &mut [],
1036                TIMEOUT,
1037            )?;
1038
1039            self.get_last_rw_status()
1040        })?;
1041
1042        Ok(())
1043    }
1044
1045    fn write_mem_16bit(
1046        &mut self,
1047        address: u32,
1048        data: &[u8],
1049        apsel: u8,
1050    ) -> Result<(), DebugProbeError> {
1051        // Do not attempt to write if there is no data.
1052        if data.is_empty() {
1053            return Ok(());
1054        }
1055
1056        self.select_ap(apsel)?;
1057
1058        tracing::trace!("write_mem_16bit");
1059
1060        // TODO what is the maximum supported length?
1061
1062        assert!(
1063            data.len().is_multiple_of(2),
1064            "Data length has to be a multiple of 2 for 16 bit writes"
1065        );
1066
1067        if !address.is_multiple_of(2) {
1068            return Err(DebugProbeError::from(StlinkError::UnalignedAddress));
1069        }
1070
1071        retry_on_wait(|| {
1072            self.device.write(
1073                &memory_command(commands::JTAG_WRITEMEM_16BIT, address, data.len(), apsel),
1074                data,
1075                &mut [],
1076                TIMEOUT,
1077            )?;
1078
1079            self.get_last_rw_status()
1080        })?;
1081
1082        Ok(())
1083    }
1084
1085    fn write_mem_8bit(
1086        &mut self,
1087        address: u32,
1088        data: &[u8],
1089        apsel: u8,
1090    ) -> Result<(), DebugProbeError> {
1091        // Do not attempt to write if there is no data. Doing so would result in endless retry.
1092        if data.is_empty() {
1093            return Ok(());
1094        }
1095
1096        self.select_ap(apsel)?;
1097
1098        tracing::trace!("write_mem_8bit");
1099        let byte_length = data.len();
1100
1101        if self.hw_version < 3 {
1102            assert!(
1103                byte_length <= 64,
1104                "8-Bit writes are limited to 64 bytes on ST-Link v2"
1105            );
1106        } else {
1107            assert!(
1108                byte_length <= 512,
1109                "8-Bit writes are limited to 512 bytes on ST-Link v3"
1110            );
1111        }
1112
1113        retry_on_wait(|| {
1114            self.device.write(
1115                &memory_command(commands::JTAG_WRITEMEM_8BIT, address, data.len(), apsel),
1116                data,
1117                &mut [],
1118                TIMEOUT,
1119            )?;
1120
1121            self.get_last_rw_status()
1122        })?;
1123
1124        Ok(())
1125    }
1126
1127    fn _read_debug_reg(&mut self, address: u32) -> Result<u32, DebugProbeError> {
1128        tracing::trace!("Read debug reg {:08x}", address);
1129        let mut buff = [0u8; 8];
1130
1131        let addbytes = address.to_le_bytes();
1132        self.send_jtag_command(
1133            &[
1134                commands::JTAG_COMMAND,
1135                commands::JTAG_READ_DEBUG_REG,
1136                addbytes[0],
1137                addbytes[1],
1138                addbytes[2],
1139                addbytes[3],
1140            ],
1141            &[],
1142            &mut buff,
1143            TIMEOUT,
1144        )?;
1145
1146        Ok(buff.pread(4).unwrap())
1147    }
1148
1149    fn _write_debug_reg(&mut self, address: u32, value: u32) -> Result<(), DebugProbeError> {
1150        tracing::trace!("Write debug reg {:08x}", address);
1151        let mut buff = [0u8; 2];
1152
1153        let mut cmd = [0u8; 2 + 4 + 4];
1154        cmd[0] = commands::JTAG_COMMAND;
1155        cmd[1] = commands::JTAG_WRITE_DEBUG_REG;
1156
1157        cmd.pwrite_with(address, 2, LE).unwrap();
1158        cmd.pwrite_with(value, 6, LE).unwrap();
1159
1160        self.send_jtag_command(&cmd, &[], &mut buff, TIMEOUT)?;
1161
1162        Ok(())
1163    }
1164}
1165
1166const fn memory_command(command: u8, address: u32, len: usize, apsel: u8) -> [u8; 9] {
1167    let addbytes = address.to_le_bytes();
1168    let data_length = len.to_le_bytes();
1169    [
1170        commands::JTAG_COMMAND,
1171        command,
1172        addbytes[0],
1173        addbytes[1],
1174        addbytes[2],
1175        addbytes[3],
1176        data_length[0],
1177        data_length[1],
1178        apsel,
1179    ]
1180}
1181
1182impl<D: StLinkUsb> SwoAccess for StLink<D> {
1183    fn enable_swo(&mut self, config: &SwoConfig) -> Result<(), ArmError> {
1184        match config.mode() {
1185            SwoMode::Uart => {
1186                self.start_trace_reception(config)?;
1187                Ok(())
1188            }
1189            SwoMode::Manchester => Err(ArmError::Probe(
1190                StlinkError::ManchesterSwoNotSupported.into(),
1191            )),
1192        }
1193    }
1194
1195    fn disable_swo(&mut self) -> Result<(), ArmError> {
1196        self.stop_trace_reception()?;
1197        Ok(())
1198    }
1199
1200    fn read_swo_timeout(&mut self, timeout: Duration) -> Result<Vec<u8>, ArmError> {
1201        let data = self.read_swo_data(timeout)?;
1202        Ok(data)
1203    }
1204}
1205
1206/// ST-Link specific errors.
1207#[derive(thiserror::Error, Debug, docsplay::Display)]
1208pub enum StlinkError {
1209    /// Invalid voltage values returned by probe.
1210    VoltageDivisionByZero,
1211
1212    /// Probe is in an unknown mode.
1213    UnknownMode,
1214
1215    /// Current version of the STLink firmware does not support accessing banked DP registers.
1216    BanksNotAllowedOnDPRegister,
1217
1218    /// Not enough bytes were written. Expected {should} but only {is} were written.
1219    NotEnoughBytesWritten {
1220        /// The number of bytes actually written
1221        is: usize,
1222        /// The number of bytes that should have been written
1223        should: usize,
1224    },
1225
1226    /// USB endpoint not found.
1227    EndpointNotFound,
1228
1229    /// Command failed with status {0:?}.
1230    CommandFailed(Status),
1231
1232    /// The probe does not support JTAG.
1233    JTAGNotSupportedOnProbe,
1234
1235    /// The probe does not support SWO with Manchester encoding.
1236    ManchesterSwoNotSupported,
1237
1238    /// The probe does not support multidrop SWD.
1239    MultidropNotSupported,
1240
1241    /// Attempted unaligned access.
1242    UnalignedAddress,
1243
1244    /// The firmware on the probe is outdated, and not supported by probe-rs. The minimum supported firmware version is {0}.
1245    /// Use the ST-Link updater utility to update your probe firmware.
1246    ProbeFirmwareOutdated(u8),
1247
1248    /// USB error.
1249    Usb(#[from] std::io::Error),
1250}
1251
1252impl ProbeError for StlinkError {}
1253
1254#[derive(Debug)]
1255struct StlinkArmDebug {
1256    probe: Box<StLink<StLinkUsbDevice>>,
1257
1258    /// The ST-Link probes don't support SWD multidrop, so we always use the default DP.
1259    ///
1260    /// This flag tracks if we are connected to a DP.
1261    connected_to_dp: bool,
1262
1263    /// Information about the APs of the target.
1264    /// APs are identified by a number, starting from zero.
1265    pub access_ports: BTreeSet<FullyQualifiedApAddress>,
1266}
1267
1268impl StlinkArmDebug {
1269    fn new(probe: Box<StLink<StLinkUsbDevice>>) -> Self {
1270        // Determine the number and type of available APs.
1271        Self {
1272            probe,
1273            access_ports: BTreeSet::new(),
1274            connected_to_dp: false,
1275        }
1276    }
1277
1278    fn select_dp(&mut self, dp: DpAddress) -> Result<(), ArmError> {
1279        if dp != DpAddress::Default {
1280            return Err(DebugProbeError::from(StlinkError::MultidropNotSupported).into());
1281        }
1282
1283        if !self.connected_to_dp {
1284            // We don't need to explicitly select a DP when using the ST-Link,
1285            // so we only detect the connected APs here.
1286            //
1287            // It's however important that we set this flag here, so we don't end up recursively calling this function.
1288            self.connected_to_dp = true;
1289
1290            // Determine the number and type of available APs.
1291            self.access_ports = valid_access_ports(self, DpAddress::Default)
1292                .into_iter()
1293                .collect();
1294
1295            self.access_ports.iter().for_each(|addr| {
1296                tracing::debug!("AP {:#x?}", addr);
1297            });
1298        }
1299
1300        Ok(())
1301    }
1302
1303    fn select_dp_and_dp_bank(
1304        &mut self,
1305        dp: DpAddress,
1306        address: DpRegisterAddress,
1307    ) -> Result<(), ArmError> {
1308        self.select_dp(dp)?;
1309
1310        let Some(bank) = address.bank else {
1311            return Ok(());
1312        };
1313
1314        if bank != 0 && !self.probe.supports_dp_bank_selection() {
1315            tracing::warn!(
1316                "Trying to access DP register at address {address:#x?}, which is not supported on ST-Links."
1317            );
1318            return Err(DebugProbeError::from(StlinkError::BanksNotAllowedOnDPRegister).into());
1319        }
1320
1321        Ok(())
1322    }
1323
1324    fn select_ap_and_ap_bank(
1325        &mut self,
1326        ap: &FullyQualifiedApAddress,
1327        _address: u64,
1328    ) -> Result<(), ArmError> {
1329        self.select_dp(ap.dp())?;
1330        self.probe.select_ap(ap.ap_v1()?)?;
1331
1332        Ok(())
1333    }
1334}
1335
1336impl DapAccess for StlinkArmDebug {
1337    #[tracing::instrument(skip(self), fields(value))]
1338    fn read_raw_dp_register(
1339        &mut self,
1340        dp: DpAddress,
1341        address: DpRegisterAddress,
1342    ) -> Result<u32, ArmError> {
1343        self.select_dp_and_dp_bank(dp, address)?;
1344        let result = self.probe.read_register(DP_PORT, address.into())?;
1345
1346        tracing::Span::current().record("value", result);
1347
1348        tracing::debug!("Read succesful");
1349
1350        Ok(result)
1351    }
1352
1353    #[tracing::instrument(skip(self))]
1354    fn write_raw_dp_register(
1355        &mut self,
1356        dp: DpAddress,
1357        address: DpRegisterAddress,
1358        value: u32,
1359    ) -> Result<(), ArmError> {
1360        self.select_dp_and_dp_bank(dp, address)?;
1361
1362        self.probe.write_register(DP_PORT, address.into(), value)?;
1363        Ok(())
1364    }
1365
1366    fn read_raw_ap_register(
1367        &mut self,
1368        ap: &FullyQualifiedApAddress,
1369        address: u64,
1370    ) -> Result<u32, ArmError> {
1371        if ap.ap().is_v2() {
1372            return Err(ArmError::NotImplemented(
1373                "ST-Link does not yet support APv2",
1374            ));
1375        }
1376        self.select_ap_and_ap_bank(ap, address)?;
1377
1378        let value = self
1379            .probe
1380            .read_register(ap.ap_v1()? as u16, (address & 0xFF) as u8)?;
1381
1382        Ok(value)
1383    }
1384
1385    fn write_raw_ap_register(
1386        &mut self,
1387        ap: &FullyQualifiedApAddress,
1388        address: u64,
1389        value: u32,
1390    ) -> Result<(), ArmError> {
1391        if ap.ap().is_v2() {
1392            return Err(ArmError::NotImplemented(
1393                "ST-Link does not yet support APv2",
1394            ));
1395        }
1396        self.select_ap_and_ap_bank(ap, address)?;
1397
1398        self.probe
1399            .write_register(ap.ap_v1()? as u16, (address & 0xFF) as u8, value)?;
1400
1401        Ok(())
1402    }
1403
1404    fn try_dap_probe(&self) -> Option<&dyn DapProbe> {
1405        None
1406    }
1407
1408    fn try_dap_probe_mut(&mut self) -> Option<&mut dyn DapProbe> {
1409        None
1410    }
1411}
1412
1413impl ArmDebugInterface for StlinkArmDebug {
1414    fn memory_interface(
1415        &mut self,
1416        access_port: &FullyQualifiedApAddress,
1417    ) -> Result<Box<dyn ArmMemoryInterface + '_>, ArmError> {
1418        let mem_ap = MemoryAp::new(self, access_port)?;
1419        let interface = StLinkMemoryInterface {
1420            probe: self,
1421            current_ap: mem_ap,
1422        };
1423
1424        Ok(Box::new(interface) as _)
1425    }
1426
1427    fn access_ports(
1428        &mut self,
1429        dp: DpAddress,
1430    ) -> Result<BTreeSet<FullyQualifiedApAddress>, ArmError> {
1431        self.select_dp(dp)?;
1432
1433        Ok(self.access_ports.clone())
1434    }
1435
1436    fn close(self: Box<Self>) -> Probe {
1437        Probe::from_attached_probe(self.probe)
1438    }
1439
1440    fn current_debug_port(&self) -> Option<DpAddress> {
1441        if self.connected_to_dp {
1442            // SWD multidrop is not supported on ST-Link
1443            Some(DpAddress::Default)
1444        } else {
1445            None
1446        }
1447    }
1448
1449    fn select_debug_port(&mut self, dp: DpAddress) -> Result<(), ArmError> {
1450        self.select_dp(dp)
1451    }
1452
1453    fn reinitialize(&mut self) -> Result<(), ArmError> {
1454        Ok(())
1455    }
1456}
1457
1458impl SwdSequence for StlinkArmDebug {
1459    fn swj_sequence(&mut self, _bit_len: u8, _bits: u64) -> Result<(), DebugProbeError> {
1460        // This is not supported for ST-Links, unfortunately.
1461        Err(DebugProbeError::CommandNotSupportedByProbe {
1462            command_name: "swj_sequence",
1463        })
1464    }
1465
1466    fn swj_pins(
1467        &mut self,
1468        pin_out: u32,
1469        pin_select: u32,
1470        pin_wait: u32,
1471    ) -> Result<u32, DebugProbeError> {
1472        self.probe.swj_pins(pin_out, pin_select, pin_wait)
1473    }
1474}
1475
1476impl SwoAccess for StlinkArmDebug {
1477    fn enable_swo(&mut self, config: &SwoConfig) -> Result<(), ArmError> {
1478        self.probe.enable_swo(config)
1479    }
1480
1481    fn disable_swo(&mut self) -> Result<(), ArmError> {
1482        self.probe.disable_swo()
1483    }
1484
1485    fn read_swo_timeout(&mut self, timeout: Duration) -> Result<Vec<u8>, ArmError> {
1486        self.probe.read_swo_timeout(timeout)
1487    }
1488}
1489
1490#[derive(Debug)]
1491struct StLinkMemoryInterface<'probe> {
1492    probe: &'probe mut StlinkArmDebug,
1493    current_ap: MemoryAp,
1494}
1495
1496impl SwdSequence for StLinkMemoryInterface<'_> {
1497    fn swj_sequence(&mut self, bit_len: u8, bits: u64) -> Result<(), DebugProbeError> {
1498        self.probe.swj_sequence(bit_len, bits)
1499    }
1500
1501    fn swj_pins(
1502        &mut self,
1503        pin_out: u32,
1504        pin_select: u32,
1505        pin_wait: u32,
1506    ) -> Result<u32, DebugProbeError> {
1507        self.probe.swj_pins(pin_out, pin_select, pin_wait)
1508    }
1509}
1510
1511impl MemoryInterface<ArmError> for StLinkMemoryInterface<'_> {
1512    fn supports_native_64bit_access(&mut self) -> bool {
1513        false
1514    }
1515
1516    fn read_64(&mut self, address: u64, data: &mut [u64]) -> Result<(), ArmError> {
1517        let address = valid_32bit_arm_address(address)?;
1518
1519        // ST-Link V3 requires the data phase to be non-empty. For empty data,
1520        // return success.
1521        if data.is_empty() {
1522            return Ok(());
1523        }
1524
1525        for (i, d) in data.iter_mut().enumerate() {
1526            let mut buff = vec![0u8; 8];
1527
1528            self.probe.probe.read_mem_32bit(
1529                address + (i * 8) as u32,
1530                &mut buff,
1531                self.current_ap.ap_address().ap_v1()?,
1532            )?;
1533
1534            *d = u64::from_le_bytes(buff.try_into().unwrap());
1535        }
1536
1537        Ok(())
1538    }
1539
1540    fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), ArmError> {
1541        let address = valid_32bit_arm_address(address)?;
1542
1543        // ST-Link V3 requires the data phase to be non-empty. For empty data,
1544        // return success.
1545        if data.is_empty() {
1546            return Ok(());
1547        }
1548
1549        // Read needs to be chunked into chunks with appropiate max length (see STLINK_MAX_READ_LEN).
1550        for (index, chunk) in data.chunks_mut(STLINK_MAX_READ_LEN / 4).enumerate() {
1551            let mut buff = vec![0u8; 4 * chunk.len()];
1552
1553            self.probe.probe.read_mem_32bit(
1554                address + (index * STLINK_MAX_READ_LEN) as u32,
1555                &mut buff,
1556                self.current_ap.ap_address().ap_v1()?,
1557            )?;
1558
1559            for (index, word) in buff.chunks_exact(4).enumerate() {
1560                chunk[index] = u32::from_le_bytes(word.try_into().unwrap());
1561            }
1562        }
1563
1564        Ok(())
1565    }
1566
1567    fn read_16(&mut self, address: u64, data: &mut [u16]) -> Result<(), ArmError> {
1568        let address = valid_32bit_arm_address(address)?;
1569
1570        // ST-Link V3 requires the data phase to be non-empty. For empty data,
1571        // return success.
1572        if data.is_empty() {
1573            return Ok(());
1574        }
1575
1576        // Read needs to be chunked into chunks of appropriate max length of the probe
1577        // use half the limits of 8bit accesses to be conservative. TODO can we increase this?
1578        let chunk_size = if self.probe.probe.hw_version < 3 {
1579            32
1580        } else {
1581            64
1582        };
1583
1584        for (index, chunk) in data.chunks_mut(chunk_size).enumerate() {
1585            let mut buff = vec![0u8; 2 * chunk.len()];
1586            self.probe.probe.read_mem_16bit(
1587                address + (index * chunk_size) as u32,
1588                &mut buff,
1589                self.current_ap.ap_address().ap_v1()?,
1590            )?;
1591
1592            for (index, word) in buff.chunks_exact(2).enumerate() {
1593                chunk[index] = u16::from_le_bytes(word.try_into().unwrap());
1594            }
1595        }
1596
1597        Ok(())
1598    }
1599
1600    fn read_8(&mut self, address: u64, data: &mut [u8]) -> Result<(), ArmError> {
1601        let address = valid_32bit_arm_address(address)?;
1602
1603        // ST-Link V3 requires the data phase to be non-empty. For empty data,
1604        // return success.
1605        if data.is_empty() {
1606            return Ok(());
1607        }
1608
1609        // Read needs to be chunked into chunks of appropriate max length of the probe
1610        let chunk_size = if self.probe.probe.hw_version < 3 {
1611            64
1612        } else {
1613            // This 128 byte chunk was set as the maximum possible amount is 255 even though it should
1614            // support 512 bytes in theory. Thus we chose a smaller amount to avoid more possible bugs
1615            // by not pushing the limit.
1616            // See code of `read_mem_8bit` for more info.
1617            128
1618        };
1619
1620        for (index, chunk) in data.chunks_mut(chunk_size).enumerate() {
1621            chunk.copy_from_slice(&self.probe.probe.read_mem_8bit(
1622                address + (index * chunk_size) as u32,
1623                chunk.len() as u16,
1624                self.current_ap.ap_address().ap_v1()?,
1625            )?);
1626        }
1627
1628        Ok(())
1629    }
1630
1631    fn write_64(&mut self, address: u64, data: &[u64]) -> Result<(), ArmError> {
1632        let address = valid_32bit_arm_address(address)?;
1633
1634        // ST-Link V3 requires the data phase to be non-empty. For empty data,
1635        // return success.
1636        if data.is_empty() {
1637            return Ok(());
1638        }
1639
1640        let mut tx_buffer = vec![0u8; data.len() * 8];
1641
1642        let mut offset = 0;
1643
1644        for word in data {
1645            tx_buffer
1646                .gwrite(word, &mut offset)
1647                .expect("Failed to write into tx_buffer");
1648        }
1649
1650        for (index, chunk) in tx_buffer.chunks(STLINK_MAX_WRITE_LEN).enumerate() {
1651            self.probe.probe.write_mem_32bit(
1652                address + (index * STLINK_MAX_WRITE_LEN) as u32,
1653                chunk,
1654                self.current_ap.ap_address().ap_v1()?,
1655            )?;
1656        }
1657
1658        Ok(())
1659    }
1660
1661    fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), ArmError> {
1662        let address = valid_32bit_arm_address(address)?;
1663
1664        // ST-Link V3 requires the data phase to be non-empty. For empty data,
1665        // return success.
1666        if data.is_empty() {
1667            return Ok(());
1668        }
1669
1670        let mut tx_buffer = vec![0u8; data.len() * 4];
1671
1672        let mut offset = 0;
1673
1674        for word in data {
1675            tx_buffer
1676                .gwrite(word, &mut offset)
1677                .expect("Failed to write into tx_buffer");
1678        }
1679
1680        for (index, chunk) in tx_buffer.chunks(STLINK_MAX_WRITE_LEN).enumerate() {
1681            self.probe.probe.write_mem_32bit(
1682                address + (index * STLINK_MAX_WRITE_LEN) as u32,
1683                chunk,
1684                self.current_ap.ap_address().ap_v1()?,
1685            )?;
1686        }
1687
1688        Ok(())
1689    }
1690
1691    fn write_16(&mut self, address: u64, data: &[u16]) -> Result<(), ArmError> {
1692        let address = valid_32bit_arm_address(address)?;
1693
1694        // ST-Link V3 requires the data phase to be non-empty. For empty data,
1695        // return success.
1696        if data.is_empty() {
1697            return Ok(());
1698        }
1699
1700        let mut tx_buffer = vec![0u8; data.len() * 2];
1701
1702        let mut offset = 0;
1703
1704        for word in data {
1705            tx_buffer
1706                .gwrite(word, &mut offset)
1707                .expect("Failed to write into tx_buffer");
1708        }
1709
1710        // use half the limits of 8bit accesses to be conservative. TODO can we increase this?
1711        let chunk_size = if self.probe.probe.hw_version < 3 {
1712            32
1713        } else {
1714            256
1715        };
1716
1717        for (index, chunk) in tx_buffer.chunks(chunk_size).enumerate() {
1718            self.probe.probe.write_mem_16bit(
1719                address + (index * STLINK_MAX_WRITE_LEN) as u32,
1720                chunk,
1721                self.current_ap.ap_address().ap_v1()?,
1722            )?;
1723        }
1724
1725        Ok(())
1726    }
1727
1728    fn write_8(&mut self, address: u64, data: &[u8]) -> Result<(), ArmError> {
1729        let address = valid_32bit_arm_address(address)?;
1730
1731        // ST-Link V3 requires the data phase to be non-empty. For empty data,
1732        // return success.
1733        if data.is_empty() {
1734            return Ok(());
1735        }
1736
1737        // The underlying STLink command is limited to a single USB frame at a time
1738        // so we must manually chunk it into multiple command if it exceeds
1739        // that size.
1740        let chunk_size = if self.probe.probe.hw_version < 3 {
1741            64
1742        } else {
1743            512
1744        };
1745
1746        // If we write less than 64 bytes, just write it directly
1747        if data.len() < chunk_size {
1748            tracing::trace!("write_8: small - direct 8 bit write to {:08x}", address);
1749            self.probe.probe.write_mem_8bit(
1750                address,
1751                data,
1752                self.current_ap.ap_address().ap_v1()?,
1753            )?;
1754        } else {
1755            // Handle unaligned data in the beginning.
1756            let bytes_beginning = if address % 4 == 0 {
1757                0
1758            } else {
1759                (4 - address % 4) as usize
1760            };
1761
1762            let mut current_address = address;
1763
1764            if bytes_beginning > 0 {
1765                tracing::trace!(
1766                    "write_8: at_begin - unaligned write of {} bytes to address {:08x}",
1767                    bytes_beginning,
1768                    current_address,
1769                );
1770                self.probe.probe.write_mem_8bit(
1771                    current_address,
1772                    &data[..bytes_beginning],
1773                    self.current_ap.ap_address().ap_v1()?,
1774                )?;
1775
1776                current_address += bytes_beginning as u32;
1777            }
1778
1779            // Address has to be aligned here.
1780            assert!(current_address % 4 == 0);
1781
1782            let aligned_len = ((data.len() - bytes_beginning) / 4) * 4;
1783
1784            tracing::trace!(
1785                "write_8: aligned write of {} bytes to address {:08x}",
1786                aligned_len,
1787                current_address,
1788            );
1789
1790            for (index, chunk) in data[bytes_beginning..(bytes_beginning + aligned_len)]
1791                .chunks(STLINK_MAX_WRITE_LEN)
1792                .enumerate()
1793            {
1794                self.probe.probe.write_mem_32bit(
1795                    current_address + (index * STLINK_MAX_WRITE_LEN) as u32,
1796                    chunk,
1797                    self.current_ap.ap_address().ap_v1()?,
1798                )?;
1799            }
1800
1801            current_address += aligned_len as u32;
1802
1803            let remaining_bytes = &data[bytes_beginning + aligned_len..];
1804
1805            if !remaining_bytes.is_empty() {
1806                tracing::trace!(
1807                    "write_8: at_end -unaligned write of {} bytes to address {:08x}",
1808                    bytes_beginning,
1809                    current_address,
1810                );
1811                self.probe.probe.write_mem_8bit(
1812                    current_address,
1813                    remaining_bytes,
1814                    self.current_ap.ap_address().ap_v1()?,
1815                )?;
1816            }
1817        }
1818        Ok(())
1819    }
1820
1821    fn flush(&mut self) -> Result<(), ArmError> {
1822        Ok(())
1823    }
1824
1825    fn supports_8bit_transfers(&self) -> Result<bool, ArmError> {
1826        Ok(true)
1827    }
1828}
1829
1830impl ArmMemoryInterface for StLinkMemoryInterface<'_> {
1831    fn base_address(&mut self) -> Result<u64, ArmError> {
1832        self.current_ap.base_address(self.probe)
1833    }
1834
1835    fn fully_qualified_address(&self) -> FullyQualifiedApAddress {
1836        self.current_ap.ap_address().clone()
1837    }
1838
1839    fn get_arm_debug_interface(&mut self) -> Result<&mut dyn ArmDebugInterface, DebugProbeError> {
1840        Ok(self.probe)
1841    }
1842
1843    fn generic_status(&mut self) -> Result<crate::architecture::arm::ap::CSW, ArmError> {
1844        self.current_ap.generic_status(self.probe)
1845    }
1846}
1847
1848fn is_wait_error(e: &StlinkError) -> bool {
1849    matches!(
1850        e,
1851        StlinkError::CommandFailed(Status::SwdDpWait | Status::SwdApWait)
1852    )
1853}
1854
1855fn retry_on_wait<R>(mut f: impl FnMut() -> Result<R, StlinkError>) -> Result<R, StlinkError> {
1856    let mut last_err = None;
1857    for attempt in 0..13 {
1858        match f() {
1859            Ok(res) => return Ok(res),
1860            Err(e) => {
1861                if is_wait_error(&e) {
1862                    tracing::warn!("got SwdDpWait/SwdApWait, retrying.");
1863                    last_err = Some(e);
1864                } else {
1865                    return Err(e);
1866                }
1867            }
1868        }
1869
1870        // Sleep with exponential backoff.
1871        thread::sleep(Duration::from_micros(100 << attempt));
1872    }
1873
1874    tracing::warn!("too many retries, giving up");
1875
1876    // Return the last error (will be SwdDpWait or SwdApWait)
1877    Err(last_err.unwrap())
1878}
1879
1880#[cfg(test)]
1881mod test {
1882    use super::*;
1883
1884    #[derive(Debug)]
1885    struct MockUsb {
1886        hw_version: u8,
1887        jtag_version: u8,
1888        swim_version: u8,
1889
1890        target_voltage_a0: f32,
1891        _target_voltage_a1: f32,
1892    }
1893
1894    impl MockUsb {
1895        fn build(self) -> StLink<MockUsb> {
1896            StLink {
1897                device: self,
1898                name: "Mock STlink".into(),
1899                hw_version: 0,
1900                protocol: WireProtocol::Swd,
1901                jtag_version: 0,
1902                swd_speed_khz: 0,
1903                jtag_speed_khz: 0,
1904                swo_enabled: false,
1905                opened_aps: vec![],
1906            }
1907        }
1908    }
1909
1910    impl StLinkUsb for MockUsb {
1911        fn write(
1912            &mut self,
1913            cmd: &[u8],
1914            _write_data: &[u8],
1915            read_data: &mut [u8],
1916            _timeout: Duration,
1917        ) -> Result<(), StlinkError> {
1918            match cmd[0] {
1919                commands::GET_VERSION => {
1920                    // GET_VERSION response structure:
1921                    //   Byte 0-1:
1922                    //     [15:12] Major/HW version
1923                    //     [11:6]  JTAG/SWD version
1924                    //     [5:0]   SWIM or MSC version
1925                    //   Byte 2-3: ST_VID
1926                    //   Byte 4-5: STLINK_PID
1927
1928                    let version: u16 = ((self.hw_version as u16) << 12)
1929                        | ((self.jtag_version as u16) << 6)
1930                        | (self.swim_version as u16);
1931
1932                    read_data[0] = (version >> 8) as u8;
1933                    read_data[1] = version as u8;
1934
1935                    Ok(())
1936                }
1937                commands::GET_TARGET_VOLTAGE => {
1938                    read_data.pwrite(self.target_voltage_a0, 0).unwrap();
1939                    read_data.pwrite(self.target_voltage_a0, 4).unwrap();
1940                    Ok(())
1941                }
1942                commands::JTAG_COMMAND => {
1943                    // Return a status of OK for JTAG commands
1944                    read_data[0] = 0x80;
1945
1946                    Ok(())
1947                }
1948                _ => Ok(()),
1949            }
1950        }
1951        fn reset(&mut self) -> Result<(), StlinkError> {
1952            Ok(())
1953        }
1954
1955        fn read_swo(
1956            &mut self,
1957            _read_data: &mut [u8],
1958            _timeout: Duration,
1959        ) -> Result<usize, StlinkError> {
1960            unimplemented!("Not implemented for MockUSB")
1961        }
1962    }
1963
1964    #[test]
1965    fn detect_old_firmware() {
1966        // Test that the init function detects old, unsupported firmware.
1967
1968        let usb_mock = MockUsb {
1969            hw_version: 2,
1970            jtag_version: 20,
1971            swim_version: 0,
1972
1973            target_voltage_a0: 1.0,
1974            _target_voltage_a1: 2.0,
1975        };
1976
1977        let mut probe = usb_mock.build();
1978
1979        let init_result = probe.init();
1980
1981        match init_result.unwrap_err() {
1982            StlinkError::ProbeFirmwareOutdated(_) => (),
1983            other => panic!("Expected firmware outdated error, got {other}"),
1984        }
1985    }
1986
1987    #[test]
1988    fn firmware_without_multiple_ap_support() {
1989        // Test that firmware with only support for a single AP works,
1990        // as long as only AP 0 is selected
1991
1992        let usb_mock = MockUsb {
1993            hw_version: 2,
1994            jtag_version: 26,
1995            swim_version: 0,
1996            target_voltage_a0: 1.0,
1997            _target_voltage_a1: 2.0,
1998        };
1999
2000        let mut probe = usb_mock.build();
2001
2002        probe.init().expect("Init function failed");
2003
2004        // Selecting AP 0 should still work
2005        probe.select_ap(0).expect("Select AP 0 failed.");
2006
2007        probe
2008            .select_ap(1)
2009            .expect_err("Selecting AP other than AP 0 should fail");
2010    }
2011
2012    #[test]
2013    fn firmware_with_multiple_ap_support() {
2014        // Test that firmware with only support for a single AP works,
2015        // as long as only AP 0 is selected
2016
2017        let usb_mock = MockUsb {
2018            hw_version: 2,
2019            jtag_version: 30,
2020            swim_version: 0,
2021            target_voltage_a0: 1.0,
2022            _target_voltage_a1: 2.0,
2023        };
2024
2025        let mut probe = usb_mock.build();
2026
2027        probe.init().expect("Init function failed");
2028
2029        // Selecting AP 0 should still work
2030        probe.select_ap(0).expect("Select AP 0 failed.");
2031
2032        probe
2033            .select_ap(1)
2034            .expect("Selecting AP other than AP 0 should work");
2035    }
2036
2037    #[test]
2038    fn test_is_wait_error() {
2039        assert!(!is_wait_error(&StlinkError::BanksNotAllowedOnDPRegister));
2040        assert!(!is_wait_error(&StlinkError::CommandFailed(
2041            Status::JtagFreqNotSupported
2042        )));
2043        assert!(is_wait_error(&StlinkError::CommandFailed(
2044            Status::SwdDpWait
2045        )));
2046        assert!(is_wait_error(&StlinkError::CommandFailed(
2047            Status::SwdApWait
2048        )));
2049    }
2050}