probe_rs/architecture/arm/core/
armv7a.rs

1//! Register types and the core interface for armv7-a
2
3use super::{
4    CortexAState,
5    instructions::aarch32::{
6        build_ldc, build_mcr, build_mov, build_mrc, build_mrs, build_msr, build_stc, build_vmov,
7        build_vmrs,
8    },
9    registers::{
10        aarch32::{
11            AARCH32_CORE_REGISTERS, AARCH32_WITH_FP_16_CORE_REGISTERS,
12            AARCH32_WITH_FP_32_CORE_REGISTERS,
13        },
14        cortex_m::{FP, PC, RA, SP, XPSR},
15    },
16};
17use crate::{
18    Architecture, CoreInformation, CoreInterface, CoreRegister, CoreStatus, CoreType, Endian,
19    InstructionSet, MemoryInterface,
20    architecture::arm::{
21        ArmError, DapAccess, FullyQualifiedApAddress,
22        ap::{ApRegister, BD0, BD1, BD2, BD3, TAR, TAR2},
23        core::armv7a_debug_regs::*,
24        memory::ArmMemoryInterface,
25        sequences::ArmDebugSequence,
26    },
27    core::{CoreRegisters, MemoryMappedRegister, RegisterId, RegisterValue},
28    error::Error,
29    memory::{MemoryNotAlignedError, valid_32bit_address},
30};
31use std::{
32    mem::size_of,
33    sync::Arc,
34    time::{Duration, Instant},
35};
36use zerocopy::{FromBytes, IntoBytes};
37
38/// The maximum amount of time to wait for the core to respond
39const OPERATION_TIMEOUT: Duration = Duration::from_millis(250);
40
41/// Addresses for accessing debug registers when in banked mode
42struct BankedAccess<'a> {
43    /// Keep a reference to the `interface` to prevent anyone else
44    /// from changing the TAR while we're doing banked operations.
45    interface: &'a mut dyn DapAccess,
46    ap: FullyQualifiedApAddress,
47    dtrtx: u64,
48    itr: u64,
49    dscr: u64,
50    dtrrx: u64,
51}
52
53impl<'a> BankedAccess<'a> {
54    fn set_dtrtx(&mut self, value: u32) -> Result<(), ArmError> {
55        self.interface
56            .write_raw_ap_register(&self.ap, self.dtrtx, value)
57    }
58
59    fn dscr(&mut self) -> Result<Dbgdscr, ArmError> {
60        self.interface
61            .read_raw_ap_register(&self.ap, self.dscr)
62            .map(Dbgdscr::from)
63    }
64
65    fn set_dscr(&mut self, value: Dbgdscr) -> Result<(), ArmError> {
66        self.interface
67            .write_raw_ap_register(&self.ap, self.dscr, value.into())
68    }
69
70    fn set_itr(&mut self, value: u32) -> Result<(), ArmError> {
71        self.interface
72            .write_raw_ap_register(&self.ap, self.itr, value)
73    }
74
75    fn dtrrx(&mut self) -> Result<u32, ArmError> {
76        self.interface.read_raw_ap_register(&self.ap, self.dtrrx)
77    }
78
79    /// Operate the core in DCC Fast mode. For more information, see
80    /// ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
81    /// section C8.2.2.
82    ///
83    /// In this mode, writing to the ITR register does not immediately
84    /// trigger the instruction. Instead, it waits for a read from DTRRX
85    /// or a write to DTRTX. By placing an instruction with address-increment
86    /// in the pipeline this way, a load or store can be retriggered
87    /// repeatedly to quickly stream memory.
88    fn with_dcc_fast_mode<R>(
89        &mut self,
90        f: impl FnOnce(&mut Self) -> Result<R, ArmError>,
91    ) -> Result<R, ArmError> {
92        // Place DSCR in DCC Fast mode
93        let mut dscr = self.dscr()?;
94        dscr.set_extdccmode(2);
95        self.set_dscr(dscr)?;
96        let result = f(self);
97
98        // Return DSCR back to DCC Non Blocking mode
99        let mut dscr = self.dscr()?;
100        dscr.set_extdccmode(0);
101        self.set_dscr(dscr)?;
102
103        result
104    }
105}
106
107/// Errors for the ARMv7-A state machine
108#[derive(thiserror::Error, Debug)]
109pub enum Armv7aError {
110    /// Invalid register number
111    #[error("Register number {0} is not valid for ARMv7-A")]
112    InvalidRegisterNumber(u16),
113
114    /// Not halted
115    #[error("Core is running but operation requires it to be halted")]
116    NotHalted,
117
118    /// Data Abort occurred
119    #[error("A data abort occurred")]
120    DataAbort,
121}
122
123/// Interface for interacting with an ARMv7-A core
124pub struct Armv7a<'probe> {
125    memory: Box<dyn ArmMemoryInterface + 'probe>,
126
127    state: &'probe mut CortexAState,
128
129    base_address: u64,
130
131    sequence: Arc<dyn ArmDebugSequence>,
132
133    num_breakpoints: Option<u32>,
134
135    itr_enabled: bool,
136
137    endianness: Option<Endian>,
138}
139
140impl<'probe> Armv7a<'probe> {
141    pub(crate) fn new(
142        mut memory: Box<dyn ArmMemoryInterface + 'probe>,
143        state: &'probe mut CortexAState,
144        base_address: u64,
145        sequence: Arc<dyn ArmDebugSequence>,
146    ) -> Result<Self, Error> {
147        if !state.initialized() {
148            // determine current state
149            let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
150            let dbgdscr = Dbgdscr(memory.read_word_32(address)?);
151
152            tracing::debug!("State when connecting: {:x?}", dbgdscr);
153
154            let core_state = if dbgdscr.halted() {
155                let reason = dbgdscr.halt_reason();
156
157                tracing::debug!("Core was halted when connecting, reason: {:?}", reason);
158
159                CoreStatus::Halted(reason)
160            } else {
161                CoreStatus::Running
162            };
163
164            state.current_state = core_state;
165        }
166
167        let mut core = Self {
168            memory,
169            state,
170            base_address,
171            sequence,
172            num_breakpoints: None,
173            itr_enabled: false,
174            endianness: None,
175        };
176
177        if !core.state.initialized() {
178            core.reset_register_cache();
179            core.read_fp_reg_count()?;
180            core.state.initialize();
181        }
182
183        Ok(core)
184    }
185
186    fn read_fp_reg_count(&mut self) -> Result<(), Error> {
187        if self.state.fp_reg_count == 0 && matches!(self.state.current_state, CoreStatus::Halted(_))
188        {
189            self.prepare_r0_for_clobber()?;
190
191            // Check CP10/CP11 in CPACR which indicate whether the FPU is enabled;
192            // if it's disabled (both 0) then don't try to read MVFR0 as it would fault.
193            let instruction = build_mrc(15, 0, 0, 1, 0, 2);
194            self.execute_instruction(instruction)?;
195            let instruction = build_mcr(14, 0, 0, 0, 5, 0);
196            let cpacr = Cpacr(self.execute_instruction_with_result(instruction)?);
197            if cpacr.cp(10) == 0 || cpacr.cp(11) == 0 {
198                return Ok(());
199            }
200
201            // VMRS r0, MVFR0
202            let instruction = build_vmrs(0, 0b0111);
203            self.execute_instruction(instruction)?;
204
205            // Read from r0
206            let instruction = build_mcr(14, 0, 0, 0, 5, 0);
207            let vmrs = self.execute_instruction_with_result(instruction)?;
208
209            self.state.fp_reg_count = match vmrs & 0b111 {
210                0b001 => 16,
211                0b010 => 32,
212                _ => 0,
213            };
214        }
215
216        Ok(())
217    }
218
219    /// Execute an instruction
220    fn execute_instruction(&mut self, instruction: u32) -> Result<Dbgdscr, ArmError> {
221        if !self.state.current_state.is_halted() {
222            return Err(ArmError::CoreNotHalted);
223        }
224
225        // Enable ITR if needed
226        if !self.itr_enabled {
227            let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
228            let mut dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
229            dbgdscr.set_itren(true);
230
231            self.memory.write_word_32(address, dbgdscr.into())?;
232
233            self.itr_enabled = true;
234        }
235
236        execute_instruction(&mut *self.memory, self.base_address, instruction)
237    }
238
239    /// Execute an instruction on the CPU and return the result
240    fn execute_instruction_with_result(&mut self, instruction: u32) -> Result<u32, Error> {
241        // Run instruction
242        let mut dbgdscr = self.execute_instruction(instruction)?;
243
244        // Wait for TXfull
245        let start = Instant::now();
246        while !dbgdscr.txfull_l() {
247            let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
248            dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
249            // Check if we had any aborts, if so clear them and fail
250            check_and_clear_data_abort(&mut *self.memory, self.base_address, dbgdscr)?;
251            if start.elapsed() >= OPERATION_TIMEOUT {
252                return Err(Error::Timeout);
253            }
254        }
255
256        // Read result
257        let address = Dbgdtrtx::get_mmio_address_from_base(self.base_address)?;
258        let result = self.memory.read_word_32(address)?;
259
260        Ok(result)
261    }
262
263    fn execute_instruction_with_input(
264        &mut self,
265        instruction: u32,
266        value: u32,
267    ) -> Result<(), Error> {
268        // Move value
269        let address = Dbgdtrrx::get_mmio_address_from_base(self.base_address)?;
270        self.memory.write_word_32(address, value)?;
271
272        // Wait for RXfull
273        let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
274        let mut dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
275
276        let start = Instant::now();
277        while !dbgdscr.rxfull_l() {
278            dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
279            // Check if we had any aborts, if so clear them and fail
280            check_and_clear_data_abort(&mut *self.memory, self.base_address, dbgdscr)?;
281            if start.elapsed() >= OPERATION_TIMEOUT {
282                return Err(Error::Timeout);
283            }
284        }
285
286        // Run instruction
287        self.execute_instruction(instruction)?;
288
289        Ok(())
290    }
291
292    fn reset_register_cache(&mut self) {
293        self.state.register_cache = vec![None; 51];
294    }
295
296    /// Sync any updated registers back to the core
297    fn writeback_registers(&mut self) -> Result<(), Error> {
298        let writeback_iter = (17u16..=48).chain(15u16..=16).chain(0u16..=14);
299
300        for i in writeback_iter {
301            if let Some((val, writeback)) = self.state.register_cache[i as usize]
302                && writeback
303            {
304                match i {
305                    0..=14 => {
306                        let instruction = build_mrc(14, 0, i, 0, 5, 0);
307
308                        self.execute_instruction_with_input(instruction, val.try_into()?)?;
309                    }
310                    15 => {
311                        // Move val to r0
312                        let instruction = build_mrc(14, 0, 0, 0, 5, 0);
313
314                        self.execute_instruction_with_input(instruction, val.try_into()?)?;
315
316                        // Use `mov pc, r0` rather than `bx r0` because the `bx` instruction is
317                        // `UNPREDICTABLE` in the debug state (ARM Architecture Reference Manual,
318                        // ARMv7-A and ARMv7-R edition, C5.3: "Executing instructions in Debug state").
319                        let instruction = build_mov(15, 0);
320                        self.execute_instruction(instruction)?;
321                    }
322                    16 => {
323                        // msr cpsr_fsxc, r0
324                        let instruction = build_msr(0);
325                        self.execute_instruction_with_input(instruction, val.try_into()?)?;
326                    }
327                    17..=48 => {
328                        // Move value to r0, r1
329                        let value: u64 = val.try_into()?;
330                        let low_word = value as u32;
331                        let high_word = (value >> 32) as u32;
332
333                        let instruction = build_mrc(14, 0, 0, 0, 5, 0);
334                        self.execute_instruction_with_input(instruction, low_word)?;
335
336                        let instruction = build_mrc(14, 0, 1, 0, 5, 0);
337                        self.execute_instruction_with_input(instruction, high_word)?;
338
339                        // VMOV
340                        let instruction = build_vmov(0, 0, 1, i - 17);
341                        self.execute_instruction(instruction)?;
342                    }
343                    _ => {
344                        panic!("Logic missing for writeback of register {i}");
345                    }
346                }
347            }
348        }
349
350        self.reset_register_cache();
351
352        Ok(())
353    }
354
355    /// Save r0 if needed before it gets clobbered by instruction execution
356    fn prepare_r0_for_clobber(&mut self) -> Result<(), Error> {
357        self.prepare_for_clobber(0)
358    }
359
360    /// Save `r<n>` if needed before it gets clobbered by instruction execution
361    fn prepare_for_clobber(&mut self, reg: usize) -> Result<(), Error> {
362        if self.state.register_cache[reg].is_none() {
363            // cache reg since we're going to clobber it
364            let val: u32 = self.read_core_reg(RegisterId(reg as u16))?.try_into()?;
365
366            // Mark reg as needing writeback
367            self.state.register_cache[reg] = Some((val.into(), true));
368        }
369
370        Ok(())
371    }
372
373    fn set_r0(&mut self, value: u32) -> Result<(), Error> {
374        let instruction = build_mrc(14, 0, 0, 0, 5, 0);
375
376        self.execute_instruction_with_input(instruction, value)
377    }
378
379    fn set_core_status(&mut self, new_status: CoreStatus) {
380        super::update_core_status(&mut self.memory, &mut self.state.current_state, new_status);
381    }
382
383    pub(crate) fn halted_access<R>(
384        &mut self,
385        op: impl FnOnce(&mut Self) -> Result<R, Error>,
386    ) -> Result<R, Error> {
387        let was_running = !(self.state.current_state.is_halted() || self.status()?.is_halted());
388
389        if was_running {
390            self.halt(Duration::from_millis(100))?;
391        }
392
393        let result = op(self);
394
395        if was_running {
396            self.run()?
397        }
398
399        result
400    }
401
402    /// For greater performance, place DBGDTRTX, DBGDTRRX, DBGITR, and DBGDCSR
403    /// into the banked register window. This will allow us to directly access
404    /// these four values.
405    fn banked_access(&mut self) -> Result<BankedAccess<'_>, Error> {
406        let address = Dbgdtrtx::get_mmio_address_from_base(self.base_address)?;
407        let ap = self.memory.fully_qualified_address();
408        let is_64_bit = self.is_64_bit();
409        let interface = self.memory.get_arm_debug_interface()?;
410
411        if is_64_bit {
412            interface.write_raw_ap_register(&ap, TAR2::ADDRESS, (address >> 32) as u32)?;
413        }
414        interface.write_raw_ap_register(&ap, TAR::ADDRESS, address as u32)?;
415
416        Ok(BankedAccess {
417            interface,
418            ap,
419            dtrtx: BD0::ADDRESS,
420            itr: BD1::ADDRESS,
421            dscr: BD2::ADDRESS,
422            dtrrx: BD3::ADDRESS,
423        })
424    }
425}
426
427// These helper functions allow access to the ARMv7A core from Sequences.
428// They are also used by the `CoreInterface` to avoid code duplication.
429
430/// Request the core to halt. Does not wait for the core to halt.
431pub(crate) fn request_halt(
432    memory: &mut dyn ArmMemoryInterface,
433    base_address: u64,
434) -> Result<(), ArmError> {
435    let address = Dbgdrcr::get_mmio_address_from_base(base_address)?;
436    let mut value = Dbgdrcr(0);
437    value.set_hrq(true);
438
439    memory.write_word_32(address, value.into())?;
440    Ok(())
441}
442
443/// Start the core running. This does not flush any state.
444pub(crate) fn run(memory: &mut dyn ArmMemoryInterface, base_address: u64) -> Result<(), ArmError> {
445    let address = Dbgdrcr::get_mmio_address_from_base(base_address)?;
446    let mut value = Dbgdrcr(0);
447    value.set_rrq(true);
448
449    memory.write_word_32(address, value.into())?;
450
451    // Wait for ack
452    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
453
454    let start = Instant::now();
455    loop {
456        let dbgdscr = Dbgdscr(memory.read_word_32(address)?);
457        if dbgdscr.restarted() {
458            return Ok(());
459        }
460        if start.elapsed() > OPERATION_TIMEOUT {
461            return Err(ArmError::Timeout);
462        }
463    }
464}
465
466/// Wait for the core to be halted. If the core does not halt, then
467/// this will return `ArmError::Timeout`.
468pub(crate) fn wait_for_core_halted(
469    memory: &mut dyn ArmMemoryInterface,
470    base_address: u64,
471    timeout: Duration,
472) -> Result<(), ArmError> {
473    // Wait until halted state is active again.
474    let start = Instant::now();
475
476    while !core_halted(memory, base_address)? {
477        if start.elapsed() >= timeout {
478            return Err(ArmError::Timeout);
479        }
480        // Wait a bit before polling again.
481        std::thread::sleep(Duration::from_millis(1));
482    }
483
484    Ok(())
485}
486
487/// Return whether or not the core is halted.
488fn core_halted(memory: &mut dyn ArmMemoryInterface, base_address: u64) -> Result<bool, ArmError> {
489    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
490    let dbgdscr = Dbgdscr(memory.read_word_32(address)?);
491
492    Ok(dbgdscr.halted())
493}
494
495/// Set and enable a specific breakpoint. If the breakpoint is in use, it
496/// will be cleared.
497pub(crate) fn set_hw_breakpoint(
498    memory: &mut dyn ArmMemoryInterface,
499    base_address: u64,
500    bp_unit_index: usize,
501    addr: u32,
502) -> Result<(), ArmError> {
503    let bp_value_addr = Dbgbvr::get_mmio_address_from_base(base_address)?
504        + (bp_unit_index * size_of::<u32>()) as u64;
505    let bp_control_addr = Dbgbcr::get_mmio_address_from_base(base_address)?
506        + (bp_unit_index * size_of::<u32>()) as u64;
507    let mut bp_control = Dbgbcr(0);
508
509    // Breakpoint type - address match
510    bp_control.set_bt(0b0000);
511    // Match on all modes
512    bp_control.set_hmc(true);
513    bp_control.set_pmc(0b11);
514    // Match on all bytes
515    bp_control.set_bas(0b1111);
516    // Enable
517    bp_control.set_e(true);
518
519    memory.write_word_32(bp_value_addr, addr)?;
520    memory.write_word_32(bp_control_addr, bp_control.into())?;
521
522    Ok(())
523}
524
525/// If a specified breakpoint is set, disable it and clear it.
526pub(crate) fn clear_hw_breakpoint(
527    memory: &mut dyn ArmMemoryInterface,
528    base_address: u64,
529    bp_unit_index: usize,
530) -> Result<(), ArmError> {
531    let bp_value_addr = Dbgbvr::get_mmio_address_from_base(base_address)?
532        + (bp_unit_index * size_of::<u32>()) as u64;
533    let bp_control_addr = Dbgbcr::get_mmio_address_from_base(base_address)?
534        + (bp_unit_index * size_of::<u32>()) as u64;
535
536    memory.write_word_32(bp_value_addr, 0)?;
537    memory.write_word_32(bp_control_addr, 0)?;
538    Ok(())
539}
540
541/// Get a specific hardware breakpoint. If the breakpoint is not set, return `None`.
542pub(crate) fn get_hw_breakpoint(
543    memory: &mut dyn ArmMemoryInterface,
544    base_address: u64,
545    bp_unit_index: usize,
546) -> Result<Option<u32>, ArmError> {
547    let bp_value_addr = Dbgbvr::get_mmio_address_from_base(base_address)?
548        + (bp_unit_index * size_of::<u32>()) as u64;
549    let bp_value = memory.read_word_32(bp_value_addr)?;
550
551    let bp_control_addr = Dbgbcr::get_mmio_address_from_base(base_address)?
552        + (bp_unit_index * size_of::<u32>()) as u64;
553    let bp_control = Dbgbcr(memory.read_word_32(bp_control_addr)?);
554
555    Ok(if bp_control.e() { Some(bp_value) } else { None })
556}
557
558fn check_and_clear_data_abort(
559    memory: &mut dyn ArmMemoryInterface,
560    base_address: u64,
561    dbgdscr: Dbgdscr,
562) -> Result<(), ArmError> {
563    // Check if we had any aborts, if so clear them and fail
564    if dbgdscr.adabort_l() || dbgdscr.sdabort_l() || dbgdscr.und_l() {
565        let address = Dbgdrcr::get_mmio_address_from_base(base_address)?;
566        let mut dbgdrcr = Dbgdrcr(0);
567        dbgdrcr.set_cse(true);
568
569        memory.write_word_32(address, dbgdrcr.into())?;
570        return Err(ArmError::Armv7a(
571            crate::architecture::arm::armv7a::Armv7aError::DataAbort,
572        ));
573    }
574    Ok(())
575}
576
577/// Execute a single instruction.
578fn execute_instruction(
579    memory: &mut dyn ArmMemoryInterface,
580    base_address: u64,
581    instruction: u32,
582) -> Result<Dbgdscr, ArmError> {
583    // Run instruction
584    let address = Dbgitr::get_mmio_address_from_base(base_address)?;
585    memory.write_word_32(address, instruction)?;
586
587    // Wait for completion
588    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
589    let mut dbgdscr = Dbgdscr(memory.read_word_32(address)?);
590
591    let start = Instant::now();
592    while !dbgdscr.instrcoml_l() {
593        dbgdscr = Dbgdscr(memory.read_word_32(address)?);
594        // Check if we had any aborts, if so clear them and fail
595        check_and_clear_data_abort(memory, base_address, dbgdscr)?;
596        if start.elapsed() >= OPERATION_TIMEOUT {
597            return Err(ArmError::Timeout);
598        }
599    }
600
601    // Check if we had any aborts, if so clear them and fail
602    check_and_clear_data_abort(memory, base_address, dbgdscr)?;
603
604    Ok(dbgdscr)
605}
606
607/// Set the DBGDBGDTRRX register, which can be accessed with an
608/// `STC p14, c5, ..., #4` instruction.
609fn set_instruction_input(
610    memory: &mut dyn ArmMemoryInterface,
611    base_address: u64,
612    value: u32,
613) -> Result<(), ArmError> {
614    // Move value
615    let address = Dbgdtrrx::get_mmio_address_from_base(base_address)?;
616    memory.write_word_32(address, value)?;
617
618    // Wait for RXfull
619    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
620    let mut dbgdscr = Dbgdscr(memory.read_word_32(address)?);
621
622    let start = Instant::now();
623    while !dbgdscr.rxfull_l() {
624        dbgdscr = Dbgdscr(memory.read_word_32(address)?);
625        // Check if we had any aborts, if so clear them and fail
626        check_and_clear_data_abort(memory, base_address, dbgdscr)?;
627        if start.elapsed() >= OPERATION_TIMEOUT {
628            return Err(ArmError::Timeout);
629        }
630    }
631
632    Ok(())
633}
634
635/// Return the contents of DBGDTRTX, which is set as a result of an
636/// `LDC, p14, c5, ..., #4` instruction.
637fn get_instruction_result(
638    memory: &mut dyn ArmMemoryInterface,
639    base_address: u64,
640) -> Result<u32, ArmError> {
641    // Wait for TXfull
642    let address = Dbgdscr::get_mmio_address_from_base(base_address)?;
643    let start = Instant::now();
644    loop {
645        let dbgdscr = Dbgdscr(memory.read_word_32(address)?);
646        if dbgdscr.txfull_l() {
647            break;
648        }
649        if start.elapsed() > OPERATION_TIMEOUT {
650            return Err(ArmError::Timeout);
651        }
652    }
653
654    // Read result
655    let address = Dbgdtrtx::get_mmio_address_from_base(base_address)?;
656    memory.read_word_32(address)
657}
658
659/// Write a 32-bit value to main memory. Assumes that the core is halted. Note that
660/// this clobbers $r0.
661pub(crate) fn write_word_32(
662    memory: &mut dyn ArmMemoryInterface,
663    base_address: u64,
664    address: u32,
665    data: u32,
666) -> Result<(), ArmError> {
667    // Load address into r0
668    set_instruction_input(memory, base_address, address)?;
669    execute_instruction(memory, base_address, build_mrc(14, 0, 0, 0, 5, 0))?;
670
671    // Store the value in the DBGDBGDTRRX register and store that value into RAM.
672    // STC p14, c5, [r0], #4
673    set_instruction_input(memory, base_address, data)?;
674    execute_instruction(memory, base_address, build_stc(14, 5, 0, 4))?;
675    Ok(())
676}
677
678/// Read a 32-bit value from main memory. Assumes that the core is halted. Note that
679/// this clobbers $r0.
680pub(crate) fn read_word_32(
681    memory: &mut dyn ArmMemoryInterface,
682    base_address: u64,
683    address: u32,
684) -> Result<u32, ArmError> {
685    // Load address into r0
686    set_instruction_input(memory, base_address, address)?;
687    execute_instruction(memory, base_address, build_mrc(14, 0, 0, 0, 5, 0))?;
688
689    // Execute the instruction and store the result in the DBGDTRTX register.
690    // LDC p14, c5, [r0], #4
691    execute_instruction(memory, base_address, build_ldc(14, 5, 0, 4))?;
692    get_instruction_result(memory, base_address)
693}
694
695impl CoreInterface for Armv7a<'_> {
696    fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
697        wait_for_core_halted(&mut *self.memory, self.base_address, timeout).map_err(|e| e.into())
698    }
699
700    fn core_halted(&mut self) -> Result<bool, Error> {
701        core_halted(&mut *self.memory, self.base_address).map_err(|e| e.into())
702    }
703
704    fn status(&mut self) -> Result<crate::core::CoreStatus, Error> {
705        // determine current state
706        let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
707        let dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
708
709        if dbgdscr.halted() {
710            let reason = dbgdscr.halt_reason();
711
712            self.set_core_status(CoreStatus::Halted(reason));
713
714            self.read_fp_reg_count()?;
715
716            return Ok(CoreStatus::Halted(reason));
717        }
718        // Core is neither halted nor sleeping, so we assume it is running.
719        if self.state.current_state.is_halted() {
720            tracing::warn!("Core is running, but we expected it to be halted");
721        }
722
723        self.set_core_status(CoreStatus::Running);
724
725        Ok(CoreStatus::Running)
726    }
727
728    fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
729        if !matches!(self.state.current_state, CoreStatus::Halted(_)) {
730            request_halt(&mut *self.memory, self.base_address)?;
731            self.wait_for_core_halted(timeout)?;
732
733            // Reset our cached values
734            self.reset_register_cache();
735        }
736        // Update core status
737        let _ = self.status()?;
738
739        // try to read the program counter
740        let pc_value = self.read_core_reg(self.program_counter().into())?;
741
742        // get pc
743        Ok(CoreInformation {
744            pc: pc_value.try_into()?,
745        })
746    }
747
748    fn run(&mut self) -> Result<(), Error> {
749        if matches!(self.state.current_state, CoreStatus::Running) {
750            return Ok(());
751        }
752
753        // set writeback values
754        self.writeback_registers()?;
755
756        // Disable ITRen before sending RRQ (per ARM C5.7)
757        if self.itr_enabled {
758            let address = Dbgdscr::get_mmio_address_from_base(self.base_address)?;
759            let mut dbgdscr = Dbgdscr(self.memory.read_word_32(address)?);
760            dbgdscr.set_itren(false);
761            self.memory.write_word_32(address, dbgdscr.into())?;
762            self.itr_enabled = false;
763        }
764
765        run(&mut *self.memory, self.base_address)?;
766
767        // Recompute / verify current state
768        self.set_core_status(CoreStatus::Running);
769        let _ = self.status()?;
770
771        Ok(())
772    }
773
774    fn reset(&mut self) -> Result<(), Error> {
775        self.sequence.reset_system(
776            &mut *self.memory,
777            crate::CoreType::Armv7a,
778            Some(self.base_address),
779        )?;
780
781        // Reset our cached values
782        self.reset_register_cache();
783
784        // Recompute / verify current state
785        self.set_core_status(CoreStatus::Running);
786        let _ = self.status()?;
787
788        Ok(())
789    }
790
791    fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
792        self.sequence.reset_catch_set(
793            &mut *self.memory,
794            crate::CoreType::Armv7a,
795            Some(self.base_address),
796        )?;
797        self.sequence.reset_system(
798            &mut *self.memory,
799            crate::CoreType::Armv7a,
800            Some(self.base_address),
801        )?;
802
803        if !self.core_halted()? {
804            tracing::warn!("Core not halted after reset, platform-specific setup may be required");
805            tracing::warn!("Requesting halt anyway, but system may already be initialised");
806            let address = Dbgdrcr::get_mmio_address_from_base(self.base_address)?;
807            let mut value = Dbgdrcr(0);
808            value.set_hrq(true);
809            self.memory.write_word_32(address, value.into())?;
810        }
811
812        self.sequence.reset_catch_clear(
813            &mut *self.memory,
814            crate::CoreType::Armv7a,
815            Some(self.base_address),
816        )?;
817        self.wait_for_core_halted(timeout)?;
818
819        // Update core status
820        let _ = self.status()?;
821
822        // Reset our cached values
823        self.reset_register_cache();
824
825        // try to read the program counter
826        let pc_value = self.read_core_reg(self.program_counter().into())?;
827
828        // get pc
829        Ok(CoreInformation {
830            pc: pc_value.try_into()?,
831        })
832    }
833
834    fn step(&mut self) -> Result<CoreInformation, Error> {
835        // Save current breakpoint
836        let bp_unit_index = (self.available_breakpoint_units()? - 1) as usize;
837        let bp_value_addr = Dbgbvr::get_mmio_address_from_base(self.base_address)?
838            + (bp_unit_index * size_of::<u32>()) as u64;
839        let saved_bp_value = self.memory.read_word_32(bp_value_addr)?;
840
841        let bp_control_addr = Dbgbcr::get_mmio_address_from_base(self.base_address)?
842            + (bp_unit_index * size_of::<u32>()) as u64;
843        let saved_bp_control = self.memory.read_word_32(bp_control_addr)?;
844
845        // Set breakpoint for any change
846        let current_pc: u32 = self
847            .read_core_reg(self.program_counter().into())?
848            .try_into()?;
849        let mut bp_control = Dbgbcr(0);
850
851        // Breakpoint type - address mismatch
852        bp_control.set_bt(0b0100);
853        // Match on all modes
854        bp_control.set_hmc(true);
855        bp_control.set_pmc(0b11);
856        // Match on all bytes
857        bp_control.set_bas(0b1111);
858        // Enable
859        bp_control.set_e(true);
860
861        self.memory.write_word_32(bp_value_addr, current_pc)?;
862        self.memory
863            .write_word_32(bp_control_addr, bp_control.into())?;
864
865        // Resume
866        self.run()?;
867
868        // Wait for halt
869        self.wait_for_core_halted(Duration::from_millis(100))?;
870
871        // Reset breakpoint
872        self.memory.write_word_32(bp_value_addr, saved_bp_value)?;
873        self.memory
874            .write_word_32(bp_control_addr, saved_bp_control)?;
875
876        // try to read the program counter
877        let pc_value = self.read_core_reg(self.program_counter().into())?;
878
879        // get pc
880        Ok(CoreInformation {
881            pc: pc_value.try_into()?,
882        })
883    }
884
885    fn read_core_reg(&mut self, address: RegisterId) -> Result<RegisterValue, Error> {
886        let reg_num = address.0;
887
888        // check cache
889        if (reg_num as usize) < self.state.register_cache.len()
890            && let Some(cached_result) = self.state.register_cache[reg_num as usize]
891        {
892            return Ok(cached_result.0);
893        }
894
895        // Generate instruction to extract register
896        let result: Result<RegisterValue, Error> = match reg_num {
897            0..=14 => {
898                // r0-r14, valid
899                // MCR p14, 0, <Rd>, c0, c5, 0 ; Write DBGDTRTXint Register
900                let instruction = build_mcr(14, 0, reg_num, 0, 5, 0);
901
902                let val = self.execute_instruction_with_result(instruction)?;
903
904                Ok(val.into())
905            }
906            15 => {
907                // PC, must access via r0
908                self.prepare_r0_for_clobber()?;
909
910                // MOV r0, PC
911                let instruction = build_mov(0, 15);
912                self.execute_instruction(instruction)?;
913
914                // Read from r0
915                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
916                let pra_plus_offset = self.execute_instruction_with_result(instruction)?;
917
918                // PC returned is PC + 8
919                Ok((pra_plus_offset - 8).into())
920            }
921            16 => {
922                // CPSR, must access via r0
923                self.prepare_r0_for_clobber()?;
924
925                // MRS r0, CPSR
926                let instruction = build_mrs(0);
927                self.execute_instruction(instruction)?;
928
929                // Read from r0
930                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
931                let cpsr = self.execute_instruction_with_result(instruction)?;
932
933                Ok(cpsr.into())
934            }
935            17..=48 => {
936                // Access via r0, r1
937                self.prepare_for_clobber(0)?;
938                self.prepare_for_clobber(1)?;
939
940                // If FPEXC.EN = 0, then these registers aren't safe to access.  Read as zero
941                let fpexc: u32 = self.read_core_reg(50.into())?.try_into()?;
942                if (fpexc & (1 << 30)) == 0 {
943                    // Disabled
944                    return Ok(0u32.into());
945                }
946
947                // VMOV r0, r1, <reg>
948                let instruction = build_vmov(1, 0, 1, reg_num - 17);
949                self.execute_instruction(instruction)?;
950
951                // Read from r0
952                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
953                let mut value = self.execute_instruction_with_result(instruction)? as u64;
954
955                // Read from r1
956                let instruction = build_mcr(14, 0, 1, 0, 5, 0);
957                value |= (self.execute_instruction_with_result(instruction)? as u64) << 32;
958
959                Ok(value.into())
960            }
961            49 => {
962                // Access via r0
963                self.prepare_for_clobber(0)?;
964
965                // If FPEXC.EN = 0, then these registers aren't safe to access.  Read as zero
966                let fpexc: u32 = self.read_core_reg(50.into())?.try_into()?;
967                if (fpexc & (1 << 30)) == 0 {
968                    // Disabled
969                    return Ok(0u32.into());
970                }
971
972                // VMRS r0, FPSCR
973                let instruction = build_vmrs(0, 1);
974                self.execute_instruction(instruction)?;
975
976                // Read from r0
977                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
978                let value = self.execute_instruction_with_result(instruction)?;
979
980                Ok(value.into())
981            }
982            50 => {
983                // Access via r0
984                self.prepare_for_clobber(0)?;
985
986                // VMRS r0, FPEXC
987                let instruction = build_vmrs(0, 0b1000);
988                self.execute_instruction(instruction)?;
989
990                let instruction = build_mcr(14, 0, 0, 0, 5, 0);
991                let value = self.execute_instruction_with_result(instruction)?;
992
993                Ok(value.into())
994            }
995            _ => Err(Error::Arm(
996                Armv7aError::InvalidRegisterNumber(reg_num).into(),
997            )),
998        };
999
1000        if let Ok(value) = result {
1001            self.state.register_cache[reg_num as usize] = Some((value, false));
1002
1003            Ok(value)
1004        } else {
1005            Err(result.err().unwrap())
1006        }
1007    }
1008
1009    fn write_core_reg(&mut self, address: RegisterId, value: RegisterValue) -> Result<(), Error> {
1010        let reg_num = address.0;
1011
1012        if (reg_num as usize) >= self.state.register_cache.len() {
1013            return Err(Error::Arm(
1014                Armv7aError::InvalidRegisterNumber(reg_num).into(),
1015            ));
1016        }
1017        self.state.register_cache[reg_num as usize] = Some((value, true));
1018
1019        Ok(())
1020    }
1021
1022    fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
1023        if self.num_breakpoints.is_none() {
1024            let address = Dbgdidr::get_mmio_address_from_base(self.base_address)?;
1025            let dbgdidr = Dbgdidr(self.memory.read_word_32(address)?);
1026
1027            self.num_breakpoints = Some(dbgdidr.brps() + 1);
1028        }
1029        Ok(self.num_breakpoints.unwrap())
1030    }
1031
1032    /// See docs on the [`CoreInterface::hw_breakpoints`] trait
1033    fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error> {
1034        let mut breakpoints = vec![];
1035        let num_hw_breakpoints = self.available_breakpoint_units()? as usize;
1036
1037        for bp_unit_index in 0..num_hw_breakpoints {
1038            let bp_value_addr = Dbgbvr::get_mmio_address_from_base(self.base_address)?
1039                + (bp_unit_index * size_of::<u32>()) as u64;
1040            let bp_value = self.memory.read_word_32(bp_value_addr)?;
1041
1042            let bp_control_addr = Dbgbcr::get_mmio_address_from_base(self.base_address)?
1043                + (bp_unit_index * size_of::<u32>()) as u64;
1044            let bp_control = Dbgbcr(self.memory.read_word_32(bp_control_addr)?);
1045
1046            if bp_control.e() {
1047                breakpoints.push(Some(bp_value as u64));
1048            } else {
1049                breakpoints.push(None);
1050            }
1051        }
1052        Ok(breakpoints)
1053    }
1054
1055    fn enable_breakpoints(&mut self, _state: bool) -> Result<(), Error> {
1056        // Breakpoints are always on with v7-A
1057        Ok(())
1058    }
1059
1060    fn set_hw_breakpoint(&mut self, bp_unit_index: usize, addr: u64) -> Result<(), Error> {
1061        let addr = valid_32bit_address(addr)?;
1062        set_hw_breakpoint(&mut *self.memory, self.base_address, bp_unit_index, addr)?;
1063        Ok(())
1064    }
1065
1066    fn clear_hw_breakpoint(&mut self, bp_unit_index: usize) -> Result<(), Error> {
1067        clear_hw_breakpoint(&mut *self.memory, self.base_address, bp_unit_index)?;
1068        Ok(())
1069    }
1070
1071    fn registers(&self) -> &'static CoreRegisters {
1072        match self.state.fp_reg_count {
1073            16 => &AARCH32_WITH_FP_16_CORE_REGISTERS,
1074            32 => &AARCH32_WITH_FP_32_CORE_REGISTERS,
1075            _ => &AARCH32_CORE_REGISTERS,
1076        }
1077    }
1078
1079    fn program_counter(&self) -> &'static CoreRegister {
1080        &PC
1081    }
1082
1083    fn frame_pointer(&self) -> &'static CoreRegister {
1084        &FP
1085    }
1086
1087    fn stack_pointer(&self) -> &'static CoreRegister {
1088        &SP
1089    }
1090
1091    fn return_address(&self) -> &'static CoreRegister {
1092        &RA
1093    }
1094
1095    fn hw_breakpoints_enabled(&self) -> bool {
1096        true
1097    }
1098
1099    fn architecture(&self) -> Architecture {
1100        Architecture::Arm
1101    }
1102
1103    fn core_type(&self) -> CoreType {
1104        CoreType::Armv7a
1105    }
1106
1107    fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
1108        let cpsr: u32 = self.read_core_reg(XPSR.id())?.try_into()?;
1109
1110        // CPSR bit 5 - T - Thumb mode
1111        match (cpsr >> 5) & 1 {
1112            1 => Ok(InstructionSet::Thumb2),
1113            _ => Ok(InstructionSet::A32),
1114        }
1115    }
1116
1117    fn endianness(&mut self) -> Result<Endian, Error> {
1118        if let Some(endianness) = self.endianness {
1119            return Ok(endianness);
1120        }
1121        self.halted_access(|core| {
1122            let endianness = {
1123                let psr = TryInto::<u32>::try_into(core.read_core_reg(XPSR.id())?).unwrap();
1124                if psr & 1 << 9 == 0 {
1125                    Endian::Little
1126                } else {
1127                    Endian::Big
1128                }
1129            };
1130            core.endianness = Some(endianness);
1131            Ok(endianness)
1132        })
1133    }
1134
1135    fn fpu_support(&mut self) -> Result<bool, Error> {
1136        Ok(self.state.fp_reg_count != 0)
1137    }
1138
1139    fn floating_point_register_count(&mut self) -> Result<usize, Error> {
1140        Ok(self.state.fp_reg_count)
1141    }
1142
1143    #[tracing::instrument(skip(self))]
1144    fn reset_catch_set(&mut self) -> Result<(), Error> {
1145        self.halted_access(|core| {
1146            core.sequence.reset_catch_set(
1147                &mut *core.memory,
1148                CoreType::Armv7a,
1149                Some(core.base_address),
1150            )?;
1151            Ok(())
1152        })?;
1153        Ok(())
1154    }
1155
1156    #[tracing::instrument(skip(self))]
1157    fn reset_catch_clear(&mut self) -> Result<(), Error> {
1158        // Clear the reset_catch bit which was set earlier.
1159        self.halted_access(|core| {
1160            core.sequence.reset_catch_clear(
1161                &mut *core.memory,
1162                CoreType::Armv7a,
1163                Some(core.base_address),
1164            )?;
1165            Ok(())
1166        })?;
1167        Ok(())
1168    }
1169
1170    #[tracing::instrument(skip(self))]
1171    fn debug_core_stop(&mut self) -> Result<(), Error> {
1172        if matches!(self.state.current_state, CoreStatus::Halted(_)) {
1173            // We may have clobbered registers we wrote during debugging
1174            // Best effort attempt to put them back before we exit debug mode
1175            self.writeback_registers()?;
1176        }
1177
1178        self.sequence
1179            .debug_core_stop(&mut *self.memory, CoreType::Armv7a)?;
1180
1181        Ok(())
1182    }
1183}
1184
1185impl MemoryInterface for Armv7a<'_> {
1186    fn supports_native_64bit_access(&mut self) -> bool {
1187        false
1188    }
1189
1190    fn read_word_64(&mut self, address: u64) -> Result<u64, Error> {
1191        self.halted_access(|core| {
1192            #[repr(align(4))]
1193            struct AlignedBytes([u8; 8]);
1194            let mut bytes = AlignedBytes([0u8; 8]);
1195            core.read(address, &mut bytes.0)?;
1196            let ret = match core.endianness()? {
1197                Endian::Little => u64::from_le_bytes(bytes.0),
1198                Endian::Big => u64::from_be_bytes(bytes.0),
1199            };
1200
1201            Ok(ret)
1202        })
1203    }
1204
1205    fn read_word_32(&mut self, address: u64) -> Result<u32, Error> {
1206        self.halted_access(|core| {
1207            let address = valid_32bit_address(address)?;
1208
1209            // LDC p14, c5, [r0], #4
1210            let instr = build_ldc(14, 5, 0, 4);
1211
1212            // Save r0
1213            core.prepare_r0_for_clobber()?;
1214
1215            // Load r0 with the address to read from
1216            core.set_r0(address)?;
1217
1218            // Read memory from [r0]
1219            core.execute_instruction_with_result(instr)
1220        })
1221    }
1222
1223    fn read_word_16(&mut self, address: u64) -> Result<u16, Error> {
1224        self.halted_access(|core| {
1225            // Find the word this is in and its byte offset
1226            let mut byte_offset = address % 4;
1227            let word_start = address - byte_offset;
1228
1229            // Read the word
1230            let data = core.read_word_32(word_start)?;
1231
1232            // We do 32-bit reads, so we need to take a different field
1233            // if we're running on a big endian device.
1234            if Endian::Big == core.endianness()? {
1235                // TODO: This doesn't work accessing 16-bit words that are not aligned.
1236                if address & 1 != 0 {
1237                    return Err(Error::MemoryNotAligned(MemoryNotAlignedError {
1238                        address,
1239                        alignment: 2,
1240                    }));
1241                }
1242                byte_offset = 2 - byte_offset;
1243            }
1244
1245            // Return the 16-bit word
1246            Ok((data >> (byte_offset * 8)) as u16)
1247        })
1248    }
1249
1250    fn read_word_8(&mut self, address: u64) -> Result<u8, Error> {
1251        self.halted_access(|core| {
1252            // Find the word this is in and its byte offset
1253            let mut byte_offset = address % 4;
1254
1255            let word_start = address - byte_offset;
1256
1257            // Read the word
1258            let data = core.read_word_32(word_start)?;
1259
1260            // We do 32-bit reads, so we need to take a different field
1261            // if we're running on a big endian device.
1262            if Endian::Big == core.endianness()? {
1263                byte_offset = 3 - byte_offset;
1264            }
1265
1266            // Return the byte
1267            Ok(data.to_le_bytes()[byte_offset as usize])
1268        })
1269    }
1270
1271    fn read_64(&mut self, address: u64, data: &mut [u64]) -> Result<(), Error> {
1272        self.halted_access(|core| {
1273            for (i, word) in data.iter_mut().enumerate() {
1274                *word = core.read_word_64(address + ((i as u64) * 8))?;
1275            }
1276
1277            Ok(())
1278        })
1279    }
1280
1281    fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), Error> {
1282        self.halted_access(|core| {
1283            let count = data.len();
1284            if count > 2 {
1285                // Save r0
1286                core.prepare_r0_for_clobber()?;
1287                core.set_r0(valid_32bit_address(address)?)?;
1288
1289                let mut banked = core.banked_access()?;
1290
1291                // Ignore any errors encountered here -- they will set a Data Abort
1292                // which we will pick up in `check_and_clear_data_abort()`
1293                if banked
1294                    .with_dcc_fast_mode(|banked| {
1295                        // LDC p14, c5, [r0], #4
1296                        banked.set_itr(build_ldc(14, 5, 0, 4))?;
1297
1298                        // Throw away the first value, which is from a previous operation
1299                        let _ = banked.dtrrx()?;
1300
1301                        // Continually write the tx register, which will auto-increment.
1302                        // Because reads lag by one instruction, we need to break before
1303                        // we read the final value. If we don't we will end up reading one
1304                        // extra word past the buffer, which may end up outside valid RAM.
1305                        for word in data[0..count - 1].iter_mut() {
1306                            *word = banked.dtrrx()?;
1307                        }
1308                        Ok(())
1309                    })
1310                    .is_ok()
1311                {
1312                    // Grab the last value that we skipped during the main sequence.
1313                    // Ignore any errors here since they will generate an abort that
1314                    // will be caught below.
1315                    if let Ok(last) = banked.dtrrx()
1316                        && let Some(v) = data.last_mut()
1317                    {
1318                        *v = last;
1319                    }
1320                }
1321
1322                // Check if we had any aborts, if so clear them and fail
1323                let dscr = banked.dscr()?;
1324                check_and_clear_data_abort(&mut *core.memory, core.base_address, dscr)?;
1325            } else {
1326                for (i, word) in data.iter_mut().enumerate() {
1327                    *word = core.read_word_32(address + ((i as u64) * 4))?;
1328                }
1329            }
1330
1331            Ok(())
1332        })
1333    }
1334
1335    fn read_16(&mut self, address: u64, data: &mut [u16]) -> Result<(), Error> {
1336        self.halted_access(|core| {
1337            for (i, word) in data.iter_mut().enumerate() {
1338                *word = core.read_word_16(address + ((i as u64) * 2))?;
1339            }
1340
1341            Ok(())
1342        })
1343    }
1344
1345    fn read_8(&mut self, address: u64, data: &mut [u8]) -> Result<(), Error> {
1346        self.read(address, data)
1347    }
1348
1349    fn read(&mut self, address: u64, data: &mut [u8]) -> Result<(), Error> {
1350        self.halted_access(|core| {
1351            if address.is_multiple_of(4) && data.len().is_multiple_of(4) {
1352                // Avoid heap allocation and copy if we don't need it.
1353                if let Ok((aligned_buffer, _)) =
1354                    <[u32]>::mut_from_prefix_with_elems(data, data.len() / 4)
1355                {
1356                    core.read_32(address, aligned_buffer)?;
1357                } else {
1358                    let mut temporary_buffer = vec![0u32; data.len() / 4];
1359                    core.read_32(address, &mut temporary_buffer)?;
1360                    data.copy_from_slice(temporary_buffer.as_bytes());
1361                }
1362
1363                // We used 32-bit accesses, so swap the 32-bit values if necessary.
1364                if core.endianness()? == Endian::Big {
1365                    for word in data.chunks_exact_mut(4) {
1366                        word.reverse();
1367                    }
1368                }
1369            } else {
1370                let start_address = address & !3;
1371                let end_address = address + (data.len() as u64);
1372                let end_address = end_address + (4 - (end_address & 3));
1373                let start_extra_count = address as usize % 4;
1374                let mut buffer = vec![0u32; (end_address - start_address) as usize / 4];
1375                core.read_32(start_address, &mut buffer)?;
1376                if core.endianness()? == Endian::Big {
1377                    for word in buffer.iter_mut() {
1378                        *word = word.swap_bytes();
1379                    }
1380                }
1381                data.copy_from_slice(
1382                    &buffer.as_bytes()[start_extra_count..start_extra_count + data.len()],
1383                );
1384            }
1385            Ok(())
1386        })
1387    }
1388
1389    fn write_word_64(&mut self, address: u64, data: u64) -> Result<(), Error> {
1390        self.halted_access(|core| {
1391            let (data_low, data_high) = match core.endianness()? {
1392                Endian::Little => (data as u32, (data >> 32) as u32),
1393                Endian::Big => ((data >> 32) as u32, data as u32),
1394            };
1395
1396            core.write_32(address, &[data_low, data_high])
1397        })
1398    }
1399
1400    fn write_word_32(&mut self, address: u64, data: u32) -> Result<(), Error> {
1401        self.halted_access(|core| {
1402            let address = valid_32bit_address(address)?;
1403
1404            // STC p14, c5, [r0], #4
1405            let instr = build_stc(14, 5, 0, 4);
1406
1407            // Save r0
1408            core.prepare_r0_for_clobber()?;
1409
1410            // Load r0 with the address to write to
1411            core.set_r0(address)?;
1412
1413            // Write to [r0]
1414            core.execute_instruction_with_input(instr, data)
1415        })
1416    }
1417
1418    fn write_word_8(&mut self, address: u64, data: u8) -> Result<(), Error> {
1419        self.halted_access(|core| {
1420            // Find the word this is in and its byte offset
1421            let mut byte_offset = address % 4;
1422            let word_start = address - byte_offset;
1423
1424            // We do 32-bit reads and writes, so we need to take a different field
1425            // if we're running on a big endian device.
1426            if Endian::Big == core.endianness()? {
1427                byte_offset = 3 - byte_offset;
1428            }
1429
1430            // Get the current word value
1431            let current_word = core.read_word_32(word_start)?;
1432            let mut word_bytes = current_word.to_le_bytes();
1433            word_bytes[byte_offset as usize] = data;
1434
1435            core.write_word_32(word_start, u32::from_le_bytes(word_bytes))
1436        })
1437    }
1438
1439    fn write_word_16(&mut self, address: u64, data: u16) -> Result<(), Error> {
1440        self.halted_access(|core| {
1441            // Find the word this is in and its byte offset
1442            let mut byte_offset = address % 4;
1443            let word_start = address - byte_offset;
1444
1445            // We do 32-bit reads and writes, so we need to take a different field
1446            // if we're running on a big endian device.
1447            if Endian::Big == core.endianness()? {
1448                // TODO: This doesn't work when accessing 16-bit words that are not aligned.
1449                if address & 1 != 0 {
1450                    return Err(Error::MemoryNotAligned(MemoryNotAlignedError {
1451                        address,
1452                        alignment: 2,
1453                    }));
1454                }
1455                byte_offset = 2 - byte_offset;
1456            }
1457
1458            // Get the current word value
1459            let mut word = core.read_word_32(word_start)?;
1460
1461            // patch the word into it
1462            word &= !(0xFFFFu32 << (byte_offset * 8));
1463            word |= (data as u32) << (byte_offset * 8);
1464
1465            core.write_word_32(word_start, word)
1466        })
1467    }
1468
1469    fn write_64(&mut self, address: u64, data: &[u64]) -> Result<(), Error> {
1470        self.halted_access(|core| {
1471            for (i, word) in data.iter().enumerate() {
1472                core.write_word_64(address + ((i as u64) * 8), *word)?;
1473            }
1474
1475            Ok(())
1476        })
1477    }
1478
1479    fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), Error> {
1480        self.halted_access(|core| {
1481            if data.len() > 2 {
1482                // Save r0
1483                core.prepare_r0_for_clobber()?;
1484                core.set_r0(valid_32bit_address(address)?)?;
1485
1486                let mut banked = core.banked_access()?;
1487
1488                banked
1489                    .with_dcc_fast_mode(|banked| {
1490                        // STC p14, c5, [r0], #4
1491                        banked.set_itr(build_stc(14, 5, 0, 4))?;
1492
1493                        // Continually write the tx register, which will auto-increment
1494                        for word in data.iter() {
1495                            banked.set_dtrtx(*word)?;
1496                        }
1497                        Ok(())
1498                    })
1499                    .ok();
1500
1501                // Check if we had any aborts, if so clear them and fail
1502                let dscr = banked.dscr()?;
1503                check_and_clear_data_abort(&mut *core.memory, core.base_address, dscr)?;
1504            } else {
1505                // Slow path -- perform multiple writes
1506                for (i, word) in data.iter().enumerate() {
1507                    core.write_word_32(address + ((i as u64) * 4), *word)?;
1508                }
1509            }
1510
1511            Ok(())
1512        })
1513    }
1514
1515    fn write_16(&mut self, address: u64, data: &[u16]) -> Result<(), Error> {
1516        self.halted_access(|core| {
1517            for (i, word) in data.iter().enumerate() {
1518                core.write_word_16(address + ((i as u64) * 2), *word)?;
1519            }
1520
1521            Ok(())
1522        })
1523    }
1524
1525    fn write_8(&mut self, address: u64, data: &[u8]) -> Result<(), Error> {
1526        self.write(address, data)
1527    }
1528
1529    fn write(&mut self, address: u64, data: &[u8]) -> Result<(), Error> {
1530        self.halted_access(|core| {
1531            let len = data.len();
1532            let start_extra_count = ((4 - (address % 4) as usize) % 4).min(len);
1533            let end_extra_count = (len - start_extra_count) % 4;
1534            assert!(start_extra_count < 4);
1535            assert!(end_extra_count < 4);
1536
1537            // Fall back to slower bytewise access if it's not aligned
1538            if start_extra_count != 0 || end_extra_count != 0 {
1539                for (i, byte) in data.iter().enumerate() {
1540                    core.write_word_8(address + (i as u64), *byte)?;
1541                }
1542                return Ok(());
1543            }
1544
1545            // Make sure we don't try to do an empty but potentially unaligned write
1546            // We do a 32 bit write of the remaining bytes that are 4 byte aligned.
1547            let mut buffer = vec![0u32; data.len() / 4];
1548            let endianness = core.endianness()?;
1549            for (bytes, value) in data.chunks_exact(4).zip(buffer.iter_mut()) {
1550                *value = match endianness {
1551                    Endian::Little => u32::from_le_bytes(bytes.try_into().unwrap()),
1552                    Endian::Big => u32::from_be_bytes(bytes.try_into().unwrap()),
1553                }
1554            }
1555            core.write_32(address, &buffer)?;
1556
1557            Ok(())
1558        })
1559    }
1560
1561    fn supports_8bit_transfers(&self) -> Result<bool, Error> {
1562        Ok(false)
1563    }
1564
1565    fn flush(&mut self) -> Result<(), Error> {
1566        // Nothing to do - this runs through the CPU which automatically handles any caching
1567        Ok(())
1568    }
1569}
1570
1571#[cfg(test)]
1572mod test {
1573    use crate::{
1574        architecture::arm::{
1575            FullyQualifiedApAddress, communication_interface::SwdSequence,
1576            sequences::DefaultArmSequence,
1577        },
1578        probe::DebugProbeError,
1579    };
1580
1581    use super::*;
1582
1583    const TEST_BASE_ADDRESS: u64 = 0x8000_1000;
1584
1585    fn address_to_reg_num(address: u64) -> u32 {
1586        ((address - TEST_BASE_ADDRESS) / 4) as u32
1587    }
1588
1589    #[derive(Debug)]
1590    pub struct ExpectedMemoryOp {
1591        read: bool,
1592        address: u64,
1593        value: u32,
1594    }
1595
1596    pub struct MockProbe {
1597        expected_ops: Vec<ExpectedMemoryOp>,
1598    }
1599
1600    impl MockProbe {
1601        pub fn new() -> Self {
1602            MockProbe {
1603                expected_ops: vec![],
1604            }
1605        }
1606
1607        pub fn expected_read(&mut self, addr: u64, value: u32) {
1608            self.expected_ops.push(ExpectedMemoryOp {
1609                read: true,
1610                address: addr,
1611                value,
1612            });
1613        }
1614
1615        pub fn expected_write(&mut self, addr: u64, value: u32) {
1616            self.expected_ops.push(ExpectedMemoryOp {
1617                read: false,
1618                address: addr,
1619                value,
1620            });
1621        }
1622    }
1623
1624    impl MemoryInterface<ArmError> for MockProbe {
1625        fn read_8(&mut self, _address: u64, _data: &mut [u8]) -> Result<(), ArmError> {
1626            todo!()
1627        }
1628
1629        fn read_16(&mut self, _address: u64, _data: &mut [u16]) -> Result<(), ArmError> {
1630            todo!()
1631        }
1632
1633        fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), ArmError> {
1634            if self.expected_ops.is_empty() {
1635                panic!(
1636                    "Received unexpected read_32 op: register {:#}",
1637                    address_to_reg_num(address)
1638                );
1639            }
1640
1641            assert_eq!(data.len(), 1);
1642
1643            let expected_op = self.expected_ops.remove(0);
1644
1645            assert!(
1646                expected_op.read,
1647                "R/W mismatch for register: Expected {:#} Actual: {:#}",
1648                address_to_reg_num(expected_op.address),
1649                address_to_reg_num(address)
1650            );
1651            assert_eq!(
1652                expected_op.address,
1653                address,
1654                "Read from unexpected register: Expected {:#} Actual: {:#}",
1655                address_to_reg_num(expected_op.address),
1656                address_to_reg_num(address)
1657            );
1658
1659            data[0] = expected_op.value;
1660
1661            Ok(())
1662        }
1663
1664        fn read(&mut self, address: u64, data: &mut [u8]) -> Result<(), ArmError> {
1665            self.read_8(address, data)
1666        }
1667
1668        fn write_8(&mut self, _address: u64, _data: &[u8]) -> Result<(), ArmError> {
1669            todo!()
1670        }
1671
1672        fn write_16(&mut self, _address: u64, _data: &[u16]) -> Result<(), ArmError> {
1673            todo!()
1674        }
1675
1676        fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), ArmError> {
1677            if self.expected_ops.is_empty() {
1678                panic!(
1679                    "Received unexpected write_32 op: register {:#}",
1680                    address_to_reg_num(address)
1681                );
1682            }
1683
1684            assert_eq!(data.len(), 1);
1685
1686            let expected_op = self.expected_ops.remove(0);
1687
1688            assert!(
1689                !expected_op.read,
1690                "Read/write mismatch on register: {:#}",
1691                address_to_reg_num(address)
1692            );
1693            assert_eq!(
1694                expected_op.address,
1695                address,
1696                "Write to unexpected register: Expected {:#} Actual: {:#}",
1697                address_to_reg_num(expected_op.address),
1698                address_to_reg_num(address)
1699            );
1700
1701            assert_eq!(
1702                expected_op.value, data[0],
1703                "Write value mismatch Expected {:#X} Actual: {:#X}",
1704                expected_op.value, data[0]
1705            );
1706
1707            Ok(())
1708        }
1709
1710        fn write(&mut self, address: u64, data: &[u8]) -> Result<(), ArmError> {
1711            self.write_8(address, data)
1712        }
1713
1714        fn flush(&mut self) -> Result<(), ArmError> {
1715            todo!()
1716        }
1717
1718        fn read_64(&mut self, _address: u64, _data: &mut [u64]) -> Result<(), ArmError> {
1719            todo!()
1720        }
1721
1722        fn write_64(&mut self, _address: u64, _data: &[u64]) -> Result<(), ArmError> {
1723            todo!()
1724        }
1725
1726        fn supports_8bit_transfers(&self) -> Result<bool, ArmError> {
1727            Ok(false)
1728        }
1729
1730        fn supports_native_64bit_access(&mut self) -> bool {
1731            false
1732        }
1733    }
1734
1735    impl ArmMemoryInterface for MockProbe {
1736        fn fully_qualified_address(&self) -> FullyQualifiedApAddress {
1737            todo!()
1738        }
1739
1740        fn get_arm_debug_interface(
1741            &mut self,
1742        ) -> Result<&mut dyn crate::architecture::arm::ArmDebugInterface, DebugProbeError> {
1743            Err(DebugProbeError::NotImplemented {
1744                function_name: "get_arm_debug_interface",
1745            })
1746        }
1747
1748        fn generic_status(&mut self) -> Result<crate::architecture::arm::ap::CSW, ArmError> {
1749            Err(ArmError::Probe(DebugProbeError::NotImplemented {
1750                function_name: "generic_status",
1751            }))
1752        }
1753
1754        fn base_address(&mut self) -> Result<u64, ArmError> {
1755            todo!()
1756        }
1757    }
1758
1759    impl SwdSequence for MockProbe {
1760        fn swj_sequence(&mut self, _bit_len: u8, _bits: u64) -> Result<(), DebugProbeError> {
1761            todo!()
1762        }
1763
1764        fn swj_pins(
1765            &mut self,
1766            _pin_out: u32,
1767            _pin_select: u32,
1768            _pin_wait: u32,
1769        ) -> Result<u32, DebugProbeError> {
1770            todo!()
1771        }
1772    }
1773
1774    fn add_status_expectations(probe: &mut MockProbe, halted: bool) {
1775        let mut dbgdscr = Dbgdscr(0);
1776        dbgdscr.set_halted(halted);
1777        dbgdscr.set_restarted(true);
1778        probe.expected_read(
1779            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1780            dbgdscr.into(),
1781        );
1782    }
1783
1784    fn add_enable_itr_expectations(probe: &mut MockProbe) {
1785        let mut dbgdscr = Dbgdscr(0);
1786        dbgdscr.set_halted(true);
1787        probe.expected_read(
1788            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1789            dbgdscr.into(),
1790        );
1791        dbgdscr.set_itren(true);
1792        probe.expected_write(
1793            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1794            dbgdscr.into(),
1795        );
1796    }
1797
1798    fn add_read_reg_expectations(probe: &mut MockProbe, reg: u16, value: u32) {
1799        probe.expected_write(
1800            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1801            build_mcr(14, 0, reg, 0, 5, 0),
1802        );
1803        let mut dbgdscr = Dbgdscr(0);
1804        dbgdscr.set_instrcoml_l(true);
1805        dbgdscr.set_txfull_l(true);
1806
1807        probe.expected_read(
1808            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1809            dbgdscr.into(),
1810        );
1811        probe.expected_read(
1812            Dbgdtrtx::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1813            value,
1814        );
1815    }
1816
1817    fn add_read_pc_expectations(probe: &mut MockProbe, value: u32) {
1818        let mut dbgdscr = Dbgdscr(0);
1819        dbgdscr.set_instrcoml_l(true);
1820        dbgdscr.set_txfull_l(true);
1821
1822        probe.expected_write(
1823            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1824            build_mov(0, 15),
1825        );
1826        probe.expected_read(
1827            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1828            dbgdscr.into(),
1829        );
1830        // + 8 to add expected offset on halt
1831        add_read_reg_expectations(probe, 0, value + 8);
1832    }
1833
1834    fn add_read_fp_count_expectations(probe: &mut MockProbe) {
1835        let mut dbgdscr = Dbgdscr(0);
1836        dbgdscr.set_instrcoml_l(true);
1837        dbgdscr.set_txfull_l(true);
1838        let mut cpacr = Cpacr(0);
1839        cpacr.set_cp(10, 0b11);
1840        cpacr.set_cp(11, 0b11);
1841
1842        // CPACR read: MRC
1843        probe.expected_write(
1844            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1845            build_mrc(15, 0, 0, 1, 0, 2),
1846        );
1847        probe.expected_read(
1848            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1849            dbgdscr.into(),
1850        );
1851        // CPACR read: MCR
1852        add_read_reg_expectations(probe, 0, cpacr.0);
1853
1854        // MVFR0 read
1855        probe.expected_write(
1856            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1857            build_vmrs(0, 0b0111),
1858        );
1859        probe.expected_read(
1860            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1861            dbgdscr.into(),
1862        );
1863        add_read_reg_expectations(probe, 0, 0b010);
1864    }
1865
1866    fn add_read_cpsr_expectations(probe: &mut MockProbe, value: u32) {
1867        let mut dbgdscr = Dbgdscr(0);
1868        dbgdscr.set_instrcoml_l(true);
1869        dbgdscr.set_txfull_l(true);
1870
1871        probe.expected_write(
1872            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1873            build_mrs(0),
1874        );
1875        probe.expected_read(
1876            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1877            dbgdscr.into(),
1878        );
1879        add_read_reg_expectations(probe, 0, value);
1880    }
1881
1882    fn add_idr_expectations(probe: &mut MockProbe, bp_count: u32) {
1883        let mut dbgdidr = Dbgdidr(0);
1884        dbgdidr.set_brps(bp_count - 1);
1885        probe.expected_read(
1886            Dbgdidr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1887            dbgdidr.into(),
1888        );
1889    }
1890
1891    fn add_set_r0_expectation(probe: &mut MockProbe, value: u32) {
1892        let mut dbgdscr = Dbgdscr(0);
1893        dbgdscr.set_instrcoml_l(true);
1894        dbgdscr.set_rxfull_l(true);
1895
1896        probe.expected_write(
1897            Dbgdtrrx::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1898            value,
1899        );
1900        probe.expected_read(
1901            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1902            dbgdscr.into(),
1903        );
1904
1905        probe.expected_write(
1906            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1907            build_mrc(14, 0, 0, 0, 5, 0),
1908        );
1909        probe.expected_read(
1910            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1911            dbgdscr.into(),
1912        );
1913    }
1914
1915    fn add_read_memory_expectations(probe: &mut MockProbe, address: u64, value: u32) {
1916        add_set_r0_expectation(probe, address as u32);
1917
1918        let mut dbgdscr = Dbgdscr(0);
1919        dbgdscr.set_instrcoml_l(true);
1920        dbgdscr.set_txfull_l(true);
1921
1922        probe.expected_write(
1923            Dbgitr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1924            build_ldc(14, 5, 0, 4),
1925        );
1926        probe.expected_read(
1927            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1928            dbgdscr.into(),
1929        );
1930        probe.expected_read(
1931            Dbgdtrtx::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1932            value,
1933        );
1934    }
1935
1936    impl Drop for MockProbe {
1937        fn drop(&mut self) {
1938            if !self.expected_ops.is_empty() {
1939                panic!("self.expected_ops is not empty: {:?}", self.expected_ops);
1940            }
1941        }
1942    }
1943
1944    #[test]
1945    fn armv7a_new() {
1946        let mut probe = MockProbe::new();
1947
1948        // Add expectations
1949        add_status_expectations(&mut probe, true);
1950        add_enable_itr_expectations(&mut probe);
1951        add_read_reg_expectations(&mut probe, 0, 0);
1952        add_read_fp_count_expectations(&mut probe);
1953
1954        let mock_mem = Box::new(probe) as _;
1955
1956        let _ = Armv7a::new(
1957            mock_mem,
1958            &mut CortexAState::new(),
1959            TEST_BASE_ADDRESS,
1960            DefaultArmSequence::create(),
1961        )
1962        .unwrap();
1963    }
1964
1965    #[test]
1966    fn armv7a_core_halted() {
1967        let mut probe = MockProbe::new();
1968        let mut state = CortexAState::new();
1969
1970        // Add expectations
1971        add_status_expectations(&mut probe, true);
1972        add_enable_itr_expectations(&mut probe);
1973        add_read_reg_expectations(&mut probe, 0, 0);
1974        add_read_fp_count_expectations(&mut probe);
1975
1976        let mut dbgdscr = Dbgdscr(0);
1977        dbgdscr.set_halted(false);
1978        probe.expected_read(
1979            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1980            dbgdscr.into(),
1981        );
1982
1983        dbgdscr.set_halted(true);
1984        probe.expected_read(
1985            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
1986            dbgdscr.into(),
1987        );
1988
1989        let mock_mem = Box::new(probe) as _;
1990
1991        let mut armv7a = Armv7a::new(
1992            mock_mem,
1993            &mut state,
1994            TEST_BASE_ADDRESS,
1995            DefaultArmSequence::create(),
1996        )
1997        .unwrap();
1998
1999        // First read false, second read true
2000        assert!(!armv7a.core_halted().unwrap());
2001        assert!(armv7a.core_halted().unwrap());
2002    }
2003
2004    #[test]
2005    fn armv7a_wait_for_core_halted() {
2006        let mut probe = MockProbe::new();
2007        let mut state = CortexAState::new();
2008
2009        // Add expectations
2010        add_status_expectations(&mut probe, true);
2011        add_enable_itr_expectations(&mut probe);
2012        add_read_reg_expectations(&mut probe, 0, 0);
2013        add_read_fp_count_expectations(&mut probe);
2014
2015        let mut dbgdscr = Dbgdscr(0);
2016        dbgdscr.set_halted(false);
2017        probe.expected_read(
2018            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2019            dbgdscr.into(),
2020        );
2021
2022        dbgdscr.set_halted(true);
2023        probe.expected_read(
2024            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2025            dbgdscr.into(),
2026        );
2027
2028        let mock_mem = Box::new(probe) as _;
2029
2030        let mut armv7a = Armv7a::new(
2031            mock_mem,
2032            &mut state,
2033            TEST_BASE_ADDRESS,
2034            DefaultArmSequence::create(),
2035        )
2036        .unwrap();
2037
2038        // Should halt on second read
2039        armv7a
2040            .wait_for_core_halted(Duration::from_millis(100))
2041            .unwrap();
2042    }
2043
2044    #[test]
2045    fn armv7a_status_running() {
2046        let mut probe = MockProbe::new();
2047        let mut state = CortexAState::new();
2048
2049        // Add expectations
2050        add_status_expectations(&mut probe, true);
2051        add_enable_itr_expectations(&mut probe);
2052        add_read_reg_expectations(&mut probe, 0, 0);
2053        add_read_fp_count_expectations(&mut probe);
2054
2055        let mut dbgdscr = Dbgdscr(0);
2056        dbgdscr.set_halted(false);
2057        probe.expected_read(
2058            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2059            dbgdscr.into(),
2060        );
2061
2062        let mock_mem = Box::new(probe) as _;
2063
2064        let mut armv7a = Armv7a::new(
2065            mock_mem,
2066            &mut state,
2067            TEST_BASE_ADDRESS,
2068            DefaultArmSequence::create(),
2069        )
2070        .unwrap();
2071
2072        // Should halt on second read
2073        assert_eq!(CoreStatus::Running, armv7a.status().unwrap());
2074    }
2075
2076    #[test]
2077    fn armv7a_status_halted() {
2078        let mut probe = MockProbe::new();
2079        let mut state = CortexAState::new();
2080
2081        // Add expectations
2082        add_status_expectations(&mut probe, true);
2083        add_enable_itr_expectations(&mut probe);
2084        add_read_reg_expectations(&mut probe, 0, 0);
2085        add_read_fp_count_expectations(&mut probe);
2086
2087        let mut dbgdscr = Dbgdscr(0);
2088        dbgdscr.set_halted(true);
2089        probe.expected_read(
2090            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2091            dbgdscr.into(),
2092        );
2093
2094        let mock_mem = Box::new(probe) as _;
2095
2096        let mut armv7a = Armv7a::new(
2097            mock_mem,
2098            &mut state,
2099            TEST_BASE_ADDRESS,
2100            DefaultArmSequence::create(),
2101        )
2102        .unwrap();
2103
2104        // Should halt on second read
2105        assert_eq!(
2106            CoreStatus::Halted(crate::HaltReason::Request),
2107            armv7a.status().unwrap()
2108        );
2109    }
2110
2111    #[test]
2112    fn armv7a_read_core_reg_common() {
2113        const REG_VALUE: u32 = 0xABCD;
2114
2115        let mut probe = MockProbe::new();
2116        let mut state = CortexAState::new();
2117
2118        // Add expectations
2119        add_status_expectations(&mut probe, true);
2120        add_enable_itr_expectations(&mut probe);
2121        add_read_reg_expectations(&mut probe, 0, 0);
2122        add_read_fp_count_expectations(&mut probe);
2123
2124        // Read register
2125        add_read_reg_expectations(&mut probe, 2, REG_VALUE);
2126
2127        let mock_mem = Box::new(probe) as _;
2128
2129        let mut armv7a = Armv7a::new(
2130            mock_mem,
2131            &mut state,
2132            TEST_BASE_ADDRESS,
2133            DefaultArmSequence::create(),
2134        )
2135        .unwrap();
2136
2137        // First read will hit expectations
2138        assert_eq!(
2139            RegisterValue::from(REG_VALUE),
2140            armv7a.read_core_reg(RegisterId(2)).unwrap()
2141        );
2142
2143        // Second read will cache, no new expectations
2144        assert_eq!(
2145            RegisterValue::from(REG_VALUE),
2146            armv7a.read_core_reg(RegisterId(2)).unwrap()
2147        );
2148    }
2149
2150    #[test]
2151    fn armv7a_read_core_reg_pc() {
2152        const REG_VALUE: u32 = 0xABCD;
2153
2154        let mut probe = MockProbe::new();
2155        let mut state = CortexAState::new();
2156
2157        // Add expectations
2158        add_status_expectations(&mut probe, true);
2159        add_enable_itr_expectations(&mut probe);
2160        add_read_reg_expectations(&mut probe, 0, 0);
2161        add_read_fp_count_expectations(&mut probe);
2162
2163        // Read PC
2164        add_read_pc_expectations(&mut probe, REG_VALUE);
2165
2166        let mock_mem = Box::new(probe) as _;
2167
2168        let mut armv7a = Armv7a::new(
2169            mock_mem,
2170            &mut state,
2171            TEST_BASE_ADDRESS,
2172            DefaultArmSequence::create(),
2173        )
2174        .unwrap();
2175
2176        // First read will hit expectations
2177        assert_eq!(
2178            RegisterValue::from(REG_VALUE),
2179            armv7a.read_core_reg(RegisterId(15)).unwrap()
2180        );
2181
2182        // Second read will cache, no new expectations
2183        assert_eq!(
2184            RegisterValue::from(REG_VALUE),
2185            armv7a.read_core_reg(RegisterId(15)).unwrap()
2186        );
2187    }
2188
2189    #[test]
2190    fn armv7a_read_core_reg_cpsr() {
2191        const REG_VALUE: u32 = 0xABCD;
2192
2193        let mut probe = MockProbe::new();
2194        let mut state = CortexAState::new();
2195
2196        // Add expectations
2197        add_status_expectations(&mut probe, true);
2198        add_enable_itr_expectations(&mut probe);
2199        add_read_reg_expectations(&mut probe, 0, 0);
2200        add_read_fp_count_expectations(&mut probe);
2201
2202        // Read CPSR
2203        add_read_cpsr_expectations(&mut probe, REG_VALUE);
2204
2205        let mock_mem = Box::new(probe) as _;
2206
2207        let mut armv7a = Armv7a::new(
2208            mock_mem,
2209            &mut state,
2210            TEST_BASE_ADDRESS,
2211            DefaultArmSequence::create(),
2212        )
2213        .unwrap();
2214
2215        // First read will hit expectations
2216        assert_eq!(
2217            RegisterValue::from(REG_VALUE),
2218            armv7a.read_core_reg(XPSR.id()).unwrap()
2219        );
2220
2221        // Second read will cache, no new expectations
2222        assert_eq!(
2223            RegisterValue::from(REG_VALUE),
2224            armv7a.read_core_reg(XPSR.id()).unwrap()
2225        );
2226    }
2227
2228    #[test]
2229    fn armv7a_halt() {
2230        const REG_VALUE: u32 = 0xABCD;
2231
2232        let mut probe = MockProbe::new();
2233        let mut state = CortexAState::new();
2234
2235        // Add expectations
2236        add_status_expectations(&mut probe, false);
2237
2238        // Write halt request
2239        let mut dbgdrcr = Dbgdrcr(0);
2240        dbgdrcr.set_hrq(true);
2241        probe.expected_write(
2242            Dbgdrcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2243            dbgdrcr.into(),
2244        );
2245
2246        // Wait for halted
2247        add_status_expectations(&mut probe, true);
2248
2249        // Read status
2250        add_status_expectations(&mut probe, true);
2251        add_enable_itr_expectations(&mut probe);
2252        add_read_reg_expectations(&mut probe, 0, 0);
2253        add_read_fp_count_expectations(&mut probe);
2254
2255        // Read PC
2256        add_read_pc_expectations(&mut probe, REG_VALUE);
2257
2258        let mock_mem = Box::new(probe) as _;
2259
2260        let mut armv7a = Armv7a::new(
2261            mock_mem,
2262            &mut state,
2263            TEST_BASE_ADDRESS,
2264            DefaultArmSequence::create(),
2265        )
2266        .unwrap();
2267
2268        // Verify PC
2269        assert_eq!(
2270            REG_VALUE as u64,
2271            armv7a.halt(Duration::from_millis(100)).unwrap().pc
2272        );
2273    }
2274
2275    #[test]
2276    fn armv7a_run() {
2277        let mut probe = MockProbe::new();
2278        let mut state = CortexAState::new();
2279
2280        // Add expectations
2281        add_status_expectations(&mut probe, true);
2282        add_enable_itr_expectations(&mut probe);
2283        add_read_reg_expectations(&mut probe, 0, 0);
2284        add_read_fp_count_expectations(&mut probe);
2285
2286        // Writeback r0
2287        add_set_r0_expectation(&mut probe, 0);
2288
2289        // Disable ITRen
2290        let mut dbgdscr = Dbgdscr(0);
2291        dbgdscr.set_itren(true);
2292        probe.expected_read(
2293            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2294            dbgdscr.into(),
2295        );
2296        dbgdscr.set_itren(false);
2297        probe.expected_write(
2298            Dbgdscr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2299            dbgdscr.into(),
2300        );
2301
2302        // Write resume request
2303        let mut dbgdrcr = Dbgdrcr(0);
2304        dbgdrcr.set_rrq(true);
2305        probe.expected_write(
2306            Dbgdrcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2307            dbgdrcr.into(),
2308        );
2309
2310        // Wait for running
2311        add_status_expectations(&mut probe, false);
2312
2313        // Read status
2314        add_status_expectations(&mut probe, false);
2315
2316        let mock_mem = Box::new(probe) as _;
2317
2318        let mut armv7a = Armv7a::new(
2319            mock_mem,
2320            &mut state,
2321            TEST_BASE_ADDRESS,
2322            DefaultArmSequence::create(),
2323        )
2324        .unwrap();
2325
2326        armv7a.run().unwrap();
2327    }
2328
2329    #[test]
2330    fn armv7a_available_breakpoint_units() {
2331        const BP_COUNT: u32 = 4;
2332        let mut probe = MockProbe::new();
2333        let mut state = CortexAState::new();
2334
2335        // Add expectations
2336        add_status_expectations(&mut probe, true);
2337        add_enable_itr_expectations(&mut probe);
2338        add_read_reg_expectations(&mut probe, 0, 0);
2339        add_read_fp_count_expectations(&mut probe);
2340
2341        // Read breakpoint count
2342        add_idr_expectations(&mut probe, BP_COUNT);
2343
2344        let mock_mem = Box::new(probe) as _;
2345
2346        let mut armv7a = Armv7a::new(
2347            mock_mem,
2348            &mut state,
2349            TEST_BASE_ADDRESS,
2350            DefaultArmSequence::create(),
2351        )
2352        .unwrap();
2353
2354        assert_eq!(BP_COUNT, armv7a.available_breakpoint_units().unwrap());
2355    }
2356
2357    #[test]
2358    fn armv7a_hw_breakpoints() {
2359        const BP_COUNT: u32 = 4;
2360        const BP1: u64 = 0x2345;
2361        const BP2: u64 = 0x8000_0000;
2362        let mut probe = MockProbe::new();
2363        let mut state = CortexAState::new();
2364
2365        // Add expectations
2366        add_status_expectations(&mut probe, true);
2367        add_enable_itr_expectations(&mut probe);
2368        add_read_reg_expectations(&mut probe, 0, 0);
2369        add_read_fp_count_expectations(&mut probe);
2370
2371        // Read breakpoint count
2372        add_idr_expectations(&mut probe, BP_COUNT);
2373
2374        // Read BP values and controls
2375        probe.expected_read(
2376            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2377            BP1 as u32,
2378        );
2379        probe.expected_read(
2380            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2381            1,
2382        );
2383
2384        probe.expected_read(
2385            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + 4,
2386            BP2 as u32,
2387        );
2388        probe.expected_read(
2389            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + 4,
2390            1,
2391        );
2392
2393        probe.expected_read(
2394            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + (2 * 4),
2395            0,
2396        );
2397        probe.expected_read(
2398            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + (2 * 4),
2399            0,
2400        );
2401
2402        probe.expected_read(
2403            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + (3 * 4),
2404            0,
2405        );
2406        probe.expected_read(
2407            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap() + (3 * 4),
2408            0,
2409        );
2410
2411        let mock_mem = Box::new(probe) as _;
2412
2413        let mut armv7a = Armv7a::new(
2414            mock_mem,
2415            &mut state,
2416            TEST_BASE_ADDRESS,
2417            DefaultArmSequence::create(),
2418        )
2419        .unwrap();
2420
2421        let results = armv7a.hw_breakpoints().unwrap();
2422        assert_eq!(Some(BP1), results[0]);
2423        assert_eq!(Some(BP2), results[1]);
2424        assert_eq!(None, results[2]);
2425        assert_eq!(None, results[3]);
2426    }
2427
2428    #[test]
2429    fn armv7a_set_hw_breakpoint() {
2430        const BP_VALUE: u64 = 0x2345;
2431        let mut probe = MockProbe::new();
2432        let mut state = CortexAState::new();
2433
2434        // Add expectations
2435        add_status_expectations(&mut probe, true);
2436        add_enable_itr_expectations(&mut probe);
2437        add_read_reg_expectations(&mut probe, 0, 0);
2438        add_read_fp_count_expectations(&mut probe);
2439
2440        // Update BP value and control
2441        let mut dbgbcr = Dbgbcr(0);
2442        // Match on all modes
2443        dbgbcr.set_hmc(true);
2444        dbgbcr.set_pmc(0b11);
2445        // Match on all bytes
2446        dbgbcr.set_bas(0b1111);
2447        // Enable
2448        dbgbcr.set_e(true);
2449
2450        probe.expected_write(
2451            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2452            BP_VALUE as u32,
2453        );
2454        probe.expected_write(
2455            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2456            dbgbcr.into(),
2457        );
2458
2459        let mock_mem = Box::new(probe) as _;
2460
2461        let mut armv7a = Armv7a::new(
2462            mock_mem,
2463            &mut state,
2464            TEST_BASE_ADDRESS,
2465            DefaultArmSequence::create(),
2466        )
2467        .unwrap();
2468
2469        armv7a.set_hw_breakpoint(0, BP_VALUE).unwrap();
2470    }
2471
2472    #[test]
2473    fn armv7a_clear_hw_breakpoint() {
2474        let mut probe = MockProbe::new();
2475        let mut state = CortexAState::new();
2476
2477        // Add expectations
2478        add_status_expectations(&mut probe, true);
2479        add_enable_itr_expectations(&mut probe);
2480        add_read_reg_expectations(&mut probe, 0, 0);
2481        add_read_fp_count_expectations(&mut probe);
2482
2483        // Update BP value and control
2484        probe.expected_write(
2485            Dbgbvr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2486            0,
2487        );
2488        probe.expected_write(
2489            Dbgbcr::get_mmio_address_from_base(TEST_BASE_ADDRESS).unwrap(),
2490            0,
2491        );
2492
2493        let mock_mem = Box::new(probe) as _;
2494
2495        let mut armv7a = Armv7a::new(
2496            mock_mem,
2497            &mut state,
2498            TEST_BASE_ADDRESS,
2499            DefaultArmSequence::create(),
2500        )
2501        .unwrap();
2502
2503        armv7a.clear_hw_breakpoint(0).unwrap();
2504    }
2505
2506    #[test]
2507    fn armv7a_read_word_32() {
2508        const MEMORY_VALUE: u32 = 0xBA5EBA11;
2509        const MEMORY_ADDRESS: u64 = 0x12345678;
2510
2511        let mut probe = MockProbe::new();
2512        let mut state = CortexAState::new();
2513
2514        // Add expectations
2515        add_status_expectations(&mut probe, true);
2516        add_enable_itr_expectations(&mut probe);
2517        add_read_reg_expectations(&mut probe, 0, 0);
2518        add_read_fp_count_expectations(&mut probe);
2519
2520        // Read memory
2521        add_read_memory_expectations(&mut probe, MEMORY_ADDRESS, MEMORY_VALUE);
2522
2523        let mock_mem = Box::new(probe) as _;
2524
2525        let mut armv7a = Armv7a::new(
2526            mock_mem,
2527            &mut state,
2528            TEST_BASE_ADDRESS,
2529            DefaultArmSequence::create(),
2530        )
2531        .unwrap();
2532
2533        assert_eq!(MEMORY_VALUE, armv7a.read_word_32(MEMORY_ADDRESS).unwrap());
2534    }
2535
2536    fn test_read_word(value: u32, address: u64, memory_word_address: u64, endian: Endian) -> u8 {
2537        let mut probe = MockProbe::new();
2538        let mut state = CortexAState::new();
2539
2540        // Add expectations
2541        add_status_expectations(&mut probe, true);
2542        add_enable_itr_expectations(&mut probe);
2543        add_read_reg_expectations(&mut probe, 0, 0);
2544        add_read_fp_count_expectations(&mut probe);
2545
2546        // Read memory
2547        add_read_memory_expectations(&mut probe, memory_word_address, value);
2548
2549        // Set endianx
2550        let cpsr = if endian == Endian::Big { 1 << 9 } else { 0 };
2551        add_read_cpsr_expectations(&mut probe, cpsr);
2552
2553        let mock_mem = Box::new(probe) as _;
2554
2555        let mut armv7a = Armv7a::new(
2556            mock_mem,
2557            &mut state,
2558            TEST_BASE_ADDRESS,
2559            DefaultArmSequence::create(),
2560        )
2561        .unwrap();
2562        armv7a.read_word_8(address).unwrap()
2563    }
2564
2565    #[test]
2566    fn armv7a_read_word_8() {
2567        const MEMORY_VALUE: u32 = 0xBA5EBB11;
2568        const MEMORY_ADDRESS: u64 = 0x12345679;
2569        const MEMORY_WORD_ADDRESS: u64 = 0x12345678;
2570
2571        assert_eq!(
2572            0xBB,
2573            test_read_word(
2574                MEMORY_VALUE,
2575                MEMORY_ADDRESS,
2576                MEMORY_WORD_ADDRESS,
2577                Endian::Little
2578            )
2579        );
2580    }
2581
2582    #[test]
2583    fn armv7a_read_word_8_be() {
2584        const MEMORY_VALUE: u32 = 0xBA5EBB11;
2585        const MEMORY_ADDRESS: u64 = 0x12345679;
2586        const MEMORY_WORD_ADDRESS: u64 = 0x12345678;
2587
2588        assert_eq!(
2589            0x5E,
2590            test_read_word(
2591                MEMORY_VALUE,
2592                MEMORY_ADDRESS,
2593                MEMORY_WORD_ADDRESS,
2594                Endian::Big
2595            )
2596        );
2597    }
2598}