1use std::{
4 error::Error,
5 fmt::Debug,
6 sync::Arc,
7 thread,
8 time::{Duration, Instant},
9};
10
11use probe_rs_target::CoreType;
12
13use crate::{
14 MemoryInterface, MemoryMappedRegister, Session,
15 architecture::arm::{
16 ArmDebugInterface, DapError, RegisterAddress,
17 core::registers::cortex_m::{PC, SP},
18 dp::{Ctrl, DLPIDR, DebugPortError, DpRegister, TARGETID},
19 },
20 probe::WireProtocol,
21};
22
23use super::{
24 ArmError, DapAccess, FullyQualifiedApAddress, Pins,
25 ap::AccessPortError,
26 armv6m::Demcr,
27 communication_interface::DapProbe,
28 component::{TraceFunnel, TraceSink},
29 core::cortex_m::{Dhcsr, Vtor},
30 dp::{Abort, DPIDR, DpAccess, DpAddress, SelectV1},
31 memory::{
32 ArmMemoryInterface,
33 romtable::{CoresightComponent, PeripheralType},
34 },
35};
36
37#[derive(thiserror::Error, Debug)]
39pub enum ArmDebugSequenceError {
40 #[error("Core access requries debug_base to be specified, but it is not")]
42 DebugBaseNotSpecified,
43
44 #[error("Core access requries cti_base to be specified, but it is not")]
46 CtiBaseNotSpecified,
47
48 #[error("An error occurred in a debug sequnce: {0}")]
50 SequenceSpecific(#[from] Box<dyn Error + Send + Sync + 'static>),
51}
52
53impl ArmDebugSequenceError {
54 pub(crate) fn custom(message: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
55 ArmDebugSequenceError::SequenceSpecific(message.into())
56 }
57}
58
59#[derive(Debug)]
61pub struct DefaultArmSequence(pub(crate) ());
62
63impl DefaultArmSequence {
64 pub fn create() -> Arc<dyn ArmDebugSequence> {
66 Arc::new(Self(()))
67 }
68}
69
70impl ArmDebugSequence for DefaultArmSequence {}
71
72fn armv7a_reset_catch_set(
74 core: &mut dyn ArmMemoryInterface,
75 debug_base: Option<u64>,
76) -> Result<(), ArmError> {
77 use crate::architecture::arm::core::armv7a_debug_regs::Dbgprcr;
78
79 let debug_base =
80 debug_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::DebugBaseNotSpecified))?;
81
82 let address = Dbgprcr::get_mmio_address_from_base(debug_base)?;
83 let mut dbgprcr = Dbgprcr(core.read_word_32(address)?);
84
85 dbgprcr.set_hcwr(true);
86
87 core.write_word_32(address, dbgprcr.into())?;
88
89 Ok(())
90}
91
92fn armv7a_reset_catch_clear(
94 core: &mut dyn ArmMemoryInterface,
95 debug_base: Option<u64>,
96) -> Result<(), ArmError> {
97 use crate::architecture::arm::core::armv7a_debug_regs::Dbgprcr;
98
99 let debug_base =
100 debug_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::DebugBaseNotSpecified))?;
101
102 let address = Dbgprcr::get_mmio_address_from_base(debug_base)?;
103 let mut dbgprcr = Dbgprcr(core.read_word_32(address)?);
104
105 dbgprcr.set_hcwr(false);
106
107 core.write_word_32(address, dbgprcr.into())?;
108
109 Ok(())
110}
111
112fn armv7a_reset_system(
113 interface: &mut dyn ArmMemoryInterface,
114 debug_base: Option<u64>,
115) -> Result<(), ArmError> {
116 use crate::architecture::arm::core::armv7a_debug_regs::{Dbgprcr, Dbgprsr};
117
118 let debug_base =
119 debug_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::DebugBaseNotSpecified))?;
120
121 let address = Dbgprcr::get_mmio_address_from_base(debug_base)?;
123 let mut dbgprcr = Dbgprcr(interface.read_word_32(address)?);
124
125 dbgprcr.set_cwrr(true);
126
127 interface.write_word_32(address, dbgprcr.into())?;
128
129 let address = Dbgprsr::get_mmio_address_from_base(debug_base)?;
131
132 loop {
133 let dbgprsr = Dbgprsr(interface.read_word_32(address)?);
134 if dbgprsr.sr() {
135 break;
136 }
137 }
138
139 Ok(())
140}
141
142fn armv7a_core_start(
144 core: &mut dyn ArmMemoryInterface,
145 debug_base: Option<u64>,
146) -> Result<(), ArmError> {
147 use crate::architecture::arm::core::armv7a_debug_regs::{Dbgdsccr, Dbgdscr, Dbgdsmcr, Dbglar};
148
149 let debug_base =
150 debug_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::DebugBaseNotSpecified))?;
151 tracing::debug!(
152 "Starting debug for ARMv7-A core with registers at {:#X}",
153 debug_base
154 );
155
156 let address = Dbglar::get_mmio_address_from_base(debug_base)?;
158 core.write_word_32(address, Dbglar(0).into())?;
159
160 let address = Dbgdsccr::get_mmio_address_from_base(debug_base)?;
162 core.write_word_32(address, Dbgdsccr(0).into())?;
163
164 let address = Dbgdsmcr::get_mmio_address_from_base(debug_base)?;
166 core.write_word_32(address, Dbgdsmcr(0).into())?;
167
168 let address = Dbgdscr::get_mmio_address_from_base(debug_base)?;
170 let mut dbgdscr = Dbgdscr(core.read_word_32(address)?);
171
172 if dbgdscr.hdbgen() && dbgdscr.extdccmode() == 0 {
173 tracing::debug!("Core is already in debug mode, no need to enable it again");
174 return Ok(());
175 }
176
177 dbgdscr.set_hdbgen(true);
178 dbgdscr.set_extdccmode(0);
179 core.write_word_32(address, dbgdscr.into())?;
180
181 Ok(())
182}
183
184fn armv8a_reset_catch_set(
186 core: &mut dyn ArmMemoryInterface,
187 debug_base: Option<u64>,
188) -> Result<(), ArmError> {
189 use crate::architecture::arm::core::armv8a_debug_regs::Edecr;
190
191 let debug_base =
192 debug_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::DebugBaseNotSpecified))?;
193
194 let address = Edecr::get_mmio_address_from_base(debug_base)?;
195 let mut edecr = Edecr(core.read_word_32(address)?);
196
197 edecr.set_rce(true);
198
199 core.write_word_32(address, edecr.into())?;
200
201 Ok(())
202}
203
204fn armv8a_reset_catch_clear(
206 core: &mut dyn ArmMemoryInterface,
207 debug_base: Option<u64>,
208) -> Result<(), ArmError> {
209 use crate::architecture::arm::core::armv8a_debug_regs::Edecr;
210
211 let debug_base =
212 debug_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::DebugBaseNotSpecified))?;
213
214 let address = Edecr::get_mmio_address_from_base(debug_base)?;
215 let mut edecr = Edecr(core.read_word_32(address)?);
216
217 edecr.set_rce(false);
218
219 core.write_word_32(address, edecr.into())?;
220
221 Ok(())
222}
223
224fn armv8a_reset_system(
225 interface: &mut dyn ArmMemoryInterface,
226 debug_base: Option<u64>,
227) -> Result<(), ArmError> {
228 use crate::architecture::arm::core::armv8a_debug_regs::{Edprcr, Edprsr};
229
230 let debug_base =
231 debug_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::DebugBaseNotSpecified))?;
232
233 let address = Edprcr::get_mmio_address_from_base(debug_base)?;
235 let mut edprcr = Edprcr(interface.read_word_32(address)?);
236
237 edprcr.set_cwrr(true);
238
239 interface.write_word_32(address, edprcr.into())?;
240
241 let address = Edprsr::get_mmio_address_from_base(debug_base)?;
243
244 loop {
245 let edprsr = Edprsr(interface.read_word_32(address)?);
246 if edprsr.sr() {
247 break;
248 }
249 }
250
251 Ok(())
252}
253
254fn armv8a_core_start(
256 core: &mut dyn ArmMemoryInterface,
257 debug_base: Option<u64>,
258 cti_base: Option<u64>,
259) -> Result<(), ArmError> {
260 use crate::architecture::arm::core::armv8a_debug_regs::{
261 CtiControl, CtiGate, CtiOuten, Edlar, Edscr, Oslar,
262 };
263
264 let debug_base =
265 debug_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::DebugBaseNotSpecified))?;
266 let cti_base =
267 cti_base.ok_or_else(|| ArmError::from(ArmDebugSequenceError::CtiBaseNotSpecified))?;
268
269 tracing::debug!(
270 "Starting debug for ARMv8-A core with registers at {:#X}",
271 debug_base
272 );
273
274 let address = Edlar::get_mmio_address_from_base(debug_base)?;
276 core.write_word_32(address, Edlar(0).into())?;
277
278 let address = Oslar::get_mmio_address_from_base(debug_base)?;
280 core.write_word_32(address, Oslar(0).into())?;
281
282 let mut cticontrol = CtiControl(0);
284 cticontrol.set_glben(true);
285
286 let address = CtiControl::get_mmio_address_from_base(cti_base)?;
287 core.write_word_32(address, cticontrol.into())?;
288
289 let address = CtiGate::get_mmio_address_from_base(cti_base)?;
291 core.write_word_32(address, 0)?;
292
293 let mut ctiouten = CtiOuten(0);
296 ctiouten.set_outen(0, 1);
297
298 let address = CtiOuten::get_mmio_address_from_base(cti_base)?;
299 core.write_word_32(address, ctiouten.into())?;
300
301 let mut ctiouten = CtiOuten(0);
303 ctiouten.set_outen(1, 1);
304
305 let address = CtiOuten::get_mmio_address_from_base(cti_base)? + 4;
306 core.write_word_32(address, ctiouten.into())?;
307
308 let address = Edscr::get_mmio_address_from_base(debug_base)?;
310 let mut edscr = Edscr(core.read_word_32(address)?);
311
312 if edscr.hde() && !edscr.ma() {
313 tracing::debug!("Core is already in debug mode, no need to enable it again");
314 return Ok(());
315 }
316
317 edscr.set_hde(true);
318 edscr.set_ma(false);
319 core.write_word_32(address, edscr.into())?;
320
321 Ok(())
322}
323
324pub(crate) fn cortex_m_core_start(core: &mut dyn ArmMemoryInterface) -> Result<(), ArmError> {
326 use crate::architecture::arm::core::armv7m::Dhcsr;
327
328 let current_dhcsr = Dhcsr(core.read_word_32(Dhcsr::get_mmio_address())?);
329
330 if current_dhcsr.c_debugen() {
332 tracing::debug!("Core is already in debug mode, no need to enable it again");
333 return Ok(());
334 }
335 let mut dhcsr = Dhcsr(0);
338 dhcsr.set_c_debugen(true);
339 dhcsr.enable_write();
340
341 core.write_word_32(Dhcsr::get_mmio_address(), dhcsr.into())?;
342
343 Ok(())
344}
345
346fn cortex_m_reset_catch_clear(core: &mut dyn ArmMemoryInterface) -> Result<(), ArmError> {
348 use crate::architecture::arm::core::armv7m::Demcr;
349
350 let mut demcr = Demcr(core.read_word_32(Demcr::get_mmio_address())?);
352 demcr.set_vc_corereset(false);
353
354 core.write_word_32(Demcr::get_mmio_address(), demcr.into())?;
355 Ok(())
356}
357
358fn cortex_m_reset_catch_set(core: &mut dyn ArmMemoryInterface) -> Result<(), ArmError> {
360 use crate::architecture::arm::core::armv7m::{Demcr, Dhcsr};
361
362 let mut demcr = Demcr(core.read_word_32(Demcr::get_mmio_address())?);
364 demcr.set_vc_corereset(true);
365
366 core.write_word_32(Demcr::get_mmio_address(), demcr.into())?;
367
368 let _ = core.read_word_32(Dhcsr::get_mmio_address())?;
370
371 Ok(())
372}
373
374fn cortex_m_reset_system(interface: &mut dyn ArmMemoryInterface) -> Result<(), ArmError> {
376 use crate::architecture::arm::core::armv7m::Aircr;
377
378 let mut aircr = Aircr(0);
379 aircr.vectkey();
380 aircr.set_sysresetreq(true);
381
382 interface.write_word_32(Aircr::get_mmio_address(), aircr.into())?;
383
384 cortex_m_wait_for_reset(interface)
385}
386
387pub(crate) fn cortex_m_wait_for_reset(
389 interface: &mut dyn ArmMemoryInterface,
390) -> Result<(), ArmError> {
391 use crate::architecture::arm::core::armv7m::Dhcsr;
392
393 let start = Instant::now();
394
395 while start.elapsed() < Duration::from_millis(600) {
398 let dhcsr = match interface.read_word_32(Dhcsr::get_mmio_address()) {
399 Ok(val) => Dhcsr(val),
404 Err(ArmError::AccessPort {
405 source: AccessPortError::RegisterRead { source, .. },
406 ..
407 }) => {
408 if let Some(ArmError::Dap(DapError::NoAcknowledge)) =
409 source.downcast_ref::<ArmError>()
410 {
411 if let Ok(probe) = interface.get_arm_debug_interface() {
414 probe.reinitialize()?;
415 }
416 }
417 continue;
418 }
419 Err(err) => return Err(err),
420 };
421 if !dhcsr.s_reset_st() {
422 return Ok(());
423 }
424 }
425
426 Err(ArmError::Timeout)
427}
428
429pub trait ArmDebugSequence: Send + Sync + Debug {
433 #[doc(alias = "ResetHardwareAssert")]
438 fn reset_hardware_assert(&self, interface: &mut dyn DapProbe) -> Result<(), ArmError> {
439 let mut n_reset = Pins(0);
440 n_reset.set_nreset(true);
441
442 let _ = interface.swj_pins(0, n_reset.0 as u32, 0)?;
443
444 Ok(())
445 }
446
447 #[doc(alias = "ResetHardwareDeassert")]
459 fn reset_hardware_deassert(
460 &self,
461 probe: &mut dyn ArmDebugInterface,
462 _default_ap: &FullyQualifiedApAddress,
463 ) -> Result<(), ArmError> {
464 let mut n_reset = Pins(0);
465 n_reset.set_nreset(true);
466 let n_reset = n_reset.0 as u32;
467
468 let can_read_pins = probe.swj_pins(n_reset, n_reset, 0)? != 0xffff_ffff;
469
470 if can_read_pins {
471 let start = Instant::now();
472
473 loop {
474 if Pins(probe.swj_pins(n_reset, n_reset, 0)? as u8).nreset() {
475 return Ok(());
476 }
477 if start.elapsed() >= Duration::from_secs(1) {
478 return Err(ArmError::Timeout);
479 }
480 thread::sleep(Duration::from_millis(100));
481 }
482 } else {
483 thread::sleep(Duration::from_millis(100));
484 Ok(())
485 }
486 }
487
488 #[doc(alias = "DebugPortSetup")]
500 fn debug_port_setup(
501 &self,
502 interface: &mut dyn DapProbe,
503 dp: DpAddress,
504 ) -> Result<(), ArmError> {
505 tracing::debug!("Setting up debug port {dp:x?}");
507
508 let mut has_dormant = matches!(dp, DpAddress::Multidrop(_));
513
514 fn alert_sequence(interface: &mut dyn DapProbe) -> Result<(), ArmError> {
515 tracing::trace!("Sending Selection Alert sequence");
516
517 interface.swj_sequence(8, 0xFF)?;
519
520 interface.swj_sequence(64, 0x86852D956209F392)?;
522
523 interface.swj_sequence(64, 0x19BC0EA2E3DDAFE9)?;
525
526 Ok(())
527 }
528
529 let mut result = Ok(());
532 const NUM_RETRIES: usize = 5;
533 for retry in 0..NUM_RETRIES {
534 swd_line_reset(interface, 0)?;
536
537 match interface.active_protocol() {
540 Some(WireProtocol::Jtag) => {
541 if has_dormant {
542 tracing::debug!("Select Dormant State (from SWD)");
543 interface.swj_sequence(16, 0xE3BC)?;
544
545 alert_sequence(interface)?;
547
548 interface.swj_sequence(12, 0x0A0)?;
550 } else {
551 interface.swj_sequence(16, 0xE73C)?;
553 }
554
555 interface.swj_sequence(6, 0x3F)?;
557
558 interface.jtag_sequence(1, false, 0x01)?;
560
561 interface.configure_jtag(false)?;
563 }
564 Some(WireProtocol::Swd) => {
565 if has_dormant {
566 tracing::debug!("SelectV1 Dormant State (from JTAG)");
568 interface.swj_sequence(31, 0x33BBBBBA)?;
569
570 alert_sequence(interface)?;
572
573 interface.swj_sequence(12, 0x1A0)?;
575 } else {
576 interface.swj_sequence(16, 0xE79E)?;
579
580 }
583 }
584 _ => {
585 return Err(ArmDebugSequenceError::SequenceSpecific(
586 "Cannot detect current protocol".into(),
587 )
588 .into());
589 }
590 }
591
592 result = self.debug_port_connect(interface, dp);
596 if result.is_ok() {
597 break;
599 }
600
601 if retry >= 1 {
604 has_dormant = true;
605 }
606 }
607
608 result
609 }
610
611 #[doc(alias = "DebugPortStart")]
616 fn debug_port_start(
617 &self,
618 interface: &mut dyn DapAccess,
619 dp: DpAddress,
620 ) -> Result<(), ArmError> {
621 interface.write_dp_register(dp, SelectV1(0))?;
622 let dpidr: DPIDR = interface.read_dp_register(dp)?;
623
624 let ctrl = interface.read_dp_register::<Ctrl>(dp)?;
626 let powered_down = if dpidr.version() == 0 || dpidr.designer() == 0 {
627 let mut abort = Abort(0);
629 abort.set_dapabort(true);
630 interface.write_dp_register(dp, abort)?;
631
632 interface.write_dp_register::<Ctrl>(dp, Ctrl(0x32))?;
634
635 true
637 } else {
638 let mut abort = Abort(0);
641 abort.set_dapabort(true);
642 abort.set_orunerrclr(true);
643 abort.set_wderrclr(true);
644 abort.set_stkerrclr(true);
645 abort.set_stkcmpclr(true);
646 interface.write_dp_register(dp, abort)?;
647
648 !(ctrl.csyspwrupack() && ctrl.cdbgpwrupack())
649 };
650
651 if powered_down {
652 tracing::info!("Debug port {dp:x?} is powered down, powering up");
653 let mut ctrl = Ctrl(0);
654 ctrl.set_cdbgpwrupreq(true);
655 ctrl.set_csyspwrupreq(true);
656 if !dpidr.min() {
657 ctrl.set_mask_lane(0b1111);
662 }
663
664 match interface
665 .write_dp_register(dp, ctrl.clone())
666 .and_then(|_| interface.flush())
667 {
668 Ok(()) => {}
669 Err(e @ ArmError::Dap(DapError::NoAcknowledge)) => {
670 let Some(probe) = interface.try_dap_probe_mut() else {
675 tracing::warn!(
676 "Power-up request returned NACK, but we don't have a DapProbe, so we can't reconnect"
677 );
678 return Err(e);
679 };
680 tracing::info!("Power-up request returned NACK, reconnecting");
681 self.debug_port_connect(probe, dp)?;
682 }
683 Err(e) => return Err(e),
684 }
685
686 let start = Instant::now();
687 loop {
688 let ctrl = interface.read_dp_register::<Ctrl>(dp)?;
689 if ctrl.csyspwrupack() && ctrl.cdbgpwrupack() {
690 break;
691 }
692 if start.elapsed() >= Duration::from_secs(1) {
693 return Err(ArmError::Timeout);
694 }
695 }
696
697 interface.write_dp_register(dp, ctrl)?;
705
706 let ctrl_reg: Ctrl = interface.read_dp_register(dp)?;
707 if !(ctrl_reg.csyspwrupack() && ctrl_reg.cdbgpwrupack()) {
708 tracing::error!("Debug power request failed");
709 return Err(DebugPortError::TargetPowerUpFailed.into());
710 }
711
712 }
715
716 Ok(())
717 }
718
719 #[doc(alias = "DebugCoreStart")]
724 fn debug_core_start(
725 &self,
726 interface: &mut dyn ArmDebugInterface,
727 core_ap: &FullyQualifiedApAddress,
728 core_type: CoreType,
729 debug_base: Option<u64>,
730 cti_base: Option<u64>,
731 ) -> Result<(), ArmError> {
732 let mut core = interface.memory_interface(core_ap)?;
733
734 match core_type {
736 CoreType::Armv7a => armv7a_core_start(&mut *core, debug_base),
737 CoreType::Armv8a => armv8a_core_start(&mut *core, debug_base, cti_base),
738 CoreType::Armv6m | CoreType::Armv7m | CoreType::Armv7em | CoreType::Armv8m => {
739 cortex_m_core_start(&mut *core)
740 }
741 _ => panic!("Logic inconsistency bug - non ARM core type passed {core_type:?}"),
742 }
743 }
744
745 #[doc(alias = "ResetCatchSet")]
751 fn reset_catch_set(
752 &self,
753 core: &mut dyn ArmMemoryInterface,
754 core_type: CoreType,
755 debug_base: Option<u64>,
756 ) -> Result<(), ArmError> {
757 match core_type {
759 CoreType::Armv7a => armv7a_reset_catch_set(core, debug_base),
760 CoreType::Armv8a => armv8a_reset_catch_set(core, debug_base),
761 CoreType::Armv6m | CoreType::Armv7m | CoreType::Armv7em | CoreType::Armv8m => {
762 cortex_m_reset_catch_set(core)
763 }
764 _ => panic!("Logic inconsistency bug - non ARM core type passed {core_type:?}"),
765 }
766 }
767
768 #[doc(alias = "ResetCatchClear")]
774 fn reset_catch_clear(
775 &self,
776 core: &mut dyn ArmMemoryInterface,
777 core_type: CoreType,
778 debug_base: Option<u64>,
779 ) -> Result<(), ArmError> {
780 match core_type {
782 CoreType::Armv7a => armv7a_reset_catch_clear(core, debug_base),
783 CoreType::Armv8a => armv8a_reset_catch_clear(core, debug_base),
784 CoreType::Armv6m | CoreType::Armv7m | CoreType::Armv7em | CoreType::Armv8m => {
785 cortex_m_reset_catch_clear(core)
786 }
787 _ => panic!("Logic inconsistency bug - non ARM core type passed {core_type:?}"),
788 }
789 }
790
791 fn trace_start(
801 &self,
802 interface: &mut dyn ArmDebugInterface,
803 components: &[CoresightComponent],
804 _sink: &TraceSink,
805 ) -> Result<(), ArmError> {
806 for trace_funnel in components
810 .iter()
811 .filter_map(|comp| comp.find_component(PeripheralType::TraceFunnel))
812 {
813 let mut funnel = TraceFunnel::new(interface, trace_funnel);
814 funnel.unlock()?;
815 funnel.enable_port(0xFF)?;
816 }
817
818 Ok(())
819 }
820
821 #[doc(alias = "ResetSystem")]
827 fn reset_system(
828 &self,
829 interface: &mut dyn ArmMemoryInterface,
830 core_type: CoreType,
831 debug_base: Option<u64>,
832 ) -> Result<(), ArmError> {
833 match core_type {
835 CoreType::Armv7a => armv7a_reset_system(interface, debug_base),
836 CoreType::Armv8a => armv8a_reset_system(interface, debug_base),
837 CoreType::Armv6m | CoreType::Armv7m | CoreType::Armv7em | CoreType::Armv8m => {
838 cortex_m_reset_system(interface)
839 }
840 _ => panic!("Logic inconsistency bug - non ARM core type passed {core_type:?}"),
841 }
842 }
843
844 #[doc(alias = "DebugDeviceUnlock")]
851 fn debug_device_unlock(
852 &self,
853 _interface: &mut dyn ArmDebugInterface,
854 _default_ap: &FullyQualifiedApAddress,
855 _permissions: &crate::Permissions,
856 ) -> Result<(), ArmError> {
857 tracing::debug!("debug_device_unlock - empty by default");
858 Ok(())
859 }
860
861 #[doc(alias = "RecoverSupportStart")]
866 fn recover_support_start(
867 &self,
868 _interface: &mut dyn ArmMemoryInterface,
869 ) -> Result<(), ArmError> {
870 Ok(())
872 }
873
874 #[doc(alias = "DebugCoreStop")]
880 fn debug_core_stop(
881 &self,
882 interface: &mut dyn ArmMemoryInterface,
883 core_type: CoreType,
884 ) -> Result<(), ArmError> {
885 if core_type.is_cortex_m() {
886 let mut dhcsr = Dhcsr(0);
889 dhcsr.enable_write();
890 interface.write_word_32(Dhcsr::get_mmio_address(), dhcsr.0)?;
891
892 interface.write_word_32(Demcr::get_mmio_address(), 0x0)?;
895 }
896
897 Ok(())
898 }
899
900 #[doc(alias = "DebugPortStop")]
906 fn debug_port_stop(&self, interface: &mut dyn DapProbe, dp: DpAddress) -> Result<(), ArmError> {
907 tracing::info!("Powering down debug port {dp:x?}");
908 interface.raw_write_register(SelectV1::ADDRESS.into(), 0)?;
910
911 interface.raw_write_register(Ctrl::ADDRESS.into(), 0)?;
913
914 let start = Instant::now();
916 loop {
917 let ctrl = interface.raw_read_register(Ctrl::ADDRESS.into())?;
918 let ctrl = Ctrl(ctrl);
919 if !(ctrl.csyspwrupack() || ctrl.cdbgpwrupack()) {
920 return Ok(());
921 }
922
923 if start.elapsed() >= Duration::from_secs(1) {
924 return Err(ArmError::Timeout);
925 }
926 }
927 }
928
929 #[tracing::instrument(level = "debug", skip_all)]
942 fn debug_port_connect(
943 &self,
944 interface: &mut dyn DapProbe,
945 dp: DpAddress,
946 ) -> Result<(), ArmError> {
947 match interface.active_protocol() {
948 Some(WireProtocol::Jtag) => {
949 tracing::debug!("JTAG: No special sequence needed to connect to debug port");
950 return Ok(());
951 }
952 Some(WireProtocol::Swd) => {
953 tracing::debug!("SWD: Connecting to debug port with address {:x?}", dp);
954 }
955 None => {
956 return Err(ArmDebugSequenceError::SequenceSpecific(
957 "Cannot detect current protocol".into(),
958 )
959 .into());
960 }
961 }
962
963 const RESET_RECOVERY_TIMEOUT: Duration = Duration::from_secs(1);
965 const RESET_RECOVERY_RETRY_INTERVAL: Duration = Duration::from_millis(5);
966
967 let guard = Instant::now();
970 let dpidr = loop {
971 swd_line_reset(interface, 3)?;
972
973 if let DpAddress::Multidrop(targetsel) = dp {
975 tracing::debug!("Writing targetsel {:#x}", targetsel);
978 let parity = targetsel.count_ones() % 2;
982 let data = ((parity as u64) << 45) | ((targetsel as u64) << 13) | 0x1f99;
983
984 interface.swj_sequence(6 * 8, data)?;
987 }
988
989 tracing::debug!("Reading DPIDR to enable SWD interface");
990
991 match interface.raw_read_register(RegisterAddress::DpRegister(DPIDR::ADDRESS)) {
993 Ok(x) => break x,
994 Err(z) => {
995 if guard.elapsed() > RESET_RECOVERY_TIMEOUT {
996 tracing::debug!("DPIDR didn't become readable within guard time");
997 return Err(z);
998 }
999 }
1000 }
1001
1002 std::thread::sleep(RESET_RECOVERY_RETRY_INTERVAL);
1004 };
1005 tracing::debug!(
1006 "DPIDR became readable after {}ms",
1007 guard.elapsed().as_millis()
1008 );
1009 tracing::debug!("Result of DPIDR read: {:#x?}", dpidr);
1010
1011 tracing::debug!("Clearing errors using ABORT register");
1012 let mut abort = Abort(0);
1013 abort.set_orunerrclr(true);
1014 abort.set_wderrclr(true);
1015 abort.set_stkerrclr(true);
1016 abort.set_stkcmpclr(true);
1017
1018 interface.raw_write_register(Abort::ADDRESS.into(), abort.0)?;
1020 interface.raw_flush()?;
1021
1022 if let DpAddress::Multidrop(targetsel) = dp {
1025 tracing::debug!("Checking TARGETID and DLPIDR match");
1026 interface.raw_write_register(SelectV1::ADDRESS.into(), 2)?;
1028
1029 let target_id = interface.raw_read_register(TARGETID::ADDRESS.into())?;
1030
1031 interface.raw_write_register(SelectV1::ADDRESS.into(), 3)?;
1033 let dlpidr = interface.raw_read_register(DLPIDR::ADDRESS.into())?;
1034
1035 const TARGETID_MASK: u32 = 0x0FFF_FFFF;
1036 const DLPIDR_MASK: u32 = 0xF000_0000;
1037
1038 let targetid_match = (target_id & TARGETID_MASK) == (targetsel & TARGETID_MASK);
1039 let dlpdir_match = (dlpidr & DLPIDR_MASK) == (targetsel & DLPIDR_MASK);
1040
1041 if !(targetid_match && dlpdir_match) {
1042 tracing::warn!(
1043 "Target ID and DLPIDR do not match, failed to select debug port. Target ID: {:#x?}, DLPIDR: {:#x?}",
1044 target_id,
1045 dlpidr
1046 );
1047 return Err(ArmError::Other(
1048 "Target ID and DLPIDR do not match, failed to select debug port".to_string(),
1049 ));
1050 }
1051 }
1052
1053 interface.raw_write_register(SelectV1::ADDRESS.into(), 0)?;
1054 let ctrl_stat = interface.raw_read_register(Ctrl::ADDRESS.into()).map(Ctrl);
1055
1056 match ctrl_stat {
1057 Ok(ctrl_stat) => {
1058 tracing::debug!("Result of CTRL/STAT read: {:?}", ctrl_stat);
1059 }
1060 Err(e) => {
1061 tracing::debug!("Failed to read CTRL/STAT: {:?}", e);
1064 }
1065 }
1066
1067 Ok(())
1068 }
1069
1070 fn prepare_running_on_ram(
1075 &self,
1076 vector_table_addr: u64,
1077 session: &mut Session,
1078 ) -> Result<(), crate::Error> {
1079 tracing::info!("Performing RAM flash start");
1080 const SP_MAIN_OFFSET: usize = 0;
1081 const RESET_VECTOR_OFFSET: usize = 1;
1082
1083 if session.list_cores().len() > 1 {
1084 return Err(crate::Error::NotImplemented(
1085 "multi-core ram flash start not implemented yet",
1086 ));
1087 }
1088
1089 let (_, core_type) = session.list_cores()[0];
1090 match core_type {
1091 CoreType::Armv7a | CoreType::Armv8a => {
1092 return Err(crate::Error::NotImplemented(
1093 "RAM flash not implemented for ARM Cortex-A",
1094 ));
1095 }
1096 CoreType::Armv6m | CoreType::Armv7m | CoreType::Armv7em | CoreType::Armv8m => {
1097 tracing::debug!("RAM flash start for Cortex-M single core target");
1098 let mut core = session.core(0)?;
1099 let vtor = Vtor(vector_table_addr as u32);
1102 let mut first_table_entries: [u32; 2] = [0; 2];
1103 core.read_32(vector_table_addr, &mut first_table_entries)?;
1104 core.write_core_reg(SP.id, first_table_entries[SP_MAIN_OFFSET])?;
1107 core.write_core_reg(PC.id, first_table_entries[RESET_VECTOR_OFFSET])?;
1110 core.write_word_32(Vtor::get_mmio_address(), vtor.0)?;
1111 }
1112 _ => {
1113 panic!("Logic inconsistency bug - non ARM core type passed {core_type:?}");
1114 }
1115 }
1116 Ok(())
1117 }
1118
1119 fn debug_erase_sequence(&self) -> Option<Arc<dyn DebugEraseSequence>> {
1121 None
1122 }
1123
1124 fn allowed_access_ports(&self) -> Vec<u8> {
1126 (0..=255).collect()
1127 }
1128}
1129
1130pub trait DebugEraseSequence: Send + Sync {
1132 fn erase_all(&self, _interface: &mut dyn ArmDebugInterface) -> Result<(), ArmError> {
1142 Err(ArmError::NotImplemented("erase_all"))
1143 }
1144}
1145
1146fn swd_line_reset(interface: &mut dyn DapProbe, swdio_low_cycles: u8) -> Result<(), ArmError> {
1150 assert!(swdio_low_cycles + 51 <= 64);
1151
1152 tracing::debug!("Performing SWD line reset");
1153 interface.swj_sequence(51 + swdio_low_cycles, 0x0007_FFFF_FFFF_FFFF)?;
1154
1155 Ok(())
1156}