1use crate::{
2 Core, CoreType, Error,
3 architecture::{
4 arm::{
5 ArmError, FullyQualifiedApAddress, SwoReader,
6 communication_interface::ArmDebugInterface,
7 component::{TraceSink, get_arm_components},
8 dp::DpAddress,
9 memory::CoresightComponent,
10 sequences::{ArmDebugSequence, DefaultArmSequence},
11 },
12 riscv::{
13 communication_interface::{
14 RiscvCommunicationInterface, RiscvDebugInterfaceState, RiscvError,
15 },
16 dtm::mem_ap_dtm::MemApDtm,
17 },
18 xtensa::communication_interface::{
19 XtensaCommunicationInterface, XtensaDebugInterfaceState, XtensaError,
20 },
21 },
22 config::{CoreExt, DebugSequence, RegistryError, Target, TargetSelector, registry::Registry},
23 core::{Architecture, CombinedCoreState},
24 probe::{
25 AttachMethod, DebugProbeError, Probe, ProbeCreationError, WireProtocol,
26 fake_probe::FakeProbe, list::Lister,
27 },
28};
29use std::ops::DerefMut;
30use std::{fmt, sync::Arc, time::Duration};
31
32#[derive(Debug)]
51pub struct Session {
52 target: Target,
53 interfaces: ArchitectureInterface,
54 cores: Vec<CombinedCoreState>,
55 configured_trace_sink: Option<TraceSink>,
56}
57
58#[derive(Default, Debug)]
66pub struct SessionConfig {
67 pub permissions: Permissions,
69 pub speed: Option<u32>,
71 pub protocol: Option<WireProtocol>,
73}
74
75enum JtagInterface {
76 Riscv(RiscvDebugInterfaceState),
77 Xtensa(XtensaDebugInterfaceState),
78 Unknown,
79}
80
81impl JtagInterface {
82 fn architecture(&self) -> Option<Architecture> {
84 match self {
85 JtagInterface::Riscv(_) => Some(Architecture::Riscv),
86 JtagInterface::Xtensa(_) => Some(Architecture::Xtensa),
87 JtagInterface::Unknown => None,
88 }
89 }
90}
91
92impl fmt::Debug for JtagInterface {
93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94 match self {
95 JtagInterface::Riscv(_) => f.write_str("Riscv(..)"),
96 JtagInterface::Xtensa(_) => f.write_str("Xtensa(..)"),
97 JtagInterface::Unknown => f.write_str("Unknown"),
98 }
99 }
100}
101
102enum ArchitectureInterface {
104 Arm(Box<dyn ArmDebugInterface + 'static>),
105 ArmWithRiscv {
107 arm: Box<dyn ArmDebugInterface + 'static>,
108 riscv_mem_ap_cores: Vec<Option<(FullyQualifiedApAddress, RiscvDebugInterfaceState)>>,
110 },
111 Jtag(Probe, Vec<JtagInterface>),
112}
113
114impl fmt::Debug for ArchitectureInterface {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 match self {
117 ArchitectureInterface::Arm(_) => f.write_str("ArchitectureInterface::Arm(..)"),
118 ArchitectureInterface::ArmWithRiscv { .. } => {
119 f.write_str("ArchitectureInterface::ArmWithRiscv { .. }")
120 }
121 ArchitectureInterface::Jtag(_, ifaces) => f
122 .debug_tuple("ArchitectureInterface::Jtag(..)")
123 .field(ifaces)
124 .finish(),
125 }
126 }
127}
128
129impl ArchitectureInterface {
130 fn attach<'probe, 'target: 'probe>(
131 &'probe mut self,
132 target: &'probe Target,
133 combined_state: &'probe mut CombinedCoreState,
134 ) -> Result<Core<'probe>, Error> {
135 match self {
136 ArchitectureInterface::Arm(interface) => combined_state.attach_arm(target, interface),
137 ArchitectureInterface::ArmWithRiscv {
138 arm,
139 riscv_mem_ap_cores,
140 } => {
141 let core_id = combined_state.id();
142 if let Some(Some((ap, state))) = riscv_mem_ap_cores.get_mut(core_id) {
143 let memory = arm.memory_interface(ap).map_err(Error::Arm)?;
144 let dtm = MemApDtm::new(memory);
145 let iface =
146 RiscvCommunicationInterface::new(Box::new(dtm), &mut state.interface_state);
147 combined_state.attach_riscv(target, iface)
148 } else {
149 combined_state.attach_arm(target, arm)
150 }
151 }
152 ArchitectureInterface::Jtag(probe, ifaces) => {
153 let idx = combined_state.jtag_tap_index();
154 if let Some(probe) = probe.try_as_jtag_probe() {
155 probe.select_target(idx)?;
156 }
157 match &mut ifaces[idx] {
158 JtagInterface::Riscv(state) => {
159 let factory = probe.try_get_riscv_interface_builder()?;
160 let iface = factory.attach_auto(target, state)?;
161 combined_state.attach_riscv(target, iface)
162 }
163 JtagInterface::Xtensa(state) => {
164 let iface = probe.try_get_xtensa_interface(state)?;
165 combined_state.attach_xtensa(target, iface)
166 }
167 JtagInterface::Unknown => {
168 unreachable!(
169 "Tried to attach to unknown interface {idx}. This should never happen."
170 )
171 }
172 }
173 }
174 }
175 }
176}
177
178impl Session {
179 pub(crate) fn new(
181 probe: Probe,
182 target: TargetSelector,
183 attach_method: AttachMethod,
184 permissions: Permissions,
185 registry: &Registry,
186 ) -> Result<Self, Error> {
187 let (probe, target) = get_target_from_selector(target, attach_method, probe, registry)?;
188
189 let cores = target
190 .cores
191 .iter()
192 .enumerate()
193 .map(|(id, core)| {
194 Core::create_state(
195 id,
196 core.core_access_options.clone(),
197 &target,
198 core.core_type,
199 )
200 })
201 .collect();
202
203 let mut session = if target.default_core().memory_ap().is_some() {
206 Self::attach_arm_debug_interface(probe, target, attach_method, permissions, cores)?
207 } else {
208 Self::attach_jtag(probe, target, attach_method, permissions, cores)?
209 };
210
211 session.clear_all_hw_breakpoints()?;
212
213 Ok(session)
214 }
215
216 fn attach_arm_debug_interface(
217 mut probe: Probe,
218 target: Target,
219 attach_method: AttachMethod,
220 permissions: Permissions,
221 cores: Vec<CombinedCoreState>,
222 ) -> Result<Self, Error> {
223 let default_core = target.default_core();
224
225 let default_memory_ap = default_core.memory_ap().ok_or_else(|| {
226 Error::Other(format!(
227 "Unable to connect to core {default_core:?}, no memory AP configured"
228 ))
229 })?;
230
231 let default_dp = default_memory_ap.dp();
232
233 let sequence_handle = match &target.debug_sequence {
236 DebugSequence::Arm(sequence) => sequence.clone(),
237 DebugSequence::Riscv(_) => DefaultArmSequence::create(),
238 _ => unreachable!("DAP path only used for ARM or RISC-V-over-mem-AP targets"),
239 };
240
241 if AttachMethod::UnderReset == attach_method {
242 let _span = tracing::debug_span!("Asserting hardware reset").entered();
243
244 if let Some(dap_probe) = probe.try_as_dap_probe() {
245 sequence_handle.reset_hardware_assert(dap_probe)?;
246 } else {
247 tracing::info!(
248 "Custom reset sequences are not supported on {}.",
249 probe.get_name()
250 );
251 tracing::info!("Falling back to standard probe reset.");
252 probe.target_reset_assert()?;
253 }
254 }
255
256 if let Some(jtag) = target.jtag.as_ref()
257 && let Some(scan_chain) = jtag.scan_chain.clone()
258 && let Some(probe) = probe.try_as_jtag_probe()
259 {
260 probe.set_expected_scan_chain(&scan_chain)?;
261 }
262
263 probe.attach_to_unspecified()?;
264 if probe.protocol() == Some(WireProtocol::Jtag)
265 && let Some(probe) = probe.try_as_jtag_probe()
266 && let Ok(chain) = probe.scan_chain()
267 && !chain.is_empty()
268 {
269 for core in &cores {
270 probe.select_target(core.jtag_tap_index())?;
271 }
272 }
273
274 let mut interface = probe
275 .try_into_arm_debug_interface(sequence_handle.clone())
276 .map_err(|(_, err)| err)?;
277
278 interface.select_debug_port(default_dp)?;
279
280 let unlock_span = tracing::debug_span!("debug_device_unlock").entered();
281
282 let unlock_res =
284 sequence_handle.debug_device_unlock(&mut *interface, &default_memory_ap, &permissions);
285 drop(unlock_span);
286
287 match unlock_res {
288 Ok(()) => (),
289 Err(ArmError::ReAttachRequired) => {
291 Self::reattach_arm_interface(&mut interface, &sequence_handle)?;
292 }
293 Err(e) => return Err(Error::Arm(e)),
294 }
295
296 if attach_method == AttachMethod::UnderReset {
297 {
298 for core in &cores {
299 if core.is_arm_core() {
300 core.arm_reset_catch_set(&mut *interface)?;
301 }
302 }
303
304 let reset_hardware_deassert =
305 tracing::debug_span!("reset_hardware_deassert").entered();
306
307 if let Err(e) =
309 sequence_handle.reset_hardware_deassert(&mut *interface, &default_memory_ap)
310 {
311 if matches!(e, ArmError::Timeout) {
312 tracing::warn!(
313 "Timeout while deasserting hardware reset pin. This indicates that the reset pin is not properly connected. Please check your hardware setup."
314 );
315 }
316
317 return Err(e.into());
318 }
319 drop(reset_hardware_deassert);
320 }
321
322 for core in &cores {
325 if core.is_arm_core() {
326 core.enable_arm_debug(&mut *interface)?;
327 }
328 }
329
330 let interfaces = Self::build_arm_interfaces(&target, interface)?;
331 let mut session = Session {
332 target,
333 interfaces,
334 cores,
335 configured_trace_sink: None,
336 };
337
338 {
339 for core_id in 0..session.cores.len() {
345 if !session.cores[core_id].is_arm_core() {
346 continue;
347 }
348 let mut core = session
349 .core(core_id)
350 .inspect_err(|e| tracing::error!("Unable to get core {core_id}: {e}"))?;
351
352 core.wait_for_core_halted(Duration::from_millis(100))
353 .inspect_err(|e| {
354 tracing::error!("Unable to wait for {core_id} halted: {e}")
355 })?;
356
357 core.reset_catch_clear().inspect_err(|e| {
358 tracing::error!("Unable to clear catch for {core_id} : {e}")
359 })?;
360 }
361 }
362
363 Ok(session)
364 } else {
365 for core in &cores {
367 if core.is_arm_core() {
368 core.enable_arm_debug(&mut *interface)?;
369 }
370 }
371
372 let interfaces = Self::build_arm_interfaces(&target, interface)?;
373 Ok(Session {
374 target,
375 interfaces,
376 cores,
377 configured_trace_sink: None,
378 })
379 }
380 }
381
382 fn build_arm_interfaces(
385 target: &Target,
386 interface: Box<dyn ArmDebugInterface + 'static>,
387 ) -> Result<ArchitectureInterface, Error> {
388 use probe_rs_target::Architecture;
389 let mut riscv_mem_ap_cores: Vec<
390 Option<(FullyQualifiedApAddress, RiscvDebugInterfaceState)>,
391 > = target
392 .cores
393 .iter()
394 .map(|core| {
395 if core.core_type.architecture() == Architecture::Riscv {
396 core.memory_ap()
397 .map(|ap| (ap, RiscvDebugInterfaceState::new(Box::new(()))))
398 } else {
399 None
400 }
401 })
402 .collect();
403 let has_riscv_mem_ap = riscv_mem_ap_cores.iter().any(Option::is_some);
404 if has_riscv_mem_ap {
405 let mut arm = interface;
406 for (ap, state) in riscv_mem_ap_cores.iter_mut().flatten() {
407 let memory = arm.memory_interface(ap).map_err(Error::Arm)?;
408 let dtm = MemApDtm::new(memory);
409 let mut iface =
410 RiscvCommunicationInterface::new(Box::new(dtm), &mut state.interface_state);
411 iface.enter_debug_mode().map_err(Error::Riscv)?;
412 }
413 Ok(ArchitectureInterface::ArmWithRiscv {
414 arm,
415 riscv_mem_ap_cores,
416 })
417 } else {
418 Ok(ArchitectureInterface::Arm(interface))
419 }
420 }
421
422 fn attach_jtag(
423 mut probe: Probe,
424 target: Target,
425 _attach_method: AttachMethod,
426 _permissions: Permissions,
427 cores: Vec<CombinedCoreState>,
428 ) -> Result<Self, Error> {
429 if let Some(jtag) = target.jtag.as_ref()
433 && let Some(scan_chain) = jtag.scan_chain.clone()
434 && let Some(probe) = probe.try_as_jtag_probe()
435 {
436 if jtag.force_scan_chain {
437 probe.set_scan_chain(&scan_chain)?;
441 } else {
442 probe.set_expected_scan_chain(&scan_chain)?;
443 }
444 }
445
446 probe.attach_to_unspecified()?;
447 if let Some(probe) = probe.try_as_jtag_probe()
448 && let Ok(chain) = probe.scan_chain()
449 && !chain.is_empty()
450 {
451 for core in &cores {
452 probe.select_target(core.jtag_tap_index())?;
453 }
454 }
455
456 let highest_idx = cores.iter().map(|c| c.jtag_tap_index()).max().unwrap_or(0);
463 let tap_count = if let Some(probe) = probe.try_as_jtag_probe() {
464 match probe.scan_chain() {
465 Ok(scan_chain) => scan_chain.len().max(highest_idx + 1),
466 Err(_) => highest_idx + 1,
467 }
468 } else {
469 highest_idx + 1
470 };
471 let mut interfaces = std::iter::repeat_with(|| JtagInterface::Unknown)
472 .take(tap_count)
473 .collect::<Vec<_>>();
474
475 for core in cores.iter() {
478 let iface_idx = core.jtag_tap_index();
479
480 let core_arch = core.core_type().architecture();
481
482 if let Some(debug_arch) = interfaces[iface_idx].architecture() {
483 if core_arch == debug_arch {
484 continue;
486 }
487 return Err(Error::Probe(DebugProbeError::Other(format!(
488 "{core_arch:?} core can not be mixed with a {debug_arch:?} debug module.",
489 ))));
490 }
491
492 interfaces[iface_idx] = match core_arch {
493 Architecture::Riscv => {
494 let factory = probe.try_get_riscv_interface_builder()?;
495 let mut state = factory.create_state();
496 {
497 let mut interface = factory.attach_auto(&target, &mut state)?;
498 interface.enter_debug_mode()?;
499 }
500
501 JtagInterface::Riscv(state)
502 }
503 Architecture::Xtensa => JtagInterface::Xtensa(XtensaDebugInterfaceState::default()),
504 _ => {
505 return Err(Error::Probe(DebugProbeError::Other(format!(
506 "Unsupported core architecture {core_arch:?}",
507 ))));
508 }
509 };
510 }
511
512 let interfaces = ArchitectureInterface::Jtag(probe, interfaces);
513
514 let mut session = Session {
515 target,
516 interfaces,
517 cores,
518 configured_trace_sink: None,
519 };
520
521 match session.target.debug_sequence.clone() {
523 DebugSequence::Xtensa(_) => {}
524
525 DebugSequence::Riscv(sequence) => {
526 for core_id in 0..session.cores.len() {
527 sequence.on_connect(&mut session.get_riscv_interface(core_id)?)?;
528 }
529 }
530 _ => unreachable!("Other architectures should have already been handled"),
531 };
532
533 Ok(session)
534 }
535
536 fn auto_probe(session_config: &SessionConfig) -> Result<Probe, Error> {
538 let lister = Lister::new();
540
541 let probes = lister.list_all();
542
543 let mut probe = probes
545 .first()
546 .ok_or(Error::Probe(DebugProbeError::ProbeCouldNotBeCreated(
547 ProbeCreationError::NotFound,
548 )))?
549 .open()?;
550
551 if let Some(speed) = session_config.speed {
553 probe.set_speed(speed)?;
554 }
555
556 if let Some(protocol) = session_config.protocol {
557 probe.select_protocol(protocol)?;
558 }
559 Ok(probe)
560 }
561
562 #[tracing::instrument(skip(target))]
564 pub fn auto_attach(
565 target: impl Into<TargetSelector>,
566 session_config: SessionConfig,
567 ) -> Result<Session, Error> {
568 Self::auto_probe(&session_config)?.attach(target, session_config.permissions)
570 }
571
572 #[tracing::instrument(skip(target, registry))]
575 pub fn auto_attach_with_registry(
576 target: impl Into<TargetSelector>,
577 session_config: SessionConfig,
578 registry: &Registry,
579 ) -> Result<Session, Error> {
580 Self::auto_probe(&session_config)?.attach_with_registry(
582 target,
583 session_config.permissions,
584 registry,
585 )
586 }
587
588 pub fn list_cores(&self) -> Vec<(usize, CoreType)> {
590 self.cores.iter().map(|t| (t.id(), t.core_type())).collect()
591 }
592
593 pub fn halted_access<R>(
597 &mut self,
598 f: impl FnOnce(&mut Self) -> Result<R, Error>,
599 ) -> Result<R, Error> {
600 let mut resume_state = vec![];
601 for (core, _) in self.list_cores() {
602 let mut c = match self.core(core) {
603 Err(Error::CoreDisabled(_)) => continue,
604 other => other?,
605 };
606 if c.core_halted()? {
607 tracing::info!("Core {core} already halted");
608 } else {
609 tracing::info!("Halting core {core}...");
610 resume_state.push(core);
611 c.halt(Duration::from_millis(100))?;
612 }
613 }
614
615 let r = f(self);
616
617 for core in resume_state {
618 tracing::debug!("Resuming core...");
619 self.core(core)?.run()?;
620 }
621
622 r
623 }
624
625 fn interface_idx(&self, core: usize) -> Result<usize, Error> {
626 self.cores
627 .get(core)
628 .map(|c| c.jtag_tap_index())
629 .ok_or(Error::CoreNotFound(core))
630 }
631
632 #[tracing::instrument(level = "trace", skip(self), name = "attach_to_core")]
649 pub fn core(&mut self, core_index: usize) -> Result<Core<'_>, Error> {
650 let combined_state = self
651 .cores
652 .get_mut(core_index)
653 .ok_or(Error::CoreNotFound(core_index))?;
654
655 self.interfaces
656 .attach(&self.target, combined_state)
657 .map_err(|e| {
658 if matches!(
659 e,
660 Error::Arm(ArmError::CoreDisabled)
661 | Error::Xtensa(XtensaError::CoreDisabled)
662 | Error::Riscv(RiscvError::HartUnavailable),
663 ) {
664 Error::CoreDisabled(core_index)
669 } else {
670 e
671 }
672 })
673 }
674
675 #[tracing::instrument(skip(self))]
680 pub fn read_trace_data(&mut self) -> Result<Vec<u8>, ArmError> {
681 let sink = self
682 .configured_trace_sink
683 .as_ref()
684 .ok_or(ArmError::TracingUnconfigured)?;
685
686 match sink {
687 TraceSink::Swo(_) => {
688 let interface = self.get_arm_interface()?;
689 interface.read_swo()
690 }
691
692 TraceSink::Tpiu(_) => {
693 panic!("Probe-rs does not yet support reading parallel trace ports");
694 }
695
696 TraceSink::TraceMemory => {
697 let components = self.get_arm_components(DpAddress::Default)?;
698 let interface = self.get_arm_interface()?;
699 crate::architecture::arm::component::read_trace_memory(interface, &components)
700 }
701 }
702 }
703
704 pub fn swo_reader(&mut self) -> Result<SwoReader<'_>, Error> {
713 let interface = self.get_arm_interface()?;
714 Ok(SwoReader::new(interface))
715 }
716
717 pub fn get_arm_interface(&mut self) -> Result<&mut dyn ArmDebugInterface, ArmError> {
719 let interface = match &mut self.interfaces {
720 ArchitectureInterface::Arm(state) => state.deref_mut(),
721 ArchitectureInterface::ArmWithRiscv { arm, .. } => arm.deref_mut(),
722 ArchitectureInterface::Jtag(..) => return Err(ArmError::NoArmTarget),
723 };
724
725 Ok(interface)
726 }
727
728 pub fn get_riscv_interface(
730 &mut self,
731 core_id: usize,
732 ) -> Result<RiscvCommunicationInterface<'_>, Error> {
733 let tap_idx = self.interface_idx(core_id)?;
735 match &mut self.interfaces {
736 ArchitectureInterface::ArmWithRiscv {
737 arm,
738 riscv_mem_ap_cores,
739 } => {
740 if let Some(Some((ap, state))) = riscv_mem_ap_cores.get_mut(core_id) {
741 let memory = arm.memory_interface(ap).map_err(Error::Arm)?;
742 let dtm = MemApDtm::new(memory);
743 Ok(RiscvCommunicationInterface::new(
744 Box::new(dtm),
745 &mut state.interface_state,
746 ))
747 } else {
748 Err(RiscvError::NoRiscvTarget.into())
749 }
750 }
751 ArchitectureInterface::Jtag(probe, ifaces) => {
752 if let Some(probe) = probe.try_as_jtag_probe() {
753 probe.select_target(tap_idx)?;
754 }
755 if let JtagInterface::Riscv(state) = &mut ifaces[tap_idx] {
756 let factory = probe.try_get_riscv_interface_builder()?;
757 Ok(factory.attach_auto(&self.target, state)?)
758 } else {
759 Err(RiscvError::NoRiscvTarget.into())
760 }
761 }
762 ArchitectureInterface::Arm(_) => Err(RiscvError::NoRiscvTarget.into()),
763 }
764 }
765
766 pub fn get_xtensa_interface(
768 &mut self,
769 core_id: usize,
770 ) -> Result<XtensaCommunicationInterface<'_>, Error> {
771 let tap_idx = self.interface_idx(core_id)?;
772 if let ArchitectureInterface::Jtag(probe, ifaces) = &mut self.interfaces {
773 if let Some(probe) = probe.try_as_jtag_probe() {
774 probe.select_target(tap_idx)?;
775 }
776 if let JtagInterface::Xtensa(state) = &mut ifaces[tap_idx] {
777 return Ok(probe.try_get_xtensa_interface(state)?);
778 }
779 }
780 Err(XtensaError::NoXtensaTarget.into())
781 }
782
783 #[tracing::instrument(skip_all)]
784 fn reattach_arm_interface(
785 interface: &mut Box<dyn ArmDebugInterface>,
786 debug_sequence: &Arc<dyn ArmDebugSequence>,
787 ) -> Result<(), Error> {
788 use crate::probe::DebugProbe;
789
790 let current_dp = interface.current_debug_port();
791
792 let mut tmp_interface = Box::<FakeProbe>::default()
797 .try_get_arm_debug_interface(DefaultArmSequence::create())
798 .unwrap();
799
800 std::mem::swap(interface, &mut tmp_interface);
801
802 tracing::debug!("Re-attaching Probe");
803 let mut probe = tmp_interface.close();
804 probe.detach()?;
805 probe.attach_to_unspecified()?;
806
807 let mut new_interface = probe
808 .try_into_arm_debug_interface(debug_sequence.clone())
809 .map_err(|(_, err)| err)?;
810
811 if let Some(current_dp) = current_dp {
812 new_interface.select_debug_port(current_dp)?;
813 }
814 std::mem::swap(interface, &mut new_interface);
816
817 tracing::debug!("Probe re-attached");
818 Ok(())
819 }
820
821 pub fn prepare_running_on_ram(
823 &mut self,
824 vector_table_addr: u64,
825 core_id: usize,
826 ) -> Result<(), crate::Error> {
827 match self.target.debug_sequence.clone() {
828 DebugSequence::Arm(arm_debug_sequence) => {
829 arm_debug_sequence.prepare_running_on_ram(self, vector_table_addr, core_id)
830 }
831 DebugSequence::Riscv(riscv_debug_sequence) => {
832 riscv_debug_sequence.prepare_running_on_ram(self, vector_table_addr, core_id)
833 }
834 DebugSequence::Xtensa(xtensa_debug_sequence) => {
835 xtensa_debug_sequence.prepare_running_on_ram(self, vector_table_addr, core_id)
836 }
837 }
838 }
839
840 pub fn has_sequence_erase_all(&self) -> bool {
842 match &self.target.debug_sequence {
843 DebugSequence::Arm(seq) => seq.debug_erase_sequence().is_some(),
844 _ => false,
846 }
847 }
848
849 pub fn sequence_erase_all(&mut self) -> Result<(), Error> {
858 let interface_ref = match &mut self.interfaces {
859 ArchitectureInterface::Arm(i) => i.deref_mut(),
860 ArchitectureInterface::ArmWithRiscv { arm, .. } => arm.deref_mut(),
861 ArchitectureInterface::Jtag(..) => {
862 return Err(Error::NotImplemented(
863 "Debug Erase Sequence is not implemented for non-ARM targets.",
864 ));
865 }
866 };
867
868 let DebugSequence::Arm(ref debug_sequence) = self.target.debug_sequence else {
869 unreachable!("This should never happen. Please file a bug if it does.");
870 };
871
872 let erase_sequence = debug_sequence
873 .debug_erase_sequence()
874 .ok_or(Error::Arm(ArmError::NotImplemented("Debug Erase Sequence")))?;
875
876 tracing::info!("Trying Debug Erase Sequence");
877 let erase_result = erase_sequence.erase_all(interface_ref);
878
879 match erase_result {
880 Ok(()) => (),
881 Err(ArmError::ReAttachRequired) => match &mut self.interfaces {
883 ArchitectureInterface::Arm(interface) => {
884 Self::reattach_arm_interface(interface, debug_sequence)?;
885 for core_state in &self.cores {
886 core_state.enable_arm_debug(interface.deref_mut())?;
887 }
888 }
889 ArchitectureInterface::ArmWithRiscv { arm, .. } => {
890 Self::reattach_arm_interface(arm, debug_sequence)?;
891 for core_state in &self.cores {
892 core_state.enable_arm_debug(arm.deref_mut())?;
893 }
894 }
895 ArchitectureInterface::Jtag(..) => {}
896 },
897 Err(e) => return Err(Error::Arm(e)),
898 }
899 tracing::info!("Device Erased Successfully");
900 Ok(())
901 }
902
903 pub fn get_arm_components(
908 &mut self,
909 dp: DpAddress,
910 ) -> Result<Vec<CoresightComponent>, ArmError> {
911 let interface = self.get_arm_interface()?;
912
913 get_arm_components(interface, dp)
914 }
915
916 pub fn target(&self) -> &Target {
918 &self.target
919 }
920
921 pub fn setup_tracing(
923 &mut self,
924 core_index: usize,
925 destination: TraceSink,
926 ) -> Result<(), Error> {
927 {
929 let mut core = self.core(core_index)?;
930 crate::architecture::arm::component::enable_tracing(&mut core)?;
931 }
932
933 let sequence_handle = match &self.target.debug_sequence {
934 DebugSequence::Arm(sequence) => sequence.clone(),
935 _ => unreachable!("Mismatch between architecture and sequence type!"),
936 };
937
938 let components = self.get_arm_components(DpAddress::Default)?;
939 let interface = self.get_arm_interface()?;
940
941 match destination {
944 TraceSink::Swo(ref config) => {
945 interface.enable_swo(config)?;
946 }
947 TraceSink::Tpiu(ref config) => {
948 interface.enable_swo(config)?;
949 }
950 TraceSink::TraceMemory => {}
951 }
952
953 sequence_handle.trace_start(interface, &components, &destination)?;
954 crate::architecture::arm::component::setup_tracing(interface, &components, &destination)?;
955
956 self.configured_trace_sink.replace(destination);
957
958 Ok(())
959 }
960
961 #[tracing::instrument(skip(self))]
963 pub fn disable_swv(&mut self, core_index: usize) -> Result<(), Error> {
964 crate::architecture::arm::component::disable_swv(&mut self.core(core_index)?)
965 }
966
967 pub fn add_swv_data_trace(&mut self, unit: usize, address: u32) -> Result<(), ArmError> {
969 let components = self.get_arm_components(DpAddress::Default)?;
970 let interface = self.get_arm_interface()?;
971 crate::architecture::arm::component::add_swv_data_trace(
972 interface,
973 &components,
974 unit,
975 address,
976 )
977 }
978
979 pub fn remove_swv_data_trace(&mut self, unit: usize) -> Result<(), ArmError> {
981 let components = self.get_arm_components(DpAddress::Default)?;
982 let interface = self.get_arm_interface()?;
983 crate::architecture::arm::component::remove_swv_data_trace(interface, &components, unit)
984 }
985
986 pub fn architecture(&self) -> Architecture {
990 match &self.interfaces {
991 ArchitectureInterface::Arm(_) => Architecture::Arm,
992 ArchitectureInterface::ArmWithRiscv { .. } => {
993 self.target.cores[0].core_type.architecture()
994 }
995 ArchitectureInterface::Jtag(_, ifaces) => {
996 if let JtagInterface::Riscv(_) = &ifaces[0] {
997 Architecture::Riscv
998 } else {
999 Architecture::Xtensa
1000 }
1001 }
1002 }
1003 }
1004
1005 pub fn clear_all_hw_breakpoints(&mut self) -> Result<(), Error> {
1007 self.halted_access(|session| {
1008 { 0..session.cores.len() }.try_for_each(|core| {
1009 tracing::info!("Clearing breakpoints for core {core}");
1010
1011 match session.core(core) {
1012 Ok(mut core) => core.clear_all_hw_breakpoints(),
1013 Err(Error::CoreDisabled(_)) => Ok(()),
1014 Err(Error::Riscv(
1015 crate::architecture::riscv::communication_interface::RiscvError::Timeout,
1016 )) => {
1017 tracing::warn!(
1018 "Core {core} attach or breakpoint clear timed out, skipping"
1019 );
1020 Ok(())
1021 }
1022 Err(err) => Err(err),
1023 }
1024 })
1025 })
1026 }
1027
1028 pub fn resume_all_cores(&mut self) -> Result<(), Error> {
1030 for core_id in 0..self.cores.len() {
1032 match self.core(core_id) {
1033 Ok(mut core) => {
1034 if core.core_halted()? {
1035 core.run()?;
1036 }
1037 }
1038 Err(Error::CoreDisabled(i)) => tracing::debug!("Core {i} is disabled"),
1039 Err(error) => return Err(error),
1040 }
1041 }
1042
1043 Ok(())
1044 }
1045}
1046
1047const _: fn() = || {
1049 fn assert_impl_all<T: ?Sized + Send>() {}
1050
1051 assert_impl_all::<Session>();
1052};
1053
1054impl Drop for Session {
1055 #[tracing::instrument(name = "session_drop", skip(self))]
1056 fn drop(&mut self) {
1057 if let Err(err) = self.clear_all_hw_breakpoints() {
1058 tracing::warn!(
1059 "Could not clear all hardware breakpoints: {:?}",
1060 anyhow::anyhow!(err)
1061 );
1062 }
1063
1064 if let Err(err) = { 0..self.cores.len() }.try_for_each(|core| match self.core(core) {
1066 Ok(mut core) => core.debug_core_stop(),
1067 Err(Error::CoreDisabled(_)) => Ok(()),
1068 Err(err) => Err(err),
1069 }) {
1070 tracing::warn!("Failed to deconfigure device during shutdown: {:?}", err);
1071 }
1072 }
1073}
1074
1075fn get_target_from_selector(
1081 target: TargetSelector,
1082 attach_method: AttachMethod,
1083 mut probe: Probe,
1084 registry: &Registry,
1085) -> Result<(Probe, Target), Error> {
1086 let target = match target {
1087 TargetSelector::Unspecified(name) => registry.get_target_by_name(name)?,
1088 TargetSelector::Specified(target) => target,
1089 TargetSelector::Auto => {
1090 if AttachMethod::UnderReset == attach_method {
1094 probe.target_reset_assert()?;
1095 }
1096 probe.attach_to_unspecified()?;
1097
1098 let (returned_probe, found_target) =
1099 crate::vendor::auto_determine_target(registry, probe)?;
1100 probe = returned_probe;
1101
1102 if AttachMethod::UnderReset == attach_method {
1103 probe.target_reset_deassert()?;
1105 }
1106
1107 if let Some(target) = found_target {
1108 target
1109 } else {
1110 return Err(Error::ChipNotFound(RegistryError::ChipAutodetectFailed));
1111 }
1112 }
1113 };
1114
1115 Ok((probe, target))
1116}
1117
1118#[non_exhaustive]
1129#[derive(Debug, Clone, Default)]
1130pub struct Permissions {
1131 erase_all: bool,
1133}
1134
1135impl Permissions {
1136 pub fn new() -> Self {
1138 Self::default()
1139 }
1140
1141 #[must_use]
1147 pub fn allow_erase_all(self) -> Self {
1148 Self {
1149 erase_all: true,
1150 ..self
1151 }
1152 }
1153
1154 pub(crate) fn erase_all(&self) -> Result<(), MissingPermissions> {
1155 if self.erase_all {
1156 Ok(())
1157 } else {
1158 Err(MissingPermissions("erase_all".into()))
1159 }
1160 }
1161}
1162
1163#[derive(Debug, Clone, thiserror::Error)]
1164#[error("An operation could not be performed because it lacked the permission to do so: {0}")]
1165pub struct MissingPermissions(pub String);