1use crate::{
2 CoreType, Endian, InstructionSet, MemoryInterface, Target,
3 architecture::{
4 arm::sequences::ArmDebugSequence, riscv::sequences::RiscvDebugSequence,
5 xtensa::sequences::XtensaDebugSequence,
6 },
7 config::DebugSequence,
8 error::{BreakpointError, Error},
9 memory::CoreMemoryInterface,
10};
11pub use probe_rs_target::{Architecture, CoreAccessOptions};
12use probe_rs_target::{
13 ArmCoreAccessOptions, MemoryRegion, RiscvCoreAccessOptions, XtensaCoreAccessOptions,
14};
15use std::{sync::Arc, time::Duration};
16
17pub mod core_state;
18pub mod core_status;
19pub mod dump;
20pub mod memory_mapped_registers;
21pub mod registers;
22
23pub use core_state::*;
24pub use core_status::*;
25pub use memory_mapped_registers::MemoryMappedRegister;
26pub use registers::*;
27
28#[derive(Debug, Clone)]
30pub struct CoreInformation {
31 pub pc: u64,
33}
34
35pub trait CoreInterface: MemoryInterface {
37 fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error>;
40
41 fn core_halted(&mut self) -> Result<bool, Error>;
44
45 fn status(&mut self) -> Result<CoreStatus, Error>;
47
48 fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error>;
51
52 fn run(&mut self) -> Result<(), Error>;
54
55 fn reset(&mut self) -> Result<(), Error>;
60
61 fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error>;
66
67 fn step(&mut self) -> Result<CoreInformation, Error>;
69
70 fn read_core_reg(
72 &mut self,
73 address: registers::RegisterId,
74 ) -> Result<registers::RegisterValue, Error>;
75
76 fn write_core_reg(
78 &mut self,
79 address: registers::RegisterId,
80 value: registers::RegisterValue,
81 ) -> Result<(), Error>;
82
83 fn available_breakpoint_units(&mut self) -> Result<u32, Error>;
85
86 fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error>;
90
91 fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error>;
93
94 fn set_hw_breakpoint(&mut self, unit_index: usize, addr: u64) -> Result<(), Error>;
96
97 fn clear_hw_breakpoint(&mut self, unit_index: usize) -> Result<(), Error>;
99
100 fn registers(&self) -> &'static registers::CoreRegisters;
102
103 fn program_counter(&self) -> &'static CoreRegister;
105
106 fn frame_pointer(&self) -> &'static CoreRegister;
108
109 fn stack_pointer(&self) -> &'static CoreRegister;
111
112 fn return_address(&self) -> &'static CoreRegister;
114
115 fn hw_breakpoints_enabled(&self) -> bool;
117
118 fn debug_on_sw_breakpoint(&mut self, _enabled: bool) -> Result<(), Error> {
120 Ok(())
122 }
123
124 fn architecture(&self) -> Architecture;
126
127 fn core_type(&self) -> CoreType;
129
130 fn instruction_set(&mut self) -> Result<InstructionSet, Error>;
134
135 fn endianness(&mut self) -> Result<Endian, Error> {
138 Ok(Endian::Little)
140 }
141
142 fn fpu_support(&mut self) -> Result<bool, Error>;
146
147 fn floating_point_register_count(&mut self) -> Result<usize, Error>;
151
152 fn reset_catch_set(&mut self) -> Result<(), Error>;
158
159 fn reset_catch_clear(&mut self) -> Result<(), Error>;
163
164 fn debug_core_stop(&mut self) -> Result<(), Error>;
166
167 fn on_session_stop(&mut self) -> Result<(), Error> {
169 Ok(())
170 }
171
172 fn enable_vector_catch(&mut self, _condition: VectorCatchCondition) -> Result<(), Error> {
174 Err(Error::NotImplemented("vector catch"))
175 }
176
177 fn disable_vector_catch(&mut self, _condition: VectorCatchCondition) -> Result<(), Error> {
179 Err(Error::NotImplemented("vector catch"))
180 }
181
182 fn is_64_bit(&self) -> bool {
184 false
185 }
186}
187
188pub struct Core<'probe> {
195 id: usize,
196 name: &'probe str,
197 target: &'probe Target,
198
199 inner: Box<dyn CoreInterface + 'probe>,
200}
201
202impl CoreMemoryInterface for Core<'_> {
203 type ErrorType = Error;
204
205 fn memory(&self) -> &dyn MemoryInterface<Self::ErrorType> {
206 self.inner.as_ref()
207 }
208
209 fn memory_mut(&mut self) -> &mut dyn MemoryInterface<Self::ErrorType> {
210 self.inner.as_mut()
211 }
212}
213
214impl<'probe> Core<'probe> {
215 pub fn inner_mut(&mut self) -> &mut Box<dyn CoreInterface + 'probe> {
217 &mut self.inner
218 }
219
220 pub(crate) fn new(
222 id: usize,
223 name: &'probe str,
224 target: &'probe Target,
225 core: impl CoreInterface + 'probe,
226 ) -> Core<'probe> {
227 Self {
228 id,
229 name,
230 target,
231 inner: Box::new(core),
232 }
233 }
234
235 pub fn memory_regions(&self) -> impl Iterator<Item = &MemoryRegion> {
237 self.target
238 .memory_map
239 .iter()
240 .filter(|r| r.cores().iter().any(|m| m == self.name))
241 }
242
243 pub fn target(&self) -> &Target {
245 self.target
246 }
247
248 pub(crate) fn create_state(
250 id: usize,
251 options: CoreAccessOptions,
252 target: &Target,
253 core_type: CoreType,
254 ) -> CombinedCoreState {
255 CombinedCoreState {
256 id,
257 core_state: CoreState::new(ResolvedCoreOptions::new(target, options)),
258 specific_state: SpecificCoreState::from_core_type(core_type),
259 }
260 }
261
262 pub fn id(&self) -> usize {
264 self.id
265 }
266
267 #[tracing::instrument(skip(self))]
270 pub fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
271 self.inner.wait_for_core_halted(timeout)
272 }
273
274 pub fn core_halted(&mut self) -> Result<bool, Error> {
277 self.inner.core_halted()
278 }
279
280 #[tracing::instrument(skip(self))]
283 pub fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
284 self.inner.halt(timeout)
285 }
286
287 #[tracing::instrument(skip(self))]
289 pub fn run(&mut self) -> Result<(), Error> {
290 self.inner.run()
291 }
292
293 #[tracing::instrument(skip(self))]
298 pub fn reset(&mut self) -> Result<(), Error> {
299 self.inner.reset()
300 }
301
302 #[tracing::instrument(skip(self))]
307 pub fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
308 self.inner.reset_and_halt(timeout)
309 }
310
311 #[tracing::instrument(skip(self))]
313 pub fn step(&mut self) -> Result<CoreInformation, Error> {
314 self.inner.step()
315 }
316
317 #[tracing::instrument(level = "trace", skip(self))]
319 pub fn status(&mut self) -> Result<CoreStatus, Error> {
320 self.inner.status()
321 }
322
323 #[tracing::instrument(skip(self, address), fields(address))]
338 pub fn read_core_reg<T>(
339 &mut self,
340 address: impl Into<registers::RegisterId>,
341 ) -> Result<T, Error>
342 where
343 registers::RegisterValue: TryInto<T>,
344 Result<T, <registers::RegisterValue as TryInto<T>>::Error>: RegisterValueResultExt<T>,
345 {
346 let address = address.into();
347
348 tracing::Span::current().record("address", format!("{address:?}"));
349
350 let value = self.inner.read_core_reg(address)?;
351
352 value.try_into().into_crate_error()
353 }
354
355 #[tracing::instrument(skip(self, address, value))]
361 pub fn write_core_reg<T>(
362 &mut self,
363 address: impl Into<registers::RegisterId>,
364 value: T,
365 ) -> Result<(), Error>
366 where
367 T: Into<registers::RegisterValue>,
368 {
369 let address = address.into();
370
371 self.inner.write_core_reg(address, value.into())
372 }
373
374 pub fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
376 self.inner.available_breakpoint_units()
377 }
378
379 fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error> {
381 self.inner.enable_breakpoints(state)
382 }
383
384 #[tracing::instrument(skip(self))]
386 pub fn debug_on_sw_breakpoint(&mut self, enabled: bool) -> Result<(), Error> {
387 self.inner.debug_on_sw_breakpoint(enabled)
388 }
389
390 pub fn registers(&self) -> &'static registers::CoreRegisters {
392 self.inner.registers()
393 }
394
395 pub fn program_counter(&self) -> &'static CoreRegister {
397 self.inner.program_counter()
398 }
399
400 pub fn frame_pointer(&self) -> &'static CoreRegister {
402 self.inner.frame_pointer()
403 }
404
405 pub fn stack_pointer(&self) -> &'static CoreRegister {
407 self.inner.stack_pointer()
408 }
409
410 pub fn return_address(&self) -> &'static CoreRegister {
412 self.inner.return_address()
413 }
414
415 #[tracing::instrument(skip(self))]
422 pub fn set_hw_breakpoint(&mut self, address: u64) -> Result<(), Error> {
423 if !self.inner.hw_breakpoints_enabled() {
424 self.enable_breakpoints(true)?;
425 }
426
427 let breakpoints = self.inner.hw_breakpoints()?;
429 let breakpoint_comparator_index =
430 match breakpoints.iter().position(|&bp| bp == Some(address)) {
431 Some(breakpoint_comparator_index) => breakpoint_comparator_index,
432 None => breakpoints
433 .iter()
434 .position(|bp| bp.is_none())
435 .ok_or_else(|| Error::Other("No available hardware breakpoints".to_string()))?,
436 };
437
438 tracing::debug!(
439 "Trying to set HW breakpoint #{} with comparator address {:#08x}",
440 breakpoint_comparator_index,
441 address
442 );
443
444 self.inner
446 .set_hw_breakpoint(breakpoint_comparator_index, address)
447 }
448
449 #[tracing::instrument(skip(self))]
456 pub fn set_hw_breakpoint_unit(&mut self, unit_index: usize, addr: u64) -> Result<(), Error> {
457 if !self.inner.hw_breakpoints_enabled() {
458 self.enable_breakpoints(true)?;
459 }
460
461 tracing::debug!(
462 "Trying to set HW breakpoint #{} with comparator address {:#08x}",
463 unit_index,
464 addr
465 );
466
467 self.inner.set_hw_breakpoint(unit_index, addr)
468 }
469
470 #[tracing::instrument(skip(self))]
474 pub fn clear_hw_breakpoint(&mut self, address: u64) -> Result<(), Error> {
475 let bp_position = self
476 .inner
477 .hw_breakpoints()?
478 .iter()
479 .position(|bp| *bp == Some(address));
480
481 tracing::debug!(
482 "Will clear HW breakpoint #{} with comparator address {:#08x}",
483 bp_position.unwrap_or(usize::MAX),
484 address
485 );
486
487 match bp_position {
488 Some(bp_position) => {
489 self.inner.clear_hw_breakpoint(bp_position)?;
490 Ok(())
491 }
492 None => Err(Error::BreakpointOperation(BreakpointError::NotFound(
493 address,
494 ))),
495 }
496 }
497
498 #[tracing::instrument(skip(self))]
504 pub fn clear_all_hw_breakpoints(&mut self) -> Result<(), Error> {
505 for breakpoint in (self.inner.hw_breakpoints()?).into_iter().flatten() {
506 self.clear_hw_breakpoint(breakpoint)?
507 }
508 Ok(())
509 }
510
511 pub fn architecture(&self) -> Architecture {
513 self.inner.architecture()
514 }
515
516 pub fn core_type(&self) -> CoreType {
518 self.inner.core_type()
519 }
520
521 pub fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
525 self.inner.instruction_set()
526 }
527
528 pub fn fpu_support(&mut self) -> Result<bool, Error> {
532 self.inner.fpu_support()
533 }
534
535 pub fn floating_point_register_count(&mut self) -> Result<usize, Error> {
538 self.inner.floating_point_register_count()
539 }
540
541 pub(crate) fn reset_catch_set(&mut self) -> Result<(), Error> {
542 self.inner.reset_catch_set()
543 }
544
545 pub(crate) fn reset_catch_clear(&mut self) -> Result<(), Error> {
546 self.inner.reset_catch_clear()
547 }
548
549 pub(crate) fn debug_core_stop(&mut self) -> Result<(), Error> {
550 self.inner.debug_core_stop()
551 }
552
553 pub fn enable_vector_catch(&mut self, condition: VectorCatchCondition) -> Result<(), Error> {
555 self.inner.enable_vector_catch(condition)
556 }
557
558 pub fn disable_vector_catch(&mut self, condition: VectorCatchCondition) -> Result<(), Error> {
560 self.inner.disable_vector_catch(condition)
561 }
562
563 pub fn is_64_bit(&self) -> bool {
565 self.inner.is_64_bit()
566 }
567}
568
569impl CoreInterface for Core<'_> {
570 fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
571 self.wait_for_core_halted(timeout)
572 }
573
574 fn core_halted(&mut self) -> Result<bool, Error> {
575 self.core_halted()
576 }
577
578 fn status(&mut self) -> Result<CoreStatus, Error> {
579 self.status()
580 }
581
582 fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
583 self.halt(timeout)
584 }
585
586 fn run(&mut self) -> Result<(), Error> {
587 self.run()
588 }
589
590 fn reset(&mut self) -> Result<(), Error> {
591 self.reset()
592 }
593
594 fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
595 self.reset_and_halt(timeout)
596 }
597
598 fn step(&mut self) -> Result<CoreInformation, Error> {
599 self.step()
600 }
601
602 fn read_core_reg(
603 &mut self,
604 address: registers::RegisterId,
605 ) -> Result<registers::RegisterValue, Error> {
606 self.read_core_reg(address)
607 }
608
609 fn write_core_reg(
610 &mut self,
611 address: registers::RegisterId,
612 value: registers::RegisterValue,
613 ) -> Result<(), Error> {
614 self.write_core_reg(address, value)
615 }
616
617 fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
618 self.available_breakpoint_units()
619 }
620
621 fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error> {
622 self.inner.hw_breakpoints()
623 }
624
625 fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error> {
626 self.enable_breakpoints(state)
627 }
628
629 fn set_hw_breakpoint(&mut self, unit_index: usize, addr: u64) -> Result<(), Error> {
630 self.set_hw_breakpoint_unit(unit_index, addr)
631 }
632
633 fn clear_hw_breakpoint(&mut self, unit_index: usize) -> Result<(), Error> {
634 self.inner.clear_hw_breakpoint(unit_index)?;
635 Ok(())
636 }
637
638 fn registers(&self) -> &'static registers::CoreRegisters {
639 self.registers()
640 }
641
642 fn program_counter(&self) -> &'static CoreRegister {
643 self.program_counter()
644 }
645
646 fn frame_pointer(&self) -> &'static CoreRegister {
647 self.frame_pointer()
648 }
649
650 fn stack_pointer(&self) -> &'static CoreRegister {
651 self.stack_pointer()
652 }
653
654 fn return_address(&self) -> &'static CoreRegister {
655 self.return_address()
656 }
657
658 fn hw_breakpoints_enabled(&self) -> bool {
659 self.inner.hw_breakpoints_enabled()
660 }
661
662 fn architecture(&self) -> Architecture {
663 self.architecture()
664 }
665
666 fn core_type(&self) -> CoreType {
667 self.core_type()
668 }
669
670 fn endianness(&mut self) -> Result<Endian, Error> {
673 self.inner.endianness()
674 }
675
676 fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
677 self.instruction_set()
678 }
679
680 fn fpu_support(&mut self) -> Result<bool, Error> {
681 self.fpu_support()
682 }
683
684 fn floating_point_register_count(&mut self) -> Result<usize, crate::error::Error> {
685 self.floating_point_register_count()
686 }
687
688 fn reset_catch_set(&mut self) -> Result<(), Error> {
689 self.reset_catch_set()
690 }
691
692 fn reset_catch_clear(&mut self) -> Result<(), Error> {
693 self.reset_catch_clear()
694 }
695
696 fn debug_core_stop(&mut self) -> Result<(), Error> {
697 self.debug_core_stop()
698 }
699
700 fn is_64_bit(&self) -> bool {
701 self.is_64_bit()
702 }
703}
704
705pub enum ResolvedCoreOptions {
706 Arm {
707 sequence: Arc<dyn ArmDebugSequence>,
708 options: ArmCoreAccessOptions,
709 },
710 Riscv {
711 sequence: Arc<dyn RiscvDebugSequence>,
712 options: RiscvCoreAccessOptions,
713 },
714 Xtensa {
715 sequence: Arc<dyn XtensaDebugSequence>,
716 options: XtensaCoreAccessOptions,
717 },
718}
719
720impl ResolvedCoreOptions {
721 fn new(target: &Target, options: CoreAccessOptions) -> Self {
722 match (options, target.debug_sequence.clone()) {
723 (CoreAccessOptions::Arm(options), DebugSequence::Arm(sequence)) => {
724 Self::Arm { sequence, options }
725 }
726 (CoreAccessOptions::Riscv(options), DebugSequence::Riscv(sequence)) => {
727 Self::Riscv { sequence, options }
728 }
729 (CoreAccessOptions::Xtensa(options), DebugSequence::Xtensa(sequence)) => {
730 Self::Xtensa { sequence, options }
731 }
732 _ => unreachable!(
733 "Mismatch between core kind and access options. This is a bug, please report it."
734 ),
735 }
736 }
737
738 fn jtag_tap_index(&self) -> usize {
739 match self {
740 Self::Arm { options, .. } => options.jtag_tap.unwrap_or(0),
741 Self::Riscv { options, .. } => options.jtag_tap.unwrap_or(0),
742 Self::Xtensa { options, .. } => options.jtag_tap.unwrap_or(0),
743 }
744 }
745}
746
747impl std::fmt::Debug for ResolvedCoreOptions {
748 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
749 match self {
750 Self::Arm { options, .. } => f
751 .debug_struct("Arm")
752 .field("sequence", &"<ArmDebugSequence>")
753 .field("options", options)
754 .finish(),
755 Self::Riscv { options, .. } => f
756 .debug_struct("Riscv")
757 .field("sequence", &"<RiscvDebugSequence>")
758 .field("options", options)
759 .finish(),
760 Self::Xtensa { options, .. } => f
761 .debug_struct("Xtensa")
762 .field("sequence", &"<XtensaDebugSequence>")
763 .field("options", options)
764 .finish(),
765 }
766 }
767}