Skip to content

Commit

Permalink
--wip-- [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
ithinuel committed Jul 21, 2024
1 parent e1e1083 commit e829bff
Show file tree
Hide file tree
Showing 50 changed files with 2,612 additions and 1,717 deletions.
71 changes: 27 additions & 44 deletions probe-rs-tools/src/bin/probe-rs/cmd/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use jep106::JEP106Code;
use probe_rs::{
architecture::{
arm::{
ap::{GenericAp, MemoryAp},
ap::ApClass,
armv6m::Demcr,
component::Scs,
dp::{DebugPortId, DebugPortVersion, MinDpSupport, DLPIDR, DPIDR, TARGETID},
Expand All @@ -14,8 +14,7 @@ use probe_rs::{
Component, ComponentId, CoresightComponent, PeripheralType,
},
sequences::DefaultArmSequence,
ApInformation, ArmProbeInterface, DpAddress, FullyQualifiedApAddress,
MemoryApInformation, Register,
ArmProbeInterface, DpAddress, FullyQualifiedApAddress, Register,
},
riscv::communication_interface::RiscvCommunicationInterface,
xtensa::communication_interface::{
Expand Down Expand Up @@ -292,36 +291,25 @@ fn show_arm_info(interface: &mut dyn ArmProbeInterface, dp: DpAddress) -> Result

let mut tree = Tree::new(dp_node);

let num_access_ports = interface.num_access_ports(dp)?;

for ap_index in 0..num_access_ports {
let ap = FullyQualifiedApAddress::v1_with_dp(dp, ap_index as u8);
let access_port = GenericAp::new(ap);

let ap_information = interface.ap_information(&access_port)?;

match ap_information {
ApInformation::MemoryAp(MemoryApInformation {
debug_base_address,
address,
device_enabled,
..
}) => {
let mut ap_nodes = Tree::new(format!("{} MemoryAP", address.ap_v1()?));

if *device_enabled {
match handle_memory_ap(&access_port.into(), *debug_base_address, interface) {
Ok(component_tree) => ap_nodes.push(component_tree),
Err(e) => ap_nodes.push(format!("Error during access: {e}")),
};
} else {
ap_nodes.push("Access disabled".to_string());
}

let access_ports = interface.access_ports(dp)?;
println!("ARM Chip with debug port {:x?}:", dp);
if access_ports.is_empty() {
println!("No access ports found on this chip.");
} else {
for ap_address in access_ports {
use probe_rs::architecture::arm::ap::IDR;
let idr: IDR = interface
.read_raw_ap_register(&ap_address, IDR::ADDRESS)?
.try_into()?;

if idr.CLASS == ApClass::MemAp {
let mut ap_nodes = Tree::new(format!("{} MemoryAP ({:?})", ap_address.ap_v1()?, idr.TYPE));
match handle_memory_ap(interface, &ap_address) {
Ok(component_tree) => ap_nodes.push(component_tree),
Err(e) => ap_nodes.push(format!("Error during access: {e}")),
};
tree.push(ap_nodes);
}

ApInformation::Other { address, idr } => {
} else {
let jep = idr.DESIGNER;

let ap_type = if idr.DESIGNER == JEP_ARM {
Expand All @@ -332,7 +320,7 @@ fn show_arm_info(interface: &mut dyn ArmProbeInterface, dp: DpAddress) -> Result

tree.push(format!(
"{} Unknown AP (Designer: {}, Class: {:?}, Type: {}, Variant: {:#x}, Revision: {:#x})",
address.ap_v1()?,
ap_address.ap_v1()?,
jep.get().unwrap_or("<unknown>"),
idr.CLASS,
ap_type,
Expand All @@ -341,26 +329,21 @@ fn show_arm_info(interface: &mut dyn ArmProbeInterface, dp: DpAddress) -> Result
));
}
}
}

println!("ARM Chip with debug port {:x?}:", dp);
println!("{tree}");

if num_access_ports == 0 {
println!("No access ports found on this chip.");
println!("{tree}");
}
println!();

Ok(dp_info.version)
}

fn handle_memory_ap(
access_port: &MemoryAp,
base_address: u64,
interface: &mut dyn ArmProbeInterface,
access_port: &FullyQualifiedApAddress,
) -> Result<Tree<String>, anyhow::Error> {
let component = {
let mut memory = interface.memory_interface(access_port)?;
let base_address = memory.base_address()?;
let mut demcr = Demcr(memory.read_word_32(Demcr::get_mmio_address())?);
demcr.set_dwtena(true);
memory.write_word_32(Demcr::get_mmio_address(), demcr.into())?;
Expand All @@ -374,7 +357,7 @@ fn handle_memory_ap(
fn coresight_component_tree(
interface: &mut dyn ArmProbeInterface,
component: Component,
access_port: &MemoryAp,
access_port: &FullyQualifiedApAddress,
) -> Result<Tree<String>> {
let tree = match &component {
Component::GenericVerificationComponent(_) => Tree::new("Generic".to_string()),
Expand Down Expand Up @@ -455,7 +438,7 @@ fn process_vendor_rom_tables(
interface: &mut dyn ArmProbeInterface,
id: &ComponentId,
_table: &RomTable,
access_port: &MemoryAp,
access_port: &FullyQualifiedApAddress,
tree: &mut Tree<String>,
) -> Result<()> {
let peripheral_id = id.peripheral_id();
Expand Down Expand Up @@ -485,7 +468,7 @@ fn process_component_entry(
interface: &mut dyn ArmProbeInterface,
peripheral_id: &PeripheralID,
component: &Component,
access_port: &MemoryAp,
access_port: &FullyQualifiedApAddress,
) -> Result<()> {
let Some(part) = peripheral_id.determine_part() else {
return Ok(());
Expand Down
12 changes: 1 addition & 11 deletions probe-rs/src/architecture/arm/ap/generic_ap.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
//! Generic access port
use super::{AccessPort, ApRegister, Register};
use crate::architecture::arm::{
communication_interface::RegisterParseError, FullyQualifiedApAddress,
};
use crate::architecture::arm::communication_interface::RegisterParseError;

/// Describes the class of an access port defined in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
Expand Down Expand Up @@ -70,14 +67,7 @@ impl ApType {
}
}

define_ap!(
/// A generic access port which implements just the register every access port has to implement
/// to be compliant with the ADI 5.2 specification.
GenericAp
);

define_ap_register!(
type: GenericAp,
/// Identification Register
///
/// The identification register is used to identify
Expand Down
191 changes: 191 additions & 0 deletions probe-rs/src/architecture/arm/ap/memory_ap/amba_ahb3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use crate::architecture::arm::{
ap::{AccessPortType, ApAccess, ApRegAccess},
communication_interface::RegisterParseError,
ArmError, DapAccess, FullyQualifiedApAddress, Register,
};

use super::{AddressIncrement, DataSize};

/// Memory AP
///
/// The memory AP can be used to access a memory-mapped
/// set of debug resources of the attached system.
#[derive(Debug)]
pub struct AmbaAhb3 {
address: FullyQualifiedApAddress,
csw: CSW,
cfg: super::registers::CFG,
}

impl AmbaAhb3 {
/// Creates a new AmbaAhb3 with `address` as base address.
pub fn new<P: DapAccess>(
probe: &mut P,
address: FullyQualifiedApAddress,
) -> Result<Self, ArmError> {
use crate::architecture::arm::Register;
let csw = probe.read_raw_ap_register(&address, CSW::ADDRESS)?;
let cfg = probe.read_raw_ap_register(&address, super::registers::CFG::ADDRESS)?;
let (csw, cfg) = (csw.try_into()?, cfg.try_into()?);

let me = Self { address, csw, cfg };
let csw = CSW {
AddrInc: AddressIncrement::Single,
..me.csw
};
probe.write_ap_register(&me, csw)?;
Ok(Self { csw, ..me })
}
}

impl super::MemoryApType for AmbaAhb3 {
type CSW = CSW;

fn status<P: ApAccess + ?Sized>(&mut self, probe: &mut P) -> Result<Self::CSW, ArmError> {
assert_eq!(super::registers::CSW::ADDRESS, CSW::ADDRESS);
self.csw = probe.read_ap_register(self)?;
Ok(self.csw)
}

fn try_set_datasize<P: ApAccess + ?Sized>(
&mut self,
probe: &mut P,
data_size: DataSize,
) -> Result<(), ArmError> {
match data_size {
DataSize::U8 | DataSize::U16 | DataSize::U32 if data_size != self.csw.Size => {
let csw = CSW {
Size: data_size,
..self.csw
};
probe.write_ap_register(self, csw)?;
self.csw = csw;
}
DataSize::U64 | DataSize::U128 | DataSize::U256 => {
return Err(ArmError::UnsupportedTransferWidth(
data_size.to_byte_count() * 8,
))
}
_ => {}
}
Ok(())
}

fn has_large_address_extension(&self) -> bool {
self.cfg.LA
}

fn has_large_data_extension(&self) -> bool {
self.cfg.LD
}

fn supports_only_32bit_data_size(&self) -> bool {
// Amba AHB3 must support word, half-word and byte size transfers.
false
}
}

impl AccessPortType for AmbaAhb3 {
fn ap_address(&self) -> &FullyQualifiedApAddress {
&self.address
}
}

impl ApRegAccess<CSW> for AmbaAhb3 {}

crate::attached_regs_to_mem_ap!(memory_ap_regs => AmbaAhb3);

define_ap_register!(
/// Control and Status Word register
///
/// The control and status word register (CSW) is used
/// to configure memory access through the memory AP.
name: CSW,
address: 0x00,
fields: [
/// Is debug software access enabled.
DbgSwEnable: bool, // [31]
/// HNONSEC
///
/// Not formally defined.
/// If implemented should be 1 at reset.
/// If not implemented, should be 1 and writing 0 leads to unpredictable AHB-AP behavior.
HNONSEC: bool, // [30]
/// Defines which Requester ID is used on `HMASTER[3:0]` signals.
///
/// Support of this function is implementation defined.
MasterType: bool, // [29]
/// Drives `HPROT[4]`, Allocate.
///
/// `HPROT[4]` is an Armv5 extension to AHB. For more information, see the Arm1136JF-S™ and
/// Arm1136J-S ™ Technical Reference Manual.
Allocate: bool, // [28]
/// `HPROT[3]`
Cacheable: bool, // [27]
/// `HPROT[2]`
Bufferable: bool, // [26]
/// `HPROT[1]`
Privileged: bool, // [25]
/// `HPROT[0]`
Data: bool, // [24]
/// Secure Debug Enabled.
///
/// This field has one of the following values:
/// - `0b0` Secure access is disabled.
/// - `0b1` Secure access is enabled.
/// This field is optional, and read-only. If not implemented, the bit is RES0.
/// If CSW.DeviceEn is 0b0, SPIDEN is ignored and the effective value of SPIDEN is 0b1.
/// For more information, see `Enabling access to the connected debug device or memory system`
/// on page C2-154.
///
/// Note:
/// In ADIv5 and older versions of the architecture, the CSW.SPIDEN field is in the same bit
/// position as CSW.SDeviceEn, and has the same meaning. From ADIv6, the name SDeviceEn is
/// used to avoid confusion between this field and the SPIDEN signal on the authentication
/// interface.
SPIDEN: bool, // [23]
/// A transfer is in progress.
/// Can be used to poll whether an aborted transaction has completed.
/// Read only.
TrInProg: bool, // [7]
/// `1` if transactions can be issued through this access port at the moment.
/// Read only.
DeviceEn: bool, // [6]
/// The address increment on DRW access.
AddrInc: AddressIncrement, // [5:4]
/// The access size of this memory AP.
Size: DataSize, // [2:0]
/// Reserved bit, kept to preserve IMPLEMENTATION DEFINED statuses.
_reserved_bits: u32 // mask
],
from: value => Ok(CSW {
DbgSwEnable: ((value >> 31) & 0x01) != 0,
HNONSEC: ((value >> 30) & 0x01) != 0,
MasterType: ((value >> 29) & 0x01) != 0,
Allocate: ((value >> 28) & 0x01) != 0,
Cacheable: ((value >> 27) & 0x01) != 0,
Bufferable: ((value >> 26) & 0x01) != 0,
Privileged: ((value >> 25) & 0x01) != 0,
Data: ((value >> 24) & 0x01) != 0,
SPIDEN: ((value >> 23) & 0x01) != 0,
TrInProg: ((value >> 7) & 0x01) != 0,
DeviceEn: ((value >> 6) & 0x01) != 0,
AddrInc: AddressIncrement::from_u8(((value >> 4) & 0x03) as u8).ok_or_else(|| RegisterParseError::new("CSW", value))?,
Size: DataSize::try_from((value & 0x07) as u8).map_err(|_| RegisterParseError::new("CSW", value))?,
_reserved_bits: value & 0x007F_FF08,
}),
to: value => (u32::from(value.DbgSwEnable) << 31)
| (u32::from(value.HNONSEC ) << 30)
| (u32::from(value.MasterType ) << 29)
| (u32::from(value.Allocate ) << 28)
| (u32::from(value.Cacheable ) << 27)
| (u32::from(value.Bufferable ) << 26)
| (u32::from(value.Privileged ) << 25)
| (u32::from(value.Data ) << 24)
| (u32::from(value.SPIDEN ) << 23)
| (u32::from(value.TrInProg ) << 7)
| (u32::from(value.DeviceEn ) << 6)
| (u32::from(value.AddrInc as u8) << 4)
| (value.Size as u32)
| value._reserved_bits
);
Loading

0 comments on commit e829bff

Please sign in to comment.