opentitanlib/transport/
mod.rs1use anyhow::Result;
6use bitflags::bitflags;
7use serde::{Deserialize, Serialize};
8use std::any::Any;
9use std::collections::HashMap;
10use std::path::PathBuf;
11use std::rc::Rc;
12
13use crate::bootstrap::BootstrapOptions;
14use crate::io::emu::Emulator;
15use crate::io::gpio::{GpioBitbanging, GpioMonitoring, GpioPin};
16use crate::io::i2c::Bus;
17use crate::io::jtag::{JtagChain, JtagParams};
18use crate::io::spi::Target;
19use crate::io::uart::Uart;
20
21pub mod common;
22pub mod ioexpander;
23
24mod errors;
26pub use errors::{TransportError, TransportInterfaceType};
27
28bitflags! {
29 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
31 #[serde(transparent)]
32 pub struct Capability: u32 {
33 const NONE = 0x00;
34 const UART = 0x01 << 0;
35 const SPI = 0x01 << 1;
36 const GPIO = 0x01 << 2;
37 const I2C = 0x01 << 3;
38 const PROXY = 0x01 << 4;
39 const EMULATOR = 0x01 << 5;
40 const GPIO_MONITORING = 0x01 << 6; const JTAG = 0x01 << 7;
42 const UART_NONBLOCKING = 0x01 << 8;
43 const SPI_DUAL = 0x01 << 9;
44 const SPI_QUAD = 0x01 << 10;
45 const GPIO_BITBANGING = 0x01 << 11;
46 }
47}
48
49#[derive(Serialize, Deserialize)]
51pub struct Capabilities {
52 capabilities: Capability,
53}
54
55impl Capabilities {
56 pub fn new(cap: Capability) -> Self {
59 Self { capabilities: cap }
60 }
61
62 pub fn add(&self, extra: Capability) -> Self {
63 Self {
64 capabilities: self.capabilities | extra,
65 }
66 }
67
68 pub fn request(&self, needed: Capability) -> NeededCapabilities {
70 NeededCapabilities {
71 capabilities: self.capabilities,
72 needed,
73 }
74 }
75}
76
77pub struct NeededCapabilities {
79 capabilities: Capability,
80 needed: Capability,
81}
82
83impl NeededCapabilities {
84 pub fn ok(&self) -> Result<()> {
86 if self.capabilities & self.needed != self.needed {
87 Err(TransportError::MissingCapabilities(self.needed, self.capabilities).into())
88 } else {
89 Ok(())
90 }
91 }
92}
93
94pub trait Transport {
97 fn capabilities(&self) -> Result<Capabilities>;
100
101 fn apply_default_configuration(&self) -> Result<()> {
104 Ok(())
105 }
106
107 fn jtag(&self, _opts: &JtagParams) -> Result<Box<dyn JtagChain + '_>> {
109 Err(TransportError::InvalidInterface(TransportInterfaceType::Jtag).into())
110 }
111 fn spi(&self, _instance: &str) -> Result<Rc<dyn Target>> {
113 Err(TransportError::InvalidInterface(TransportInterfaceType::Spi).into())
114 }
115 fn i2c(&self, _instance: &str) -> Result<Rc<dyn Bus>> {
117 Err(TransportError::InvalidInterface(TransportInterfaceType::I2c).into())
118 }
119 fn uart(&self, _instance: &str) -> Result<Rc<dyn Uart>> {
121 Err(TransportError::InvalidInterface(TransportInterfaceType::Uart).into())
122 }
123 fn gpio_pin(&self, _instance: &str) -> Result<Rc<dyn GpioPin>> {
125 Err(TransportError::InvalidInterface(TransportInterfaceType::Gpio).into())
126 }
127 fn gpio_monitoring(&self) -> Result<Rc<dyn GpioMonitoring>> {
129 Err(TransportError::InvalidInterface(TransportInterfaceType::GpioMonitoring).into())
130 }
131 fn gpio_bitbanging(&self) -> Result<Rc<dyn GpioBitbanging>> {
134 Err(TransportError::InvalidInterface(TransportInterfaceType::GpioBitbanging).into())
135 }
136 fn emulator(&self) -> Result<&dyn Emulator> {
138 Err(TransportError::InvalidInterface(TransportInterfaceType::Emulator).into())
139 }
140
141 fn fpga_ops(&self) -> Result<&dyn FpgaOps> {
143 Err(TransportError::InvalidInterface(TransportInterfaceType::FpgaOps).into())
144 }
145
146 fn proxy_ops(&self) -> Result<&dyn ProxyOps> {
148 Err(TransportError::InvalidInterface(TransportInterfaceType::ProxyOps).into())
149 }
150
151 fn dispatch(&self, _action: &dyn Any) -> Result<Option<Box<dyn erased_serde::Serialize>>> {
153 Err(TransportError::UnsupportedOperation.into())
154 }
155
156 fn relinquish_exclusive_access(&self, callback: Box<dyn FnOnce() + '_>) -> Result<()> {
165 callback();
166 Ok(())
167 }
168}
169
170pub trait FpgaOps {
172 fn load_bitstream(&self, bitstream: &[u8], progress: &dyn ProgressIndicator) -> Result<()>;
173
174 fn clear_bitstream(&self) -> Result<()>;
175}
176
177pub trait ProxyOps {
179 fn provides_map(&self) -> Result<HashMap<String, String>>;
184
185 fn bootstrap(&self, options: &BootstrapOptions, payload: &[u8]) -> Result<()>;
186 fn apply_pin_strapping(&self, strapping_name: &str) -> Result<()>;
187 fn remove_pin_strapping(&self, strapping_name: &str) -> Result<()>;
188
189 fn apply_default_configuration_with_strap(&self, strapping_name: &str) -> Result<()>;
191}
192
193pub struct Bootstrap {
199 pub image_path: PathBuf,
200}
201
202pub struct SetJtagPins {
204 pub tclk: Option<Rc<dyn GpioPin>>,
205 pub tms: Option<Rc<dyn GpioPin>>,
206 pub tdi: Option<Rc<dyn GpioPin>>,
207 pub tdo: Option<Rc<dyn GpioPin>>,
208 pub trst: Option<Rc<dyn GpioPin>>,
209}
210
211pub trait ProgressIndicator {
212 fn new_stage(&self, name: &str, total: usize);
215 fn progress(&self, absolute: usize);
218}
219
220pub struct UpdateFirmware<'a> {
222 pub firmware: Option<Vec<u8>>,
226 pub progress: Box<dyn ProgressIndicator + 'a>,
228 pub force: bool,
231}
232
233pub struct EmptyTransport;
235
236impl Transport for EmptyTransport {
237 fn capabilities(&self) -> Result<Capabilities> {
238 Ok(Capabilities::new(Capability::NONE))
239 }
240}
241
242#[cfg(test)]
243pub mod tests {
244 use super::*;
245
246 #[test]
247 fn test_capabilities_met() -> anyhow::Result<()> {
248 let cap = Capabilities::new(Capability::UART | Capability::SPI);
249 assert!(cap.request(Capability::UART).ok().is_ok());
250 Ok(())
251 }
252
253 #[test]
254 fn test_capabilities_not_met() -> anyhow::Result<()> {
255 let cap = Capabilities::new(Capability::UART | Capability::SPI);
256 assert!(cap.request(Capability::GPIO).ok().is_err());
257 Ok(())
258 }
259}