1mod 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
37const STLINK_MAX_READ_LEN: usize = 6144;
42
43const STLINK_MAX_WRITE_LEN: usize = 0xFFFC;
47
48const DP_PORT: u16 = 0xFFFF;
49
50#[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#[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 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 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 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 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 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 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 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 thread::sleep(Duration::from_micros(pin_wait as u64));
368
369 Ok(0xFFFF_FFFF)
371 } else {
372 Err(DebugProbeError::CommandNotSupportedByProbe {
374 command_name: "swj_pins",
375 })
376 }
377 }
378}
379
380impl<D: StLinkUsb> StLink<D> {
381 const _MAXIMUM_TRANSFER_SIZE: u32 = 1024;
385
386 const MIN_JTAG_VERSION: u8 = 26;
388
389 const MIN_JTAG_VERSION_V3: u8 = 3;
393
394 const MIN_JTAG_VERSION_MULTI_AP: u8 = 28;
396
397 const MIN_JTAG_VERSION_DP_BANK_SEL: u8 = 32;
402
403 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 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 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 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 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 if self.hw_version >= 3 {
485 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 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 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 self.device.reset()?;
528
529 self.enter_idle()?;
530 }
531 _ => 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 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 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 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 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 fn select_ap(&mut self, ap: u8) -> Result<(), DebugProbeError> {
655 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 fn open_ap(&mut self, apsel: u8) -> Result<(), DebugProbeError> {
679 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 fn _close_ap(&mut self, apsel: u8) -> Result<(), DebugProbeError> {
705 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 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 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 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 fn read_swo_data(&mut self, timeout: Duration) -> Result<Vec<u8>, DebugProbeError> {
792 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 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, ];
826 let mut buf = [0; 8];
827 retry_on_wait(|| self.send_jtag_command(cmd, &[], &mut buf, TIMEOUT))?;
828 Ok(buf[4..8].pread_with(0, LE).unwrap())
830 }
831
832 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, 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 #[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 if data.is_empty() {
866 return Ok(());
867 }
868
869 self.select_ap(apsel)?;
870
871 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 if data.is_empty() {
911 return Ok(());
912 }
913
914 self.select_ap(apsel)?;
915
916 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 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 assert!(
969 length <= 255,
970 "8-Bit reads are limited to 255 bytes on ST-Link v3"
971 );
972 }
973
974 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 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 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 if data.is_empty() {
1053 return Ok(());
1054 }
1055
1056 self.select_ap(apsel)?;
1057
1058 tracing::trace!("write_mem_16bit");
1059
1060 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 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#[derive(thiserror::Error, Debug, docsplay::Display)]
1208pub enum StlinkError {
1209 VoltageDivisionByZero,
1211
1212 UnknownMode,
1214
1215 BanksNotAllowedOnDPRegister,
1217
1218 NotEnoughBytesWritten {
1220 is: usize,
1222 should: usize,
1224 },
1225
1226 EndpointNotFound,
1228
1229 CommandFailed(Status),
1231
1232 JTAGNotSupportedOnProbe,
1234
1235 ManchesterSwoNotSupported,
1237
1238 MultidropNotSupported,
1240
1241 UnalignedAddress,
1243
1244 ProbeFirmwareOutdated(u8),
1247
1248 Usb(#[from] std::io::Error),
1250}
1251
1252impl ProbeError for StlinkError {}
1253
1254#[derive(Debug)]
1255struct StlinkArmDebug {
1256 probe: Box<StLink<StLinkUsbDevice>>,
1257
1258 connected_to_dp: bool,
1262
1263 pub access_ports: BTreeSet<FullyQualifiedApAddress>,
1266}
1267
1268impl StlinkArmDebug {
1269 fn new(probe: Box<StLink<StLinkUsbDevice>>) -> Self {
1270 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 self.connected_to_dp = true;
1289
1290 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 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 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 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 if data.is_empty() {
1546 return Ok(());
1547 }
1548
1549 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 if data.is_empty() {
1573 return Ok(());
1574 }
1575
1576 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 if data.is_empty() {
1606 return Ok(());
1607 }
1608
1609 let chunk_size = if self.probe.probe.hw_version < 3 {
1611 64
1612 } else {
1613 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 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 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 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 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 if data.is_empty() {
1734 return Ok(());
1735 }
1736
1737 let chunk_size = if self.probe.probe.hw_version < 3 {
1741 64
1742 } else {
1743 512
1744 };
1745
1746 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 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 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 thread::sleep(Duration::from_micros(100 << attempt));
1872 }
1873
1874 tracing::warn!("too many retries, giving up");
1875
1876 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 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 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 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 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 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 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 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}