xref: /cloud-hypervisor/devices/src/tpm.rs (revision 6f8bd27cf7629733582d930519e98d19e90afb16)
1 // Copyright © 2022, Microsoft Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 
6 use anyhow::anyhow;
7 #[cfg(target_arch = "aarch64")]
8 use arch::aarch64::layout::{TPM_SIZE, TPM_START};
9 #[cfg(target_arch = "x86_64")]
10 use arch::x86_64::layout::{TPM_SIZE, TPM_START};
11 use phf::phf_map;
12 use std::cmp;
13 use std::sync::{Arc, Barrier};
14 use thiserror::Error;
15 use tpm::emulator::{BackendCmd, Emulator};
16 use tpm::TPM_CRB_BUFFER_MAX;
17 use tpm::TPM_SUCCESS;
18 use vm_device::BusDevice;
19 
20 #[derive(Error, Debug)]
21 pub enum Error {
22     #[error("Emulator doesn't implement min required capabilities: {0}")]
23     CheckCaps(#[source] anyhow::Error),
24     #[error("Failed to initialize tpm: {0}")]
25     Init(#[source] anyhow::Error),
26     #[error("Failed to deliver tpm Command: {0}")]
27     DeliverRequest(#[source] anyhow::Error),
28 }
29 type Result<T> = anyhow::Result<T, Error>;
30 
31 /* crb 32-bit registers */
32 const CRB_LOC_STATE: u32 = 0x0;
33 //Register Fields
34 // Field => (start, length)
35 // start: lowest bit in the bit field numbered from 0
36 // length: length of the bit field
37 const CRB_LOC_STATE_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
38     "tpmEstablished" => [0, 1],
39     "locAssigned" => [1,1],
40     "activeLocality"=> [2, 3],
41     "reserved" => [5, 2],
42     "tpmRegValidSts" => [7, 1]
43 };
44 const CRB_LOC_CTRL: u32 = 0x08;
45 const CRB_LOC_CTRL_REQUEST_ACCESS: u32 = 1 << 0;
46 const CRB_LOC_CTRL_RELINQUISH: u32 = 1 << 1;
47 const CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: u32 = 1 << 3;
48 const CRB_LOC_STS: u32 = 0x0C;
49 const CRB_LOC_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
50     "Granted" => [0, 1],
51     "beenSeized" => [1,1]
52 };
53 const CRB_INTF_ID: u32 = 0x30;
54 const CRB_INTF_ID_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
55     "InterfaceType" => [0, 4],
56     "InterfaceVersion" => [4, 4],
57     "CapLocality" =>  [8, 1],
58     "CapCRBIdleBypass" => [9, 1],
59     "Reserved1" => [10, 1],
60     "CapDataXferSizeSupport" => [11, 2],
61     "CapFIFO" =>  [13, 1],
62     "CapCRB" => [14, 1],
63     "CapIFRes" => [15, 2],
64     "InterfaceSelector" => [17, 2],
65     "IntfSelLock" =>  [19, 1],
66     "Reserved2" => [20, 4],
67     "RID" => [24, 8]
68 };
69 const CRB_INTF_ID2: u32 = 0x34;
70 const CRB_INTF_ID2_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
71     "VID" => [0, 16],
72     "DID" => [16, 16]
73 };
74 const CRB_CTRL_REQ: u32 = 0x40;
75 const CRB_CTRL_REQ_CMD_READY: u32 = 1 << 0;
76 const CRB_CTRL_REQ_GO_IDLE: u32 = 1 << 1;
77 const CRB_CTRL_STS: u32 = 0x44;
78 const CRB_CTRL_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
79     "tpmSts" => [0, 1],
80     "tpmIdle" => [1, 1]
81 };
82 const CRB_CTRL_CANCEL: u32 = 0x48;
83 const CRB_CANCEL_INVOKE: u32 = 1 << 0;
84 const CRB_CTRL_START: u32 = 0x4C;
85 const CRB_START_INVOKE: u32 = 1 << 0;
86 const CRB_CTRL_CMD_LADDR: u32 = 0x5C;
87 const CRB_CTRL_CMD_HADDR: u32 = 0x60;
88 const CRB_CTRL_RSP_SIZE: u32 = 0x64;
89 const CRB_CTRL_RSP_ADDR: u32 = 0x68;
90 const CRB_DATA_BUFFER: u32 = 0x80;
91 
92 const TPM_CRB_NO_LOCALITY: u32 = 0xff;
93 
94 const TPM_CRB_ADDR_BASE: u32 = TPM_START.0 as u32;
95 const TPM_CRB_ADDR_SIZE: usize = TPM_SIZE as usize;
96 
97 const TPM_CRB_R_MAX: u32 = CRB_DATA_BUFFER;
98 
99 // CRB Protocol details
100 const CRB_INTF_TYPE_CRB_ACTIVE: u32 = 0b1;
101 const CRB_INTF_VERSION_CRB: u32 = 0b1;
102 const CRB_INTF_CAP_LOCALITY_0_ONLY: u32 = 0b0;
103 const CRB_INTF_CAP_IDLE_FAST: u32 = 0b0;
104 const CRB_INTF_CAP_XFER_SIZE_64: u32 = 0b11;
105 const CRB_INTF_CAP_FIFO_NOT_SUPPORTED: u32 = 0b0;
106 const CRB_INTF_CAP_CRB_SUPPORTED: u32 = 0b1;
107 const CRB_INTF_IF_SELECTOR_CRB: u32 = 0b1;
108 const PCI_VENDOR_ID_IBM: u32 = 0x1014;
109 const CRB_CTRL_CMD_SIZE_REG: u32 = 0x58;
110 const CRB_CTRL_CMD_SIZE: usize = TPM_CRB_ADDR_SIZE - CRB_DATA_BUFFER as usize;
111 
112 fn get_fields_map(reg: u32) -> phf::Map<&'static str, [u32; 2]> {
113     match reg {
114         CRB_LOC_STATE => CRB_LOC_STATE_FIELDS,
115         CRB_LOC_STS => CRB_LOC_STS_FIELDS,
116         CRB_INTF_ID => CRB_INTF_ID_FIELDS,
117         CRB_INTF_ID2 => CRB_INTF_ID2_FIELDS,
118         CRB_CTRL_STS => CRB_CTRL_STS_FIELDS,
119         _ => {
120             panic!(
121                 "Fields in '{:?}' register were accessed which are Invalid",
122                 reg
123             );
124         }
125     }
126 }
127 
128 /// Set a particular field in a Register
129 fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str, value: u32) {
130     let reg_fields = get_fields_map(reg);
131     if reg_fields.contains_key(field) {
132         let start = reg_fields.get(field).unwrap()[0];
133         let len = reg_fields.get(field).unwrap()[1];
134         let mask = (!(0_u32) >> (32 - len)) << start;
135         regs[reg as usize] = (regs[reg as usize] & !mask) | ((value << start) & mask);
136     } else {
137         error!(
138             "Failed to tpm Register. {:?} is not a valid field in Reg {:#X}",
139             field, reg
140         )
141     }
142 }
143 
144 /// Get the value of a particular field in a Register
145 fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str) -> u32 {
146     let reg_fields = get_fields_map(reg);
147     if reg_fields.contains_key(field) {
148         let start = reg_fields.get(field).unwrap()[0];
149         let len = reg_fields.get(field).unwrap()[1];
150         let mask = (!(0_u32) >> (32 - len)) << start;
151         (regs[reg as usize] & mask) >> start
152     } else {
153         // TODO: Sensible return value if fields do not exist
154         0x0
155     }
156 }
157 
158 fn locality_from_addr(addr: u32) -> u8 {
159     (addr >> 12) as u8
160 }
161 
162 pub struct Tpm {
163     emulator: Emulator,
164     cmd: Option<BackendCmd>,
165     regs: [u32; TPM_CRB_R_MAX as usize],
166     backend_buff_size: usize,
167     data_buff: [u8; TPM_CRB_BUFFER_MAX],
168     data_buff_len: usize,
169 }
170 
171 impl Tpm {
172     pub fn new(path: String) -> Result<Self> {
173         let emulator = Emulator::new(path)
174             .map_err(|e| Error::Init(anyhow!("Failed while initializing tpm Emulator: {:?}", e)))?;
175         let mut tpm = Tpm {
176             emulator,
177             cmd: None,
178             regs: [0; TPM_CRB_R_MAX as usize],
179             backend_buff_size: TPM_CRB_BUFFER_MAX,
180             data_buff: [0; TPM_CRB_BUFFER_MAX],
181             data_buff_len: 0,
182         };
183         tpm.reset()?;
184         Ok(tpm)
185     }
186 
187     fn get_active_locality(&mut self) -> u32 {
188         if get_reg_field(&self.regs, CRB_LOC_STATE, "locAssigned") == 0 {
189             return TPM_CRB_NO_LOCALITY;
190         }
191         get_reg_field(&self.regs, CRB_LOC_STATE, "activeLocality")
192     }
193 
194     fn request_completed(&mut self, result: isize) {
195         self.regs[CRB_CTRL_START as usize] = !CRB_START_INVOKE;
196         if result != 0 {
197             set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmSts", 1);
198         }
199     }
200 
201     fn reset(&mut self) -> Result<()> {
202         let cur_buff_size = self.emulator.get_buffer_size().unwrap();
203         self.regs = [0; TPM_CRB_R_MAX as usize];
204         set_reg_field(&mut self.regs, CRB_LOC_STATE, "tpmRegValidSts", 1);
205         set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1);
206         set_reg_field(
207             &mut self.regs,
208             CRB_INTF_ID,
209             "InterfaceType",
210             CRB_INTF_TYPE_CRB_ACTIVE,
211         );
212         set_reg_field(
213             &mut self.regs,
214             CRB_INTF_ID,
215             "InterfaceVersion",
216             CRB_INTF_VERSION_CRB,
217         );
218         set_reg_field(
219             &mut self.regs,
220             CRB_INTF_ID,
221             "CapLocality",
222             CRB_INTF_CAP_LOCALITY_0_ONLY,
223         );
224         set_reg_field(
225             &mut self.regs,
226             CRB_INTF_ID,
227             "CapCRBIdleBypass",
228             CRB_INTF_CAP_IDLE_FAST,
229         );
230         set_reg_field(
231             &mut self.regs,
232             CRB_INTF_ID,
233             "CapDataXferSizeSupport",
234             CRB_INTF_CAP_XFER_SIZE_64,
235         );
236         set_reg_field(
237             &mut self.regs,
238             CRB_INTF_ID,
239             "CapFIFO",
240             CRB_INTF_CAP_FIFO_NOT_SUPPORTED,
241         );
242         set_reg_field(
243             &mut self.regs,
244             CRB_INTF_ID,
245             "CapCRB",
246             CRB_INTF_CAP_CRB_SUPPORTED,
247         );
248         set_reg_field(
249             &mut self.regs,
250             CRB_INTF_ID,
251             "InterfaceSelector",
252             CRB_INTF_IF_SELECTOR_CRB,
253         );
254         set_reg_field(&mut self.regs, CRB_INTF_ID, "RID", 0b0000);
255         set_reg_field(&mut self.regs, CRB_INTF_ID2, "VID", PCI_VENDOR_ID_IBM);
256 
257         self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = CRB_CTRL_CMD_SIZE as u32;
258         self.regs[CRB_CTRL_CMD_LADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
259         self.regs[CRB_CTRL_RSP_SIZE as usize] = CRB_CTRL_CMD_SIZE as u32;
260         self.regs[CRB_CTRL_RSP_ADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
261 
262         self.backend_buff_size = cmp::min(cur_buff_size, TPM_CRB_BUFFER_MAX);
263 
264         if let Err(e) = self.emulator.startup_tpm(self.backend_buff_size) {
265             return Err(Error::Init(anyhow!(
266                 "Failed while running Startup TPM. Error: {:?}",
267                 e
268             )));
269         }
270         Ok(())
271     }
272 }
273 
274 //impl BusDevice for TPM
275 impl BusDevice for Tpm {
276     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
277         let mut offset: u32 = offset as u32;
278         let read_len: usize = data.len();
279 
280         if offset >= CRB_DATA_BUFFER
281             && (offset + read_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32)
282         {
283             // Read from Data Buffer
284             let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize);
285             let end: usize = start + read_len;
286             data[..].clone_from_slice(&self.data_buff[start..end]);
287         } else {
288             offset &= 0xff;
289             let mut val = self.regs[offset as usize];
290 
291             if offset == CRB_LOC_STATE && !self.emulator.get_established_flag() {
292                 val |= 0x1;
293             }
294 
295             if data.len() <= 4 {
296                 data.clone_from_slice(val.to_ne_bytes()[0..read_len].as_ref());
297             } else {
298                 error!(
299                     "Invalid tpm read: offset {:#X}, data length {:?}",
300                     offset,
301                     data.len()
302                 );
303             }
304         }
305         debug!(
306             "MMIO Read: offset {:#X} len {:?} val = {:02X?}  ",
307             offset,
308             data.len(),
309             data
310         );
311     }
312 
313     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
314         debug!(
315             "MMIO Write: offset {:#X} len {:?} input data {:02X?}",
316             offset,
317             data.len(),
318             data
319         );
320         let mut offset: u32 = offset as u32;
321         if offset < CRB_DATA_BUFFER {
322             offset &= 0xff;
323         }
324         let locality = locality_from_addr(offset) as u32;
325         let write_len = data.len();
326 
327         if offset >= CRB_DATA_BUFFER
328             && (offset + write_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32)
329         {
330             let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize);
331             if start == 0 {
332                 // If filling data_buff at index 0, reset length to 0
333                 self.data_buff_len = 0;
334                 self.data_buff.fill(0);
335             }
336             let end: usize = start + data.len();
337             self.data_buff[start..end].clone_from_slice(data);
338             self.data_buff_len += data.len();
339         } else {
340             // Ctrl Commands that take more than 4 bytes as input are not yet supported
341             // CTRL_RSP_ADDR usually gets 8 byte write request. Last 4 bytes are zeros.
342             if write_len > 4 && offset != CRB_CTRL_RSP_ADDR {
343                 error!(
344                     "Invalid tpm write: offset {:#X}, data length {}",
345                     offset,
346                     data.len()
347                 );
348                 return None;
349             }
350 
351             let mut input: [u8; 4] = [0; 4];
352             input.copy_from_slice(&data[0..4]);
353             let v = u32::from_le_bytes(input);
354 
355             match offset {
356                 CRB_CTRL_CMD_SIZE_REG => {
357                     self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = v;
358                 }
359                 CRB_CTRL_CMD_LADDR => {
360                     self.regs[CRB_CTRL_CMD_LADDR as usize] = v;
361                 }
362                 CRB_CTRL_CMD_HADDR => {
363                     self.regs[CRB_CTRL_CMD_HADDR as usize] = v;
364                 }
365                 CRB_CTRL_RSP_SIZE => {
366                     self.regs[CRB_CTRL_RSP_SIZE as usize] = v;
367                 }
368                 CRB_CTRL_RSP_ADDR => {
369                     self.regs[CRB_CTRL_RSP_ADDR as usize] = v;
370                 }
371                 CRB_CTRL_REQ => match v {
372                     CRB_CTRL_REQ_CMD_READY => {
373                         set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 0);
374                     }
375                     CRB_CTRL_REQ_GO_IDLE => {
376                         set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1);
377                     }
378                     _ => {
379                         error!("Invalid value passed to CRTL_REQ register");
380                         return None;
381                     }
382                 },
383                 CRB_CTRL_CANCEL => {
384                     if v == CRB_CANCEL_INVOKE
385                         && (self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE != 0)
386                     {
387                         if let Err(e) = self.emulator.cancel_cmd() {
388                             error!("Failed to run cancel command. Error: {:?}", e);
389                         }
390                     }
391                 }
392                 CRB_CTRL_START => {
393                     if v == CRB_START_INVOKE
394                         && ((self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE) == 0)
395                         && self.get_active_locality() == locality
396                     {
397                         self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE;
398 
399                         self.cmd = Some(BackendCmd {
400                             locality: locality as u8,
401                             input: self.data_buff[0..self.data_buff_len].to_vec(),
402                             input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX),
403                             output: self.data_buff.to_vec(),
404                             output_len: TPM_CRB_BUFFER_MAX,
405                             selftest_done: false,
406                         });
407 
408                         let mut cmd = self.cmd.as_ref().unwrap().clone();
409                         let output = self.emulator.deliver_request(&mut cmd).map_err(|e| {
410                             Error::DeliverRequest(anyhow!(
411                                 "Failed to deliver tpm request. Error :{:?}",
412                                 e
413                             ))
414                         });
415                         //TODO: drop the copy here
416                         self.data_buff.fill(0);
417                         self.data_buff.clone_from_slice(output.unwrap().as_slice());
418 
419                         self.request_completed(TPM_SUCCESS as isize);
420                     }
421                 }
422                 CRB_LOC_CTRL => {
423                     warn!(
424                         "CRB_LOC_CTRL locality to write = {:?} val = {:?}",
425                         locality, v
426                     );
427                     match v {
428                         CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT => {}
429                         CRB_LOC_CTRL_RELINQUISH => {
430                             set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 0);
431                             set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 0);
432                         }
433                         CRB_LOC_CTRL_REQUEST_ACCESS => {
434                             set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 1);
435                             set_reg_field(&mut self.regs, CRB_LOC_STS, "beenSeized", 0);
436                             set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 1);
437                         }
438                         _ => {
439                             error!("Invalid value to write in CRB_LOC_CTRL {:#X} ", v);
440                         }
441                     }
442                 }
443                 _ => {
444                     error!(
445                         "Invalid tpm write: offset {:#X}, data length {:?}",
446                         offset,
447                         data.len()
448                     );
449                 }
450             }
451         }
452         None
453     }
454 }
455 
456 #[cfg(test)]
457 mod tests {
458     use super::*;
459 
460     #[test]
461     fn test_set_get_reg_field() {
462         let mut regs: [u32; TPM_CRB_R_MAX as usize] = [0; TPM_CRB_R_MAX as usize];
463         set_reg_field(&mut regs, CRB_INTF_ID, "RID", 0xAC);
464         assert_eq!(
465             get_reg_field(&regs, CRB_INTF_ID, "RID"),
466             0xAC,
467             concat!("Test: ", stringify!(set_get_reg_field))
468         );
469     }
470 }
471