From 4c95198469c126cf3ebe1b2d80cdbb703153e2da Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Fri, 14 Feb 2025 13:08:11 -0800 Subject: [PATCH 1/3] [opentitanlib] Refactor rescue into a trait Signed-off-by: Chris Frantz (cherry picked from commit 8aa221be8ca01915666e292923f07b09a2a40dd8) --- sw/host/opentitanlib/src/rescue/mod.rs | 91 ++++++++++++++++ sw/host/opentitanlib/src/rescue/serial.rs | 100 +++--------------- sw/host/opentitanlib/src/rescue/xmodem.rs | 3 +- sw/host/opentitantool/src/command/rescue.rs | 15 +-- .../tests/ownership/flash_permission_test.rs | 1 + sw/host/tests/ownership/newversion_test.rs | 1 + sw/host/tests/ownership/rescue_limit_test.rs | 1 + .../tests/ownership/rescue_permission_test.rs | 1 + sw/host/tests/ownership/transfer_lib.rs | 1 + sw/host/tests/ownership/transfer_test.rs | 1 + 10 files changed, 123 insertions(+), 92 deletions(-) diff --git a/sw/host/opentitanlib/src/rescue/mod.rs b/sw/host/opentitanlib/src/rescue/mod.rs index 319a252a961c2..c071d9b7d4135 100644 --- a/sw/host/opentitanlib/src/rescue/mod.rs +++ b/sw/host/opentitanlib/src/rescue/mod.rs @@ -2,8 +2,15 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +use anyhow::Result; use thiserror::Error; +use crate::app::TransportWrapper; +use crate::chip::boot_log::BootLog; +use crate::chip::boot_svc::{BootSlot, BootSvc, OwnershipActivateRequest, OwnershipUnlockRequest}; +use crate::chip::device_id::DeviceId; +use crate::with_unknown; + pub mod serial; pub mod xmodem; @@ -12,3 +19,87 @@ pub enum RescueError { #[error("bad mode: {0}")] BadMode(String), } + +with_unknown! { +pub enum RescueMode: u32 { + Rescue = u32::from_be_bytes(*b"RESQ"), + RescueB = u32::from_be_bytes(*b"RESB"), + BootLog = u32::from_be_bytes(*b"BLOG"), + BootSvcReq = u32::from_be_bytes(*b"BREQ"), + BootSvcRsp = u32::from_be_bytes(*b"BRSP"), + OwnerBlock = u32::from_be_bytes(*b"OWNR"), + GetOwnerPage0 = u32::from_be_bytes(*b"OPG0"), + GetOwnerPage1 = u32::from_be_bytes(*b"OPG1"), + DeviceId = u32::from_be_bytes(*b"OTID"), + EraseOwner = u32::from_be_bytes(*b"KLBR"), +} +} + +pub trait Rescue { + fn enter(&self, transport: &TransportWrapper, reset_target: bool) -> Result<()>; + fn set_mode(&self, mode: RescueMode) -> Result<()>; + fn send(&self, data: &[u8]) -> Result<()>; + fn recv(&self) -> Result>; + + // Not supported by all backends + fn set_speed(&self, speed: u32) -> Result<()>; + fn wait(&self) -> Result<()>; + fn reboot(&self) -> Result<()>; + + fn get_raw(&self, mode: RescueMode) -> Result> { + self.set_mode(mode)?; + self.recv() + } + + fn set_raw(&self, mode: RescueMode, data: &[u8]) -> Result<()> { + self.set_mode(mode)?; + self.send(data) + } + + fn update_firmware(&self, slot: BootSlot, image: &[u8]) -> Result<()> { + let mode = if slot == BootSlot::SlotB { + RescueMode::RescueB + } else { + RescueMode::Rescue + }; + self.set_raw(mode, image) + } + + fn get_boot_log(&self) -> Result { + let blog = self.get_raw(RescueMode::BootLog)?; + Ok(BootLog::try_from(blog.as_slice())?) + } + + fn get_boot_svc(&self) -> Result { + let bsvc = self.get_raw(RescueMode::BootSvcRsp)?; + Ok(BootSvc::try_from(bsvc.as_slice())?) + } + + fn get_device_id(&self) -> Result { + let id = self.get_raw(RescueMode::DeviceId)?; + DeviceId::read(&mut std::io::Cursor::new(&id)) + } + + fn set_next_bl0_slot(&self, primary: BootSlot, next: BootSlot) -> Result<()> { + let message = BootSvc::next_boot_bl0_slot(primary, next); + self.set_raw(RescueMode::BootSvcReq, &message.to_bytes()?) + } + + fn ownership_unlock(&self, unlock: OwnershipUnlockRequest) -> Result<()> { + let message = BootSvc::ownership_unlock(unlock); + self.set_raw(RescueMode::BootSvcReq, &message.to_bytes()?) + } + + fn ownership_activate(&self, activate: OwnershipActivateRequest) -> Result<()> { + let message = BootSvc::ownership_activate(activate); + self.set_raw(RescueMode::BootSvcReq, &message.to_bytes()?) + } + + fn set_owner_config(&self, data: &[u8]) -> Result<()> { + self.set_raw(RescueMode::OwnerBlock, data) + } + + fn erase_owner(&self) -> Result<()> { + self.set_raw(RescueMode::EraseOwner, &[]) + } +} diff --git a/sw/host/opentitanlib/src/rescue/serial.rs b/sw/host/opentitanlib/src/rescue/serial.rs index 309fcb4db40de..094a8b43c4ddb 100644 --- a/sw/host/opentitanlib/src/rescue/serial.rs +++ b/sw/host/opentitanlib/src/rescue/serial.rs @@ -7,15 +7,12 @@ use std::rc::Rc; use std::time::Duration; use crate::app::{TransportWrapper, UartRx}; -use crate::chip::boot_log::BootLog; -use crate::chip::boot_svc::{BootSlot, BootSvc, OwnershipActivateRequest, OwnershipUnlockRequest}; -use crate::chip::device_id::DeviceId; use crate::io::console::ConsoleExt; use crate::io::console::ext::{PassFail, PassFailResult}; use crate::io::uart::Uart; use crate::regex; -use crate::rescue::RescueError; use crate::rescue::xmodem::Xmodem; +use crate::rescue::{Rescue, RescueError, RescueMode}; pub struct RescueSerial { uart: Rc, @@ -25,19 +22,9 @@ pub struct RescueSerial { impl RescueSerial { const ONE_SECOND: Duration = Duration::from_secs(1); - pub const RESCUE: [u8; 4] = *b"RESQ"; - pub const RESCUE_B: [u8; 4] = *b"RESB"; - pub const REBOOT: [u8; 4] = *b"REBO"; - pub const BAUD: [u8; 4] = *b"BAUD"; - pub const BOOT_LOG: [u8; 4] = *b"BLOG"; - pub const BOOT_SVC_REQ: [u8; 4] = *b"BREQ"; - pub const BOOT_SVC_RSP: [u8; 4] = *b"BRSP"; - pub const OWNER_BLOCK: [u8; 4] = *b"OWNR"; - pub const GET_OWNER_PAGE0: [u8; 4] = *b"OPG0"; - pub const GET_OWNER_PAGE1: [u8; 4] = *b"OPG1"; - pub const OT_ID: [u8; 4] = *b"OTID"; - pub const ERASE_OWNER: [u8; 4] = *b"KLBR"; - pub const WAIT: [u8; 4] = *b"WAIT"; + pub const REBOOT: RescueMode = RescueMode(u32::from_be_bytes(*b"REBO")); + pub const BAUD: RescueMode = RescueMode(u32::from_be_bytes(*b"BAUD")); + pub const WAIT: RescueMode = RescueMode(u32::from_be_bytes(*b"WAIT")); const BAUD_115K: [u8; 4] = *b"115K"; const BAUD_230K: [u8; 4] = *b"230K"; @@ -53,8 +40,10 @@ impl RescueSerial { enter_delay: Duration::from_secs(5), } } +} - pub fn enter(&self, transport: &TransportWrapper, reset_target: bool) -> Result<()> { +impl Rescue for RescueSerial { + fn enter(&self, transport: &TransportWrapper, reset_target: bool) -> Result<()> { log::info!("Setting serial break to trigger rescue mode."); self.uart.set_break(true)?; if reset_target { @@ -73,7 +62,7 @@ impl RescueSerial { Ok(()) } - pub fn set_baud(&self, baud: u32) -> Result<()> { + fn set_speed(&self, baud: u32) -> Result<()> { // Make sure the requested rate is a known rate. let symbol = match baud { 115200 => Self::BAUD_115K, @@ -87,7 +76,7 @@ impl RescueSerial { // Request to change rates. We don't use `set_mode` here because changing // rates isn't a "mode" request and doesn't respond the same way. - self.uart.write(&Self::BAUD)?; + self.uart.write(&Self::BAUD.0.to_be_bytes())?; self.uart.write(b"\r")?; if let PassFailResult::Fail(result) = (&self.uart) .logged() @@ -109,7 +98,8 @@ impl RescueSerial { Ok(()) } - pub fn set_mode(&self, mode: [u8; 4]) -> Result<()> { + fn set_mode(&self, mode: RescueMode) -> Result<()> { + let mode = mode.0.to_be_bytes(); self.uart.write(&mode)?; let enter = b'\r'; self.uart.write(std::slice::from_ref(&enter))?; @@ -126,84 +116,26 @@ impl RescueSerial { Ok(()) } - pub fn wait(&self) -> Result<()> { + fn wait(&self) -> Result<()> { self.set_mode(Self::WAIT)?; Ok(()) } - pub fn reboot(&self) -> Result<()> { + fn reboot(&self) -> Result<()> { self.set_mode(Self::REBOOT)?; Ok(()) } - pub fn update_firmware(&self, slot: BootSlot, image: &[u8]) -> Result<()> { - self.set_mode(if slot == BootSlot::SlotB { - Self::RESCUE_B - } else { - Self::RESCUE - })?; + fn send(&self, data: &[u8]) -> Result<()> { let xm = Xmodem::new(); - xm.send(&*self.uart, image)?; + xm.send(&*self.uart, data)?; Ok(()) } - pub fn get_raw(&self, mode: [u8; 4]) -> Result> { - self.set_mode(mode)?; + fn recv(&self) -> Result> { let mut data = Vec::new(); let xm = Xmodem::new(); xm.receive(&*self.uart, &mut data)?; Ok(data) } - - pub fn get_boot_log(&self) -> Result { - let blog = self.get_raw(Self::BOOT_LOG)?; - Ok(BootLog::try_from(blog.as_slice())?) - } - - pub fn get_boot_svc(&self) -> Result { - let bsvc = self.get_raw(Self::BOOT_SVC_RSP)?; - Ok(BootSvc::try_from(bsvc.as_slice())?) - } - - pub fn get_device_id(&self) -> Result { - let id = self.get_raw(Self::OT_ID)?; - DeviceId::read(&mut std::io::Cursor::new(&id)) - } - - pub fn set_boot_svc_raw(&self, data: &[u8]) -> Result<()> { - self.set_mode(Self::BOOT_SVC_REQ)?; - let xm = Xmodem::new(); - xm.send(&*self.uart, data)?; - Ok(()) - } - - pub fn set_next_bl0_slot(&self, primary: BootSlot, next: BootSlot) -> Result<()> { - let message = BootSvc::next_boot_bl0_slot(primary, next); - let data = message.to_bytes()?; - self.set_boot_svc_raw(&data) - } - - pub fn ownership_unlock(&self, unlock: OwnershipUnlockRequest) -> Result<()> { - let message = BootSvc::ownership_unlock(unlock); - let data = message.to_bytes()?; - self.set_boot_svc_raw(&data) - } - - pub fn ownership_activate(&self, activate: OwnershipActivateRequest) -> Result<()> { - let message = BootSvc::ownership_activate(activate); - let data = message.to_bytes()?; - self.set_boot_svc_raw(&data) - } - - pub fn set_owner_config(&self, data: &[u8]) -> Result<()> { - self.set_mode(Self::OWNER_BLOCK)?; - let xm = Xmodem::new(); - xm.send(&*self.uart, data)?; - Ok(()) - } - - pub fn erase_owner(&self) -> Result<()> { - self.set_mode(Self::ERASE_OWNER)?; - Ok(()) - } } diff --git a/sw/host/opentitanlib/src/rescue/xmodem.rs b/sw/host/opentitanlib/src/rescue/xmodem.rs index 3cada7ceb80b9..da1c0f284007b 100644 --- a/sw/host/opentitanlib/src/rescue/xmodem.rs +++ b/sw/host/opentitanlib/src/rescue/xmodem.rs @@ -190,7 +190,8 @@ impl Xmodem { } _ => { return Err(XmodemError::UnsupportedMode(format!( - "bad start of packet: {byte:?}" + "bad start of packet: {byte:02x} ({})", + byte as char )) .into()); } diff --git a/sw/host/opentitantool/src/command/rescue.rs b/sw/host/opentitantool/src/command/rescue.rs index 70f5d82575d52..69eb375e0550d 100644 --- a/sw/host/opentitantool/src/command/rescue.rs +++ b/sw/host/opentitantool/src/command/rescue.rs @@ -20,6 +20,7 @@ use opentitanlib::image::image::Image; use opentitanlib::image::manifest::ManifestKind; use opentitanlib::ownership::{OwnerBlock, TlvHeader}; use opentitanlib::rescue::serial::RescueSerial; +use opentitanlib::rescue::{Rescue, RescueMode}; use opentitanlib::util::file::FromReader; use opentitanlib::util::parse_int::ParseInt; @@ -99,7 +100,7 @@ impl CommandDispatch for Firmware { rescue.enter(transport, self.reset_target)?; if let Some(rate) = self.rate { prev_baudrate = uart.get_baudrate()?; - rescue.set_baud(rate)?; + rescue.set_speed(rate)?; } rescue.wait()?; if self.erase_other_slot { @@ -112,7 +113,7 @@ impl CommandDispatch for Firmware { } rescue.update_firmware(self.slot, payload)?; if self.rate.is_some() { - rescue.set_baud(prev_baudrate)?; + rescue.set_speed(prev_baudrate)?; } if !self.wait { transport.reset_with_delay(UartRx::Keep, Duration::from_millis(50))?; @@ -146,7 +147,7 @@ impl CommandDispatch for GetBootLog { let rescue = RescueSerial::new(uart); rescue.enter(transport, self.reset_target)?; if self.raw { - let data = rescue.get_raw(RescueSerial::BOOT_LOG)?; + let data = rescue.get_raw(RescueMode::BootLog)?; Ok(Some(Box::new(RawBytes(data)))) } else { let data = rescue.get_boot_log()?; @@ -180,7 +181,7 @@ impl CommandDispatch for GetBootSvc { let rescue = RescueSerial::new(uart); rescue.enter(transport, self.reset_target)?; if self.raw { - let data = rescue.get_raw(RescueSerial::BOOT_SVC_RSP)?; + let data = rescue.get_raw(RescueMode::BootSvcRsp)?; Ok(Some(Box::new(RawBytes(data)))) } else { let data = rescue.get_boot_svc()?; @@ -214,7 +215,7 @@ impl CommandDispatch for GetDeviceId { let rescue = RescueSerial::new(uart); rescue.enter(transport, self.reset_target)?; if self.raw { - let data = rescue.get_raw(RescueSerial::OT_ID)?; + let data = rescue.get_raw(RescueMode::DeviceId)?; Ok(Some(Box::new(RawBytes(data)))) } else { let data = rescue.get_device_id()?; @@ -437,8 +438,8 @@ impl CommandDispatch for GetOwnerConfig { transport: &TransportWrapper, ) -> Result>> { let page = match self.page { - 0 => RescueSerial::GET_OWNER_PAGE0, - 1 => RescueSerial::GET_OWNER_PAGE1, + 0 => RescueMode::GetOwnerPage0, + 1 => RescueMode::GetOwnerPage1, _ => return Err(anyhow!("Unsupported page {}", self.page)), }; let uart = self.params.create(transport)?; diff --git a/sw/host/tests/ownership/flash_permission_test.rs b/sw/host/tests/ownership/flash_permission_test.rs index 4aac5967ae30d..d7b13a798f788 100644 --- a/sw/host/tests/ownership/flash_permission_test.rs +++ b/sw/host/tests/ownership/flash_permission_test.rs @@ -12,6 +12,7 @@ use std::time::Duration; use opentitanlib::app::{TransportWrapper, UartRx}; use opentitanlib::chip::boot_svc::{BootSlot, UnlockMode}; use opentitanlib::chip::rom_error::RomError; +use opentitanlib::rescue::Rescue; use opentitanlib::rescue::serial::RescueSerial; use opentitanlib::test_utils::init::InitializeTest; use opentitanlib::uart::console::UartConsole; diff --git a/sw/host/tests/ownership/newversion_test.rs b/sw/host/tests/ownership/newversion_test.rs index 32d18ca50ba90..0b33186883493 100644 --- a/sw/host/tests/ownership/newversion_test.rs +++ b/sw/host/tests/ownership/newversion_test.rs @@ -11,6 +11,7 @@ use std::time::Duration; use opentitanlib::app::{TransportWrapper, UartRx}; use opentitanlib::chip::rom_error::RomError; +use opentitanlib::rescue::Rescue; use opentitanlib::rescue::serial::RescueSerial; use opentitanlib::test_utils::init::InitializeTest; use opentitanlib::uart::console::UartConsole; diff --git a/sw/host/tests/ownership/rescue_limit_test.rs b/sw/host/tests/ownership/rescue_limit_test.rs index 95aacc9462eda..551d2d9bd96f4 100644 --- a/sw/host/tests/ownership/rescue_limit_test.rs +++ b/sw/host/tests/ownership/rescue_limit_test.rs @@ -12,6 +12,7 @@ use std::time::Duration; use opentitanlib::app::{TransportWrapper, UartRx}; use opentitanlib::chip::boot_svc::{BootSlot, UnlockMode}; use opentitanlib::chip::rom_error::RomError; +use opentitanlib::rescue::Rescue; use opentitanlib::rescue::serial::RescueSerial; use opentitanlib::test_utils::init::InitializeTest; use opentitanlib::uart::console::UartConsole; diff --git a/sw/host/tests/ownership/rescue_permission_test.rs b/sw/host/tests/ownership/rescue_permission_test.rs index 02db26301a2be..046ac82313363 100644 --- a/sw/host/tests/ownership/rescue_permission_test.rs +++ b/sw/host/tests/ownership/rescue_permission_test.rs @@ -11,6 +11,7 @@ use std::time::Duration; use opentitanlib::app::TransportWrapper; use opentitanlib::chip::boot_svc::{BootSlot, UnlockMode}; +use opentitanlib::rescue::Rescue; use opentitanlib::rescue::serial::RescueSerial; use opentitanlib::test_utils::init::InitializeTest; diff --git a/sw/host/tests/ownership/transfer_lib.rs b/sw/host/tests/ownership/transfer_lib.rs index abfba4e5e22ae..41981a98c4ab9 100644 --- a/sw/host/tests/ownership/transfer_lib.rs +++ b/sw/host/tests/ownership/transfer_lib.rs @@ -16,6 +16,7 @@ use opentitanlib::ownership::{ OwnerConfigItem, OwnerFlashConfig, OwnerFlashInfoConfig, OwnerFlashRegion, OwnerInfoPage, OwnerRescueConfig, OwnershipKeyAlg, }; +use opentitanlib::rescue::Rescue; use opentitanlib::rescue::serial::RescueSerial; use std::path::Path; diff --git a/sw/host/tests/ownership/transfer_test.rs b/sw/host/tests/ownership/transfer_test.rs index 490989d4f6cb5..8b7765327c158 100644 --- a/sw/host/tests/ownership/transfer_test.rs +++ b/sw/host/tests/ownership/transfer_test.rs @@ -12,6 +12,7 @@ use std::time::Duration; use opentitanlib::app::{TransportWrapper, UartRx}; use opentitanlib::chip::boot_svc::{BootSlot, UnlockMode}; use opentitanlib::chip::rom_error::RomError; +use opentitanlib::rescue::Rescue; use opentitanlib::rescue::serial::RescueSerial; use opentitanlib::test_utils::init::InitializeTest; use opentitanlib::uart::console::UartConsole; From eba90bf5d551b2168ccadcfe0bb6e9cd8031908c Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Fri, 14 Feb 2025 15:51:08 -0800 Subject: [PATCH 2/3] [opentitanlib] Refactor rescue protocol creation Signed-off-by: Chris Frantz (cherry picked from commit 0ce26d6deccaf7d31c219beb01596e6ed6a35121) --- sw/host/opentitanlib/src/io/uart/mod.rs | 2 +- sw/host/opentitanlib/src/rescue/mod.rs | 73 ++++++++++++- sw/host/opentitanlib/src/rescue/serial.rs | 5 +- sw/host/opentitantool/src/command/rescue.rs | 110 ++++++++++---------- sw/host/opentitantool/src/main.rs | 1 - 5 files changed, 129 insertions(+), 62 deletions(-) diff --git a/sw/host/opentitanlib/src/io/uart/mod.rs b/sw/host/opentitanlib/src/io/uart/mod.rs index 1c7619392f42b..ccb31e982011b 100644 --- a/sw/host/opentitanlib/src/io/uart/mod.rs +++ b/sw/host/opentitanlib/src/io/uart/mod.rs @@ -20,7 +20,7 @@ use crate::transport::TransportError; pub mod flow; pub mod serial; -#[derive(Clone, Debug, Args, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, Args, Serialize, Deserialize)] pub struct UartParams { /// UART instance. #[arg(long, default_value = "CONSOLE")] diff --git a/sw/host/opentitanlib/src/rescue/mod.rs b/sw/host/opentitanlib/src/rescue/mod.rs index c071d9b7d4135..95cd44746f4d9 100644 --- a/sw/host/opentitanlib/src/rescue/mod.rs +++ b/sw/host/opentitanlib/src/rescue/mod.rs @@ -2,22 +2,91 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -use anyhow::Result; +use anyhow::{Result, ensure}; +use clap::{Args, ValueEnum}; use thiserror::Error; use crate::app::TransportWrapper; use crate::chip::boot_log::BootLog; use crate::chip::boot_svc::{BootSlot, BootSvc, OwnershipActivateRequest, OwnershipUnlockRequest}; use crate::chip::device_id::DeviceId; +use crate::io::uart::UartParams; use crate::with_unknown; pub mod serial; pub mod xmodem; +pub use serial::RescueSerial; + #[derive(Debug, Error)] pub enum RescueError { #[error("bad mode: {0}")] BadMode(String), + #[error("configuration error: {0}")] + Configuration(String), +} + +#[derive(ValueEnum, Default, Debug, Clone, Copy, PartialEq)] +pub enum RescueProtocol { + #[default] + Xmodem, + UsbDfu, + SpiDfu, +} + +#[derive(ValueEnum, Default, Debug, Clone, Copy, PartialEq)] +pub enum RescueTrigger { + #[default] + SerialBreak, + Gpio, + Strap, +} + +#[derive(Clone, Default, Debug, Args)] +pub struct RescueParams { + /// Rescue Protocol + #[arg(short, long, value_enum, default_value_t = RescueProtocol::Xmodem)] + pub protocol: RescueProtocol, + #[arg(short, long, value_enum, default_value_t = RescueTrigger::SerialBreak)] + pub trigger: RescueTrigger, + #[arg(short, long, default_value = "")] + pub value: String, + #[command(flatten)] + uart: UartParams, +} + +impl RescueParams { + pub fn create(&self, transport: &TransportWrapper) -> Result> { + match self.protocol { + RescueProtocol::Xmodem => self.create_serial(transport), + RescueProtocol::UsbDfu => self.create_usbdfu(transport), + RescueProtocol::SpiDfu => self.create_spidfu(transport), + } + } + fn create_serial(&self, transport: &TransportWrapper) -> Result> { + ensure!( + self.trigger == RescueTrigger::SerialBreak, + RescueError::Configuration(format!( + "Xmodem does not support trigger {:?}", + self.trigger + )) + ); + ensure!( + self.value.is_empty(), + RescueError::Configuration(format!( + "Xmodem does not support trigger value {:?}", + self.value + )) + ); + + Ok(Box::new(RescueSerial::new(self.uart.create(transport)?))) + } + fn create_usbdfu(&self, _transport: &TransportWrapper) -> Result> { + unimplemented!() + } + fn create_spidfu(&self, _transport: &TransportWrapper) -> Result> { + unimplemented!() + } } with_unknown! { @@ -42,7 +111,7 @@ pub trait Rescue { fn recv(&self) -> Result>; // Not supported by all backends - fn set_speed(&self, speed: u32) -> Result<()>; + fn set_speed(&self, speed: u32) -> Result; fn wait(&self) -> Result<()>; fn reboot(&self) -> Result<()>; diff --git a/sw/host/opentitanlib/src/rescue/serial.rs b/sw/host/opentitanlib/src/rescue/serial.rs index 094a8b43c4ddb..60751ea7dfde3 100644 --- a/sw/host/opentitanlib/src/rescue/serial.rs +++ b/sw/host/opentitanlib/src/rescue/serial.rs @@ -62,7 +62,7 @@ impl Rescue for RescueSerial { Ok(()) } - fn set_speed(&self, baud: u32) -> Result<()> { + fn set_speed(&self, baud: u32) -> Result { // Make sure the requested rate is a known rate. let symbol = match baud { 115200 => Self::BAUD_115K, @@ -94,8 +94,9 @@ impl Rescue for RescueSerial { return Err(RescueError::BadMode(result[0].clone()).into()); } // Change our side of the connection to the new rate. + let old = self.uart.get_baudrate()?; self.uart.set_baudrate(baud)?; - Ok(()) + Ok(old) } fn set_mode(&self, mode: RescueMode) -> Result<()> { diff --git a/sw/host/opentitantool/src/command/rescue.rs b/sw/host/opentitantool/src/command/rescue.rs index 69eb375e0550d..cbb280847b671 100644 --- a/sw/host/opentitantool/src/command/rescue.rs +++ b/sw/host/opentitantool/src/command/rescue.rs @@ -9,7 +9,6 @@ use std::time::Duration; use anyhow::{Result, anyhow}; use clap::{Args, Subcommand}; -use opentitanlib::io::uart::UartParams; use serde_annotate::Annotate; use opentitanlib::app::command::CommandDispatch; @@ -19,8 +18,7 @@ use opentitanlib::chip::helper::{OwnershipActivateParams, OwnershipUnlockParams} use opentitanlib::image::image::Image; use opentitanlib::image::manifest::ManifestKind; use opentitanlib::ownership::{OwnerBlock, TlvHeader}; -use opentitanlib::rescue::serial::RescueSerial; -use opentitanlib::rescue::{Rescue, RescueMode}; +use opentitanlib::rescue::{RescueMode, RescueParams}; use opentitanlib::util::file::FromReader; use opentitanlib::util::parse_int::ParseInt; @@ -33,8 +31,6 @@ pub struct RawBytes( #[derive(Debug, Args)] pub struct Firmware { - #[command(flatten)] - params: UartParams, #[arg(long, help = "After connecting to rescue, negotiate faster baudrate")] rate: Option, #[arg(long, default_value = "SlotA", help = "Which flash slot to rescue")] @@ -70,7 +66,7 @@ pub struct Firmware { impl CommandDispatch for Firmware { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { let image = Image::read_from_file(&self.filename)?; @@ -94,13 +90,12 @@ impl CommandDispatch for Firmware { } subimage.data }; - let uart = self.params.create(transport)?; + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; let mut prev_baudrate = 0u32; - let rescue = RescueSerial::new(uart.clone()); rescue.enter(transport, self.reset_target)?; if let Some(rate) = self.rate { - prev_baudrate = uart.get_baudrate()?; - rescue.set_speed(rate)?; + prev_baudrate = rescue.set_speed(rate)?; } rescue.wait()?; if self.erase_other_slot { @@ -124,8 +119,6 @@ impl CommandDispatch for Firmware { #[derive(Debug, Args)] pub struct GetBootLog { - #[command(flatten)] - params: UartParams, #[arg( long, default_value_t = true, @@ -140,11 +133,11 @@ pub struct GetBootLog { impl CommandDispatch for GetBootLog { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; if self.raw { let data = rescue.get_raw(RescueMode::BootLog)?; @@ -158,8 +151,6 @@ impl CommandDispatch for GetBootLog { #[derive(Debug, Args)] pub struct GetBootSvc { - #[command(flatten)] - params: UartParams, #[arg( long, default_value_t = true, @@ -174,11 +165,11 @@ pub struct GetBootSvc { impl CommandDispatch for GetBootSvc { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; if self.raw { let data = rescue.get_raw(RescueMode::BootSvcRsp)?; @@ -192,8 +183,6 @@ impl CommandDispatch for GetBootSvc { #[derive(Debug, Args)] pub struct GetDeviceId { - #[command(flatten)] - params: UartParams, #[arg( long, default_value_t = true, @@ -208,11 +197,11 @@ pub struct GetDeviceId { impl CommandDispatch for GetDeviceId { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; if self.raw { let data = rescue.get_raw(RescueMode::DeviceId)?; @@ -226,8 +215,6 @@ impl CommandDispatch for GetDeviceId { #[derive(Debug, Args)] pub struct SetNextBl0Slot { - #[command(flatten)] - params: UartParams, #[arg( long, short, @@ -261,11 +248,11 @@ pub struct SetNextBl0Slot { impl CommandDispatch for SetNextBl0Slot { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; rescue.set_next_bl0_slot(self.primary, self.next)?; if self.get_response { @@ -281,8 +268,6 @@ impl CommandDispatch for SetNextBl0Slot { #[derive(Debug, Args)] pub struct OwnershipUnlock { - #[command(flatten)] - params: UartParams, #[arg( long, default_value_t = true, @@ -306,15 +291,15 @@ pub struct OwnershipUnlock { impl CommandDispatch for OwnershipUnlock { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { let unlock = self .unlock .apply_to(self.input.as_ref().map(File::open).transpose()?.as_mut())?; - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; rescue.ownership_unlock(unlock)?; if self.get_response { @@ -330,8 +315,6 @@ impl CommandDispatch for OwnershipUnlock { #[derive(Debug, Args)] pub struct OwnershipActivate { - #[command(flatten)] - params: UartParams, #[arg( long, default_value_t = true, @@ -355,15 +338,15 @@ pub struct OwnershipActivate { impl CommandDispatch for OwnershipActivate { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { let activate = self .activate .apply_to(self.input.as_ref().map(File::open).transpose()?.as_mut())?; - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; rescue.ownership_activate(activate)?; if self.get_response { @@ -379,8 +362,6 @@ impl CommandDispatch for OwnershipActivate { #[derive(Debug, Args)] pub struct SetOwnerConfig { - #[command(flatten)] - params: UartParams, #[arg( long, default_value_t = true, @@ -395,12 +376,12 @@ pub struct SetOwnerConfig { impl CommandDispatch for SetOwnerConfig { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { let data = std::fs::read(&self.input)?; - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; rescue.set_owner_config(&data)?; Ok(None) @@ -409,8 +390,6 @@ impl CommandDispatch for SetOwnerConfig { #[derive(Debug, Args)] pub struct GetOwnerConfig { - #[command(flatten)] - params: UartParams, #[arg( long, default_value_t = true, @@ -434,7 +413,7 @@ pub struct GetOwnerConfig { impl CommandDispatch for GetOwnerConfig { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { let page = match self.page { @@ -442,8 +421,8 @@ impl CommandDispatch for GetOwnerConfig { 1 => RescueMode::GetOwnerPage1, _ => return Err(anyhow!("Unsupported page {}", self.page)), }; - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; let data = rescue.get_raw(page)?; if let Some(output) = &self.output { @@ -461,8 +440,6 @@ impl CommandDispatch for GetOwnerConfig { #[derive(Debug, Args)] pub struct EraseOwner { - #[command(flatten)] - params: UartParams, #[arg( long, default_value_t = true, @@ -477,12 +454,12 @@ pub struct EraseOwner { impl CommandDispatch for EraseOwner { fn run( &self, - _context: &dyn Any, + context: &dyn Any, transport: &TransportWrapper, ) -> Result>> { if self.really { - let uart = self.params.create(transport)?; - let rescue = RescueSerial::new(uart); + let context = context.downcast_ref::().unwrap(); + let rescue = context.params.create(transport)?; rescue.enter(transport, self.reset_target)?; rescue.erase_owner()?; Ok(None) @@ -503,7 +480,7 @@ pub enum BootSvcCommand { } #[derive(Debug, Subcommand, CommandDispatch)] -pub enum RescueCommand { +pub enum InternalRescueCommand { #[command(subcommand)] BootSvc(BootSvcCommand), EraseOwner(EraseOwner), @@ -513,3 +490,24 @@ pub enum RescueCommand { SetOwnerConfig(SetOwnerConfig), GetOwnerConfig(GetOwnerConfig), } + +#[derive(Debug, Args)] +pub struct RescueCommand { + #[command(flatten)] + params: RescueParams, + + #[command(subcommand)] + command: InternalRescueCommand, +} + +impl CommandDispatch for RescueCommand { + fn run( + &self, + _context: &dyn Any, + transport: &TransportWrapper, + ) -> Result>> { + // None of the SPI commands care about the prior context, but they do + // care about the `bus` parameter in the current node. + self.command.run(self, transport) + } +} diff --git a/sw/host/opentitantool/src/main.rs b/sw/host/opentitantool/src/main.rs index c5b2a3486b306..67033c6193a23 100644 --- a/sw/host/opentitantool/src/main.rs +++ b/sw/host/opentitantool/src/main.rs @@ -48,7 +48,6 @@ enum RootCommandHierarchy { Otp(command::otp::Otp), #[command(subcommand)] Ownership(command::ownership::OwnershipCommand), - #[command(subcommand)] Rescue(command::rescue::RescueCommand), #[command(subcommand)] Rsa(command::rsa::Rsa), From 4bd869b97af523763777edff4a621a07a6189a67 Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Tue, 18 Feb 2025 15:35:53 -0800 Subject: [PATCH 3/3] [rust] Update `rusb` to 0.9.4 Signed-off-by: Chris Frantz (cherry picked from commit 373fdcc967b037f338356d0fecda5a99c4317639) --- MODULE.bazel.lock | 2 +- third_party/rust/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index b2d4e7fbf1023..1f03fa98fde96 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -6311,7 +6311,7 @@ "@@//third_party/mdbook/Cargo.lock": "016b012024cd9dce5be7c958215a9e09e13f005f42f66b199adeebf8f711a1b6", "@@//third_party/mdbook/Cargo.toml": "334d3b905cce5adf4db0c4dbccd00adf5e99e68af9cdda0e40bc9d970a882eec", "@@//third_party/rust/Cargo.lock": "852ff88c998988d3b801355813df0f0a4001edb04016b967593955b449c39d7e", - "@@//third_party/rust/Cargo.toml": "e8860866a6899bfdfb8ca911f7d4ec07077af41299068c3fce5a4792ec59164c", + "@@//third_party/rust/Cargo.toml": "84317364285936c5ecaea5dc85a9c27af0159b5b74b9a898fbe062a8234e0e11", "@@//third_party/tock/Cargo.lock": "b5a7a833ae205f1e3697a510e97e3185b44b195d7a22879b4669bff95febd5c8", "@@//third_party/tock/Cargo.toml": "5a939bd934aef4775b65a82e678f1180ec00aa78cf214f6052cc82353c975cc4" }, diff --git a/third_party/rust/Cargo.toml b/third_party/rust/Cargo.toml index 90521e2a65442..9ac712bbec4af 100644 --- a/third_party/rust/Cargo.toml +++ b/third_party/rust/Cargo.toml @@ -67,7 +67,7 @@ rand_chacha = "0.3" regex = "1.7" reqwest = { version = "0.12.9", features = ["http2", "default-tls", "blocking", "json"] } rsa = "0.9.7" -rusb = "0.9.3" +rusb = "0.9.4" rustix = { version = "1", features = ["event", "fs", "net", "process", "stdio", "termios"] } scopeguard = "1.2" serde = { version = "1.0.188", features = ["derive"] }