opentitanlib/tpm/
driver.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::{Result, bail, ensure};
6use clap::ValueEnum;
7use serde::{Deserialize, Serialize};
8use std::rc::Rc;
9use std::thread;
10use std::time::{Duration, Instant};
11use thiserror::Error;
12
13use crate::io::i2c;
14use crate::io::spi;
15use crate::tpm::access::TpmAccess;
16use crate::tpm::status::TpmStatus;
17
18/// Tpm registers, can be specified in command line arguments.
19#[allow(non_camel_case_types)]
20#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, ValueEnum)]
21#[value(rename_all = "verbatim")]
22pub enum Register {
23    ACCESS,
24    INT_ENABLE,
25    INT_VECTOR,
26    INT_STATUS,
27    INTF_CAPABILITY,
28    STS,
29    DATA_FIFO,
30    INTERFACE_ID,
31    XDATA_FIFO,
32    DID_VID,
33    RID,
34}
35
36impl Register {
37    /// Size of given TPM register in bytes, `None` means variable size.
38    pub fn size(&self) -> Option<usize> {
39        Some(match *self {
40            Self::ACCESS => 1,
41            Self::INT_ENABLE => 4,
42            Self::INT_VECTOR => 4,
43            Self::INT_STATUS => 4,
44            Self::INTF_CAPABILITY => 4,
45            Self::STS => 4,
46            Self::DATA_FIFO => return None,
47            Self::INTERFACE_ID => 4,
48            Self::XDATA_FIFO => return None,
49            Self::DID_VID => 4,
50            Self::RID => 4,
51        })
52    }
53}
54
55/// Errors relating to TPM communication.
56#[derive(Error, Debug)]
57pub enum TpmError {
58    #[error("TPM timeout")]
59    Timeout,
60    #[error("Unexpected response size {0}")]
61    UnexpectedResponseSize(usize),
62    #[error("Response incomplete. Missing {0} bytes.")]
63    ResponseIncomplete(usize),
64    #[error("Failed to get status")]
65    ReadStatusFail,
66    #[error("Timeout polling for response")]
67    ResponseTimeout,
68}
69
70/// Low level interface for accessing TPM.  Separate implementations exist for SPI and I2C.
71pub trait Driver {
72    /// Initialize the TPM by claiming the access register.
73    fn init(&self) -> Result<()> {
74        self.write_register(
75            Register::ACCESS,
76            &TpmAccess::ACTIVE_LOCALITY.bits().to_be_bytes(),
77        )?;
78        self.write_register(
79            Register::ACCESS,
80            &TpmAccess::REQUEST_USE.bits().to_be_bytes(),
81        )?;
82        Ok(())
83    }
84
85    /// Read from the given TPM register, number of bytes to read given by length of data slice.
86    fn read_register(&self, register: Register, data: &mut [u8]) -> Result<()>;
87
88    /// Write to the given TPM register.
89    fn write_register(&self, register: Register, data: &[u8]) -> Result<()>;
90
91    /// Execute a TPM command and return the result as a `Vec<u8>` or time out.
92    fn execute_command(&self, cmd: &[u8]) -> Result<Vec<u8>> {
93        self.write_register(Register::STS, &TpmStatus::CMD_READY.to_le_bytes())?;
94
95        log::debug!("RUN({}) {:02X?}", cmd.len(), cmd);
96        let burst_count = self.poll_for_ready()?.burst_count();
97        for slice in cmd.chunks(burst_count) {
98            self.write_register(Register::DATA_FIFO, slice)?;
99        }
100        self.write_register(Register::STS, &TpmStatus::TPM_GO.to_le_bytes())?;
101
102        let burst_count = self.poll_for_data_available()?.burst_count();
103        let mut result: Vec<u8> = vec![0; burst_count];
104        self.read_register(Register::DATA_FIFO, result.as_mut_slice())?;
105        let resp_size: usize = u32::from_be_bytes(result[2..6].try_into().unwrap()) as usize;
106        ensure!(
107            resp_size < MAX_RESPONSE_SIZE,
108            TpmError::UnexpectedResponseSize(resp_size)
109        );
110        let mut remaining = resp_size - result.len();
111
112        let mut sts = self.read_status()?;
113        while sts.is_valid() && sts.data_available() && remaining > 0 {
114            let to_read: usize = remaining.min(burst_count);
115            let mut result2: Vec<u8> = vec![0; to_read];
116            self.read_register(Register::DATA_FIFO, result2.as_mut_slice())?;
117            result.append(&mut result2);
118            remaining -= to_read;
119            sts = self.read_status()?;
120        }
121        ensure!(remaining == 0, TpmError::ResponseIncomplete(remaining));
122        log::debug!("RES({}) {:02X?}", result.len(), result.as_slice());
123
124        // Return to idle state.
125        self.write_register(Register::STS, &TpmStatus::CMD_READY.to_le_bytes())?;
126
127        Ok(result)
128    }
129
130    /// Fetches the current status.
131    fn read_status(&self) -> Result<TpmStatus> {
132        let mut out = [0u8; 4];
133        let res = self.read_register(Register::STS, &mut out);
134        if res.is_ok() {
135            Ok(TpmStatus::from_bytes(out))
136        } else {
137            log::error!("Failed to read status");
138            Err(TpmError::ReadStatusFail.into())
139        }
140    }
141
142    /// Poll the status register until the status is valid and data is available or time out.
143    fn poll_for_data_available(&self) -> Result<TpmStatus> {
144        // Some TPM operations, such as generating RSA keys can take several minutes.
145        const STATUS_POLL_TIMEOUT: Duration = Duration::from_secs(5 * 60);
146        let deadline = Instant::now() + STATUS_POLL_TIMEOUT;
147        let mut sts = self.read_status()?;
148        // If the device is busy and doesn't actually respond, the status comes back as !0. This
149        // will look like a valid status with a full FIFO, so ignore this case.
150        while !sts.is_valid()
151            || !sts.data_available()
152            || sts.raw_value() == !0
153            // Sometimes the status returns shifted. Detect that here.
154            || (sts.raw_value() & 0xFF) == 0xFF
155        {
156            if Instant::now() > deadline {
157                log::error!("Status poll timeout.");
158                return Err(TpmError::ResponseTimeout.into());
159            }
160            sts = self.read_status()?;
161            thread::sleep(Duration::from_millis(10));
162        }
163        Ok(sts)
164    }
165
166    /// Poll the status register until the status is valid and the tpm is ready or time out.
167    fn poll_for_ready(&self) -> Result<TpmStatus> {
168        const STATUS_POLL_TIMEOUT: Duration = Duration::from_millis(30000);
169        let deadline = Instant::now() + STATUS_POLL_TIMEOUT;
170        let mut sts = self.read_status()?;
171        // If the device is busy and doesn't actually respond, the status comes back as !0. This
172        // will look like a valid status with a full FIFO, so ignore this case.
173        while !sts.is_valid()
174            || !sts.is_ready()
175            || sts.raw_value() == !0
176            // Sometimes the status returns shifted. Detect that here.
177            || (sts.raw_value() & 0xFF) == 0xFF
178        {
179            ensure!(Instant::now() <= deadline, TpmError::Timeout);
180            sts = self.read_status()?;
181            thread::sleep(Duration::from_millis(10));
182        }
183        Ok(sts)
184    }
185}
186
187/// Implementation of the low level interface via standard SPI protocol.
188pub struct SpiDriver {
189    spi: Rc<dyn spi::Target>,
190    use_gsc_ready: bool,
191}
192
193impl SpiDriver {
194    pub fn new(spi: Rc<dyn spi::Target>, use_gsc_ready: bool) -> Result<Self> {
195        Ok(Self { spi, use_gsc_ready })
196    }
197
198    /// Numerical TPM register address as used in SPI protocol.
199    pub fn addr(register: Register) -> u16 {
200        match register {
201            Register::ACCESS => 0x0000,
202            Register::INT_ENABLE => 0x0008,
203            Register::INT_VECTOR => 0x000C,
204            Register::INT_STATUS => 0x0010,
205            Register::INTF_CAPABILITY => 0x0014,
206            Register::STS => 0x0018,
207            Register::DATA_FIFO => 0x0024,
208            Register::INTERFACE_ID => 0x0030,
209            Register::XDATA_FIFO => 0x0080,
210            Register::DID_VID => 0x0F00,
211            Register::RID => 0x0F04,
212        }
213    }
214
215    fn compose_header(&self, register: Register, len: usize, is_read: bool) -> [u8; 4] {
216        let mut req: u32 = ((len as u32 - 1) << SPI_TPM_DATA_LEN_POS)
217            | SPI_TPM_ADDRESS_OFFSET
218            | (Self::addr(register) as u32);
219        if is_read {
220            req |= SPI_TPM_READ;
221        } else {
222            req |= SPI_TPM_WRITE;
223        }
224        req.to_be_bytes()
225    }
226
227    /// Write a transaction header for the given register and length.
228    fn write_header(&self, register: Register, len: usize, is_read: bool) -> Result<()> {
229        let mut buffer = [0u8; 4];
230        let req = self.compose_header(register, len, is_read);
231        self.spi
232            .run_transaction(&mut [spi::Transfer::Both(&req, &mut buffer)])?;
233        // The TPM has a chance to indicate that it is ready to produce the response in the very
234        // next byte.  As the fourth and final byte of the header is being sent, if the TPM sends
235        // back 0x01 on the other data line, data will come next.
236        if buffer[3] & 1 == 0 {
237            // The TPM was not immediately ready, keep polling, until we receive a byte of 0x01.
238            let start_time = Instant::now();
239            while {
240                self.spi
241                    .run_transaction(&mut [spi::Transfer::Read(&mut buffer[0..1])])?;
242                buffer[0] & 1 == 0
243            } {
244                if Instant::now().duration_since(start_time) > TIMEOUT {
245                    bail!(TpmError::Timeout)
246                }
247            }
248        }
249        Ok(())
250    }
251
252    fn do_read_register(&self, register: Register, data: &mut [u8]) -> Result<()> {
253        let _cs_asserted = Rc::clone(&self.spi).assert_cs()?; // Deasserts when going out of scope.
254        self.write_header(register, data.len(), true)?;
255        self.spi.run_transaction(&mut [spi::Transfer::Read(data)])?;
256        Ok(())
257    }
258
259    fn do_write_register(&self, register: Register, data: &[u8]) -> Result<()> {
260        let _cs_asserted = Rc::clone(&self.spi).assert_cs()?; // Deasserts when going out of scope.
261        self.write_header(register, data.len(), false)?;
262        self.spi
263            .run_transaction(&mut [spi::Transfer::Write(data)])?;
264        Ok(())
265    }
266}
267
268const SPI_TPM_READ: u32 = 0xC0000000;
269const SPI_TPM_WRITE: u32 = 0x40000000;
270const SPI_TPM_DATA_LEN_POS: u8 = 24;
271const SPI_TPM_ADDRESS_OFFSET: u32 = 0x00D40000;
272
273const MAX_RESPONSE_SIZE: usize = 4096;
274const TIMEOUT: Duration = Duration::from_millis(500);
275
276impl Driver for SpiDriver {
277    fn read_register(&self, register: Register, data: &mut [u8]) -> Result<()> {
278        if !self.spi.supports_tpm_poll()? {
279            // Fallback on polling TPM status from this Rust code.
280            return self.do_read_register(register, data);
281        }
282        let req = self.compose_header(register, data.len(), true /* is_read */);
283        if self.use_gsc_ready {
284            self.spi.run_transaction(&mut [
285                spi::Transfer::Write(&req),
286                spi::Transfer::TpmPoll,
287                spi::Transfer::Read(data),
288                spi::Transfer::GscReady,
289            ])
290        } else {
291            self.spi.run_transaction(&mut [
292                spi::Transfer::Write(&req),
293                spi::Transfer::TpmPoll,
294                spi::Transfer::Read(data),
295            ])
296        }
297    }
298
299    fn write_register(&self, register: Register, data: &[u8]) -> Result<()> {
300        if !self.spi.supports_tpm_poll()? {
301            // Fallback on polling TPM status from this Rust code.
302            return self.do_write_register(register, data);
303        }
304        let req = self.compose_header(register, data.len(), false /* is_read */);
305        if self.use_gsc_ready {
306            self.spi.run_transaction(&mut [
307                spi::Transfer::Write(&req),
308                spi::Transfer::TpmPoll,
309                spi::Transfer::Write(data),
310                spi::Transfer::GscReady,
311            ])
312        } else {
313            self.spi.run_transaction(&mut [
314                spi::Transfer::Write(&req),
315                spi::Transfer::TpmPoll,
316                spi::Transfer::Write(data),
317            ])
318        }
319    }
320}
321
322/// Implementation of the low level interface via Google I2C protocol.
323pub struct I2cDriver {
324    i2c: Rc<dyn i2c::Bus>,
325    use_gsc_ready: bool,
326}
327
328impl I2cDriver {
329    pub fn new(i2c: Rc<dyn i2c::Bus>, use_gsc_ready: bool) -> Result<Self> {
330        Ok(Self { i2c, use_gsc_ready })
331    }
332
333    /// Numerical TPM register address as used in Google I2C protocol.
334    pub fn addr(reg: Register) -> Option<u8> {
335        match reg {
336            Register::ACCESS => Some(0x00),
337            Register::STS => Some(0x01),
338            Register::DATA_FIFO => Some(0x05),
339            Register::DID_VID => Some(0x06),
340            _ => None,
341        }
342    }
343
344    fn try_read_register(&self, register: Register, data: &mut [u8]) -> Result<()> {
345        if !self.use_gsc_ready {
346            // Do two I2C transfers in one call, for lowest latency.
347            self.i2c.run_transaction(
348                None, /* default addr */
349                &mut [
350                    i2c::Transfer::Write(&[Self::addr(register).unwrap()]),
351                    i2c::Transfer::Read(data),
352                ],
353            )
354        } else {
355            self.i2c.run_transaction(
356                None, /* default addr */
357                &mut [
358                    i2c::Transfer::Write(&[Self::addr(register).unwrap()]),
359                    i2c::Transfer::GscReady,
360                    i2c::Transfer::Read(data),
361                ],
362            )
363        }
364    }
365}
366
367impl Driver for I2cDriver {
368    fn read_register(&self, register: Register, data: &mut [u8]) -> Result<()> {
369        const MAX_TRIES: usize = 10;
370        let mut count = 0;
371        // Retry in case the I2C bus wasn't ready.
372        let res = loop {
373            count += 1;
374            match self.try_read_register(register, data) {
375                Err(e) => {
376                    log::trace!(
377                        "Register 0x{:X} access error: {}",
378                        Self::addr(register).unwrap(),
379                        e
380                    );
381                    if count == MAX_TRIES {
382                        break Err(e);
383                    }
384                }
385                Ok(()) => {
386                    if count > 1 {
387                        log::trace!("Success after {} tries.", count);
388                    }
389                    break Ok(());
390                }
391            }
392            thread::sleep(Duration::from_millis(100));
393        };
394        if res.is_err() {
395            log::error!("Failed to read TPM register.");
396        }
397        res
398    }
399
400    fn write_register(&self, register: Register, data: &[u8]) -> Result<()> {
401        let mut buffer = vec![Self::addr(register).unwrap()];
402        buffer.extend_from_slice(data);
403        if !self.use_gsc_ready {
404            self.i2c.run_transaction(
405                None, /* default addr */
406                &mut [i2c::Transfer::Write(&buffer)],
407            )
408        } else {
409            self.i2c.run_transaction(
410                None, /* default addr */
411                &mut [i2c::Transfer::Write(&buffer), i2c::Transfer::GscReady],
412            )
413        }
414    }
415}