From b8466e9fb707ca5a7feda8d9bdb4fbc1f87c5df6 Mon Sep 17 00:00:00 2001 From: "Jes B. Klinke" Date: Thu, 21 Nov 2024 14:00:09 -0800 Subject: [PATCH] WIP: SPI flashrom Change-Id: I9511b449f303a5f0cd901dac19ce9654209b3fd1 --- sw/host/opentitanlib/src/app/spi.rs | 7 +++++ sw/host/opentitanlib/src/io/spi.rs | 7 +++++ sw/host/opentitanlib/src/proxy/handler.rs | 4 +++ sw/host/opentitanlib/src/proxy/protocol.rs | 4 +++ .../src/transport/dediprog/spi.rs | 21 +++++++++++++++ .../src/transport/hyperdebug/spi.rs | 6 +++++ .../opentitanlib/src/transport/proxy/spi.rs | 7 +++++ sw/host/opentitantool/src/command/spi.rs | 27 +++++++++++++++++++ 8 files changed, 83 insertions(+) diff --git a/sw/host/opentitanlib/src/app/spi.rs b/sw/host/opentitanlib/src/app/spi.rs index 6887df696fe413..0fe913ccac9828 100644 --- a/sw/host/opentitanlib/src/app/spi.rs +++ b/sw/host/opentitanlib/src/app/spi.rs @@ -205,6 +205,13 @@ impl Target for LogicalSpiWrapper { self.physical_wrapper.underlying_target.set_voltage(voltage) } + fn get_flashrom_programmer(&self) -> Result { + self.apply_settings_to_underlying()?; + self.physical_wrapper + .underlying_target + .get_flashrom_programmer() + } + fn run_transaction(&self, transaction: &mut [spi::Transfer]) -> Result<()> { self.apply_settings_to_underlying()?; self.physical_wrapper diff --git a/sw/host/opentitanlib/src/io/spi.rs b/sw/host/opentitanlib/src/io/spi.rs index a640bfd77caf6f..05f0626d3f6bcd 100644 --- a/sw/host/opentitanlib/src/io/spi.rs +++ b/sw/host/opentitanlib/src/io/spi.rs @@ -12,6 +12,7 @@ use thiserror::Error; use super::{eeprom, gpio}; use crate::app::TransportWrapper; use crate::impl_serializable_error; +use crate::transport::TransportError; use crate::util::voltage::Voltage; #[derive(Clone, Debug, Args, Serialize, Deserialize)] @@ -202,6 +203,12 @@ pub trait Target { Err(SpiError::InvalidOption("This target does not support set_voltage".to_string()).into()) } + /// Returns `"raiden_debug_spi:serial=XXX"` or similar string usable for passing via `-p` + /// argument to `flashrom`, in order for it to connect to this SPI port instance. + fn get_flashrom_programmer(&self) -> Result { + Err(TransportError::UnsupportedOperation.into()) + } + /// Runs a SPI transaction composed from the slice of [`Transfer`] objects. Will assert the /// CS for the duration of the entire transactions. fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()>; diff --git a/sw/host/opentitanlib/src/proxy/handler.rs b/sw/host/opentitanlib/src/proxy/handler.rs index cebe18f20aa3a0..6301b57484c9d8 100644 --- a/sw/host/opentitanlib/src/proxy/handler.rs +++ b/sw/host/opentitanlib/src/proxy/handler.rs @@ -366,6 +366,10 @@ impl<'a> TransportCommandHandler<'a> { instance.set_voltage(*voltage)?; Ok(Response::Spi(SpiResponse::SetVoltage)) } + SpiRequest::GetFlashromArgs => { + let programmer = instance.get_flashrom_programmer()?; + Ok(Response::Spi(SpiResponse::GetFlashromArgs { programmer })) + } SpiRequest::RunTransaction { transaction: reqs } => { // Construct proper response to each transfer in request. let mut resps: Vec = reqs diff --git a/sw/host/opentitanlib/src/proxy/protocol.rs b/sw/host/opentitanlib/src/proxy/protocol.rs index 483a4e107253ee..f1f164a9a61752 100644 --- a/sw/host/opentitanlib/src/proxy/protocol.rs +++ b/sw/host/opentitanlib/src/proxy/protocol.rs @@ -246,6 +246,7 @@ pub enum SpiRequest { SetVoltage { voltage: Voltage, }, + GetFlashromArgs, RunTransaction { transaction: Vec, }, @@ -281,6 +282,9 @@ pub enum SpiResponse { sizes: MaxSizes, }, SetVoltage, + GetFlashromArgs { + programmer: String, + }, RunTransaction { transaction: Vec, }, diff --git a/sw/host/opentitanlib/src/transport/dediprog/spi.rs b/sw/host/opentitanlib/src/transport/dediprog/spi.rs index 1a714c900a5703..50bc19c5d64af8 100644 --- a/sw/host/opentitanlib/src/transport/dediprog/spi.rs +++ b/sw/host/opentitanlib/src/transport/dediprog/spi.rs @@ -379,6 +379,27 @@ impl Target for DediprogSpi { inner.set_voltage() } + fn get_flashrom_programmer(&self) -> Result { + let inner = self.inner.borrow(); + let voltage = match inner.voltage { + super::Voltage::V0 => "0V", + super::Voltage::V1p8 => "1.8V", + super::Voltage::V2p5 => "2.5V", + super::Voltage::V3p5 => "3.5V", + }; + let spispeed = match inner.spi_clock { + ClockSpeed::Clk24Mhz => "24M", + ClockSpeed::Clk12Mhz => "12M", + ClockSpeed::Clk8Mhz => "8M", + ClockSpeed::Clk3Mhz => "3M", + ClockSpeed::Clk2p18Mhz => "2.18M", + ClockSpeed::Clk1p5Mhz => "1.5M", + ClockSpeed::Clk750Khz => "750k", + ClockSpeed::Clk375Khz => "375k", + }; + Ok(format!("dediprog:voltage={voltage},spispeed={spispeed}")) + } + /// Dediprog has limited support for "plain" SPI transactions. It can only hold the CS /// asserted across a write then optional read, both of at most 16 bytes. fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> { diff --git a/sw/host/opentitanlib/src/transport/hyperdebug/spi.rs b/sw/host/opentitanlib/src/transport/hyperdebug/spi.rs index 53fdabe8f523bc..dbc66635b8b805 100644 --- a/sw/host/opentitanlib/src/transport/hyperdebug/spi.rs +++ b/sw/host/opentitanlib/src/transport/hyperdebug/spi.rs @@ -714,6 +714,12 @@ impl Target for HyperdebugSpiTarget { Ok(self.max_sizes) } + fn get_flashrom_programmer(&self) -> Result { + Ok(format!("raiden_debug_spi:serial={},target={}", + self.inner.usb_device.borrow().get_serial_number(), + self.target_idx)) + } + fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> { let mut idx: usize = 0; self.select_my_spi_bus()?; diff --git a/sw/host/opentitanlib/src/transport/proxy/spi.rs b/sw/host/opentitanlib/src/transport/proxy/spi.rs index 17cb826b8f8ea7..d67a69e5bbd59a 100644 --- a/sw/host/opentitanlib/src/transport/proxy/spi.rs +++ b/sw/host/opentitanlib/src/transport/proxy/spi.rs @@ -147,6 +147,13 @@ impl Target for ProxySpi { } } + fn get_flashrom_programmer(&self) -> Result { + match self.execute_command(SpiRequest::GetFlashromArgs)? { + SpiResponse::GetFlashromArgs { programmer } => Ok(programmer), + _ => bail!(ProxyError::UnexpectedReply()), + } + } + fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> { let mut req: Vec = Vec::new(); for transfer in transaction.iter() { diff --git a/sw/host/opentitantool/src/command/spi.rs b/sw/host/opentitantool/src/command/spi.rs index 68111f429e63a4..1388d0f0a91b78 100644 --- a/sw/host/opentitantool/src/command/spi.rs +++ b/sw/host/opentitantool/src/command/spi.rs @@ -416,6 +416,32 @@ impl CommandDispatch for SpiRawTransceive { } } +/// Produces output useful for separate invocation of `flashrom` connecting to a particular SPI +/// bus alias. +#[derive(Debug, Args)] +pub struct SpiFlashromArgs { +} + +#[derive(Debug, serde::Serialize)] +pub struct SpiFlashromArgsResponse { + programmer: String, +} + +impl CommandDispatch for SpiFlashromArgs { + fn run( + &self, + context: &dyn Any, + transport: &TransportWrapper, + ) -> Result>> { + transport.capabilities()?.request(Capability::SPI).ok()?; + let context = context.downcast_ref::().unwrap(); + let spi_bus = context.params.create(transport, "BOOTSTRAP")?; + Ok(Some(Box::new(SpiFlashromArgsResponse { + programmer: spi_bus.get_flashrom_programmer()?, + }))) + } +} + /// Commands for interacting with a SPI EEPROM. #[derive(Debug, Subcommand, CommandDispatch)] pub enum InternalSpiCommand { @@ -429,6 +455,7 @@ pub enum InternalSpiCommand { RawWriteRead(SpiRawWriteRead), RawTransceive(SpiRawTransceive), Tpm(SpiTpm), + FlashromArgs(SpiFlashromArgs), } #[derive(Debug, Args)]