xref: /cloud-hypervisor/devices/src/tpm.rs (revision 8803e4a2e7f8e9596b72f81d3c916390e5b10fbd)
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 std::cmp;
12 use std::sync::{Arc, Barrier};
13 use thiserror::Error;
14 use tpm::emulator::{BackendCmd, Emulator};
15 use tpm::TPM_CRB_BUFFER_MAX;
16 use vm_device::BusDevice;
17 
18 #[derive(Error, Debug)]
19 pub enum Error {
20     #[error("Emulator doesn't implement min required capabilities: {0}")]
21     CheckCaps(#[source] anyhow::Error),
22     #[error("Failed to initialize tpm: {0}")]
23     Init(#[source] anyhow::Error),
24 }
25 type Result<T> = anyhow::Result<T, Error>;
26 
27 #[allow(dead_code)]
28 enum LocStateFields {
29     TpmEstablished,
30     LocAssigned,
31     ActiveLocality,
32     Reserved,
33     TpmRegValidSts,
34 }
35 
36 enum LocStsFields {
37     Granted,
38     BeenSeized,
39 }
40 
41 #[allow(dead_code)]
42 enum IntfIdFields {
43     InterfaceType,
44     InterfaceVersion,
45     CapLocality,
46     CapCRBIdleBypass,
47     Reserved1,
48     CapDataXferSizeSupport,
49     CapFIFO,
50     CapCRB,
51     CapIFRes,
52     InterfaceSelector,
53     IntfSelLock,
54     Reserved2,
55     Rid,
56 }
57 
58 #[allow(dead_code)]
59 enum IntfId2Fields {
60     Vid,
61     Did,
62 }
63 
64 enum CtrlStsFields {
65     TpmSts,
66     TpmIdle,
67 }
68 
69 enum CrbRegister {
70     LocState(LocStateFields),
71     LocSts(LocStsFields),
72     IntfId(IntfIdFields),
73     IntfId2(IntfId2Fields),
74     CtrlSts(CtrlStsFields),
75 }
76 
77 /* crb 32-bit registers */
78 const CRB_LOC_STATE: u32 = 0x0;
79 //Register Fields
80 // Field => (base, offset, length)
81 // base:   starting position of the register
82 // offset: lowest bit in the bit field numbered from 0
83 // length: length of the bit field
84 const fn get_crb_loc_state_field(f: LocStateFields) -> (u32, u32, u32) {
85     let (offset, len) = match f {
86         LocStateFields::TpmEstablished => (0, 1),
87         LocStateFields::LocAssigned => (1, 1),
88         LocStateFields::ActiveLocality => (2, 3),
89         LocStateFields::Reserved => (5, 2),
90         LocStateFields::TpmRegValidSts => (7, 1),
91     };
92 
93     (CRB_LOC_STATE, offset, len)
94 }
95 
96 const CRB_LOC_CTRL: u32 = 0x08;
97 const CRB_LOC_CTRL_REQUEST_ACCESS: u32 = 1 << 0;
98 const CRB_LOC_CTRL_RELINQUISH: u32 = 1 << 1;
99 const CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: u32 = 1 << 3;
100 const CRB_LOC_STS: u32 = 0x0C;
101 const fn get_crb_loc_sts_field(f: LocStsFields) -> (u32, u32, u32) {
102     let (offset, len) = match f {
103         LocStsFields::Granted => (0, 1),
104         LocStsFields::BeenSeized => (1, 1),
105     };
106 
107     (CRB_LOC_STS, offset, len)
108 }
109 
110 const CRB_INTF_ID: u32 = 0x30;
111 const fn get_crb_intf_id_field(f: IntfIdFields) -> (u32, u32, u32) {
112     let (offset, len) = match f {
113         IntfIdFields::InterfaceType => (0, 4),
114         IntfIdFields::InterfaceVersion => (4, 4),
115         IntfIdFields::CapLocality => (8, 1),
116         IntfIdFields::CapCRBIdleBypass => (9, 1),
117         IntfIdFields::Reserved1 => (10, 1),
118         IntfIdFields::CapDataXferSizeSupport => (11, 2),
119         IntfIdFields::CapFIFO => (13, 1),
120         IntfIdFields::CapCRB => (14, 1),
121         IntfIdFields::CapIFRes => (15, 2),
122         IntfIdFields::InterfaceSelector => (17, 2),
123         IntfIdFields::IntfSelLock => (19, 1),
124         IntfIdFields::Reserved2 => (20, 4),
125         IntfIdFields::Rid => (24, 8),
126     };
127 
128     (CRB_INTF_ID, offset, len)
129 }
130 
131 const CRB_INTF_ID2: u32 = 0x34;
132 const fn get_crb_intf_id2_field(f: IntfId2Fields) -> (u32, u32, u32) {
133     let (offset, len) = match f {
134         IntfId2Fields::Vid => (0, 16),
135         IntfId2Fields::Did => (16, 16),
136     };
137 
138     (CRB_INTF_ID2, offset, len)
139 }
140 
141 const CRB_CTRL_REQ: u32 = 0x40;
142 const CRB_CTRL_REQ_CMD_READY: u32 = 1 << 0;
143 const CRB_CTRL_REQ_GO_IDLE: u32 = 1 << 1;
144 const CRB_CTRL_STS: u32 = 0x44;
145 const fn get_crb_ctrl_sts_field(f: CtrlStsFields) -> (u32, u32, u32) {
146     let (offset, len) = match f {
147         CtrlStsFields::TpmSts => (0, 1),
148         CtrlStsFields::TpmIdle => (1, 1),
149     };
150 
151     (CRB_CTRL_STS, offset, len)
152 }
153 const CRB_CTRL_CANCEL: u32 = 0x48;
154 const CRB_CANCEL_INVOKE: u32 = 1 << 0;
155 const CRB_CTRL_START: u32 = 0x4C;
156 const CRB_START_INVOKE: u32 = 1 << 0;
157 const CRB_CTRL_CMD_LADDR: u32 = 0x5C;
158 const CRB_CTRL_CMD_HADDR: u32 = 0x60;
159 const CRB_CTRL_RSP_SIZE: u32 = 0x64;
160 const CRB_CTRL_RSP_ADDR: u32 = 0x68;
161 const CRB_DATA_BUFFER: u32 = 0x80;
162 
163 const TPM_CRB_NO_LOCALITY: u32 = 0xff;
164 
165 const TPM_CRB_ADDR_BASE: u32 = TPM_START.0 as u32;
166 const TPM_CRB_ADDR_SIZE: usize = TPM_SIZE as usize;
167 
168 const TPM_CRB_R_MAX: usize = CRB_DATA_BUFFER as usize;
169 
170 // CRB Protocol details
171 const CRB_INTF_TYPE_CRB_ACTIVE: u32 = 0b1;
172 const CRB_INTF_VERSION_CRB: u32 = 0b1;
173 const CRB_INTF_CAP_LOCALITY_0_ONLY: u32 = 0b0;
174 const CRB_INTF_CAP_IDLE_FAST: u32 = 0b0;
175 const CRB_INTF_CAP_XFER_SIZE_64: u32 = 0b11;
176 const CRB_INTF_CAP_FIFO_NOT_SUPPORTED: u32 = 0b0;
177 const CRB_INTF_CAP_CRB_SUPPORTED: u32 = 0b1;
178 const CRB_INTF_IF_SELECTOR_CRB: u32 = 0b1;
179 const PCI_VENDOR_ID_IBM: u32 = 0x1014;
180 const CRB_CTRL_CMD_SIZE_REG: u32 = 0x58;
181 const CRB_CTRL_CMD_SIZE: usize = TPM_CRB_ADDR_SIZE - CRB_DATA_BUFFER as usize;
182 
183 // Returns (register base, offset, len)
184 const fn get_field(reg: CrbRegister) -> (u32, u32, u32) {
185     match reg {
186         CrbRegister::LocState(f) => get_crb_loc_state_field(f),
187         CrbRegister::LocSts(f) => get_crb_loc_sts_field(f),
188         CrbRegister::IntfId(f) => get_crb_intf_id_field(f),
189         CrbRegister::IntfId2(f) => get_crb_intf_id2_field(f),
190         CrbRegister::CtrlSts(f) => get_crb_ctrl_sts_field(f),
191     }
192 }
193 
194 // Set a particular field in a Register
195 fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX], reg: CrbRegister, value: u32) {
196     let (base, offset, len) = get_field(reg);
197     let mask = (!(0_u32) >> (32 - len)) << offset;
198     regs[base as usize] = (regs[base as usize] & !mask) | ((value << offset) & mask);
199 }
200 
201 // Get the value of a particular field in a Register
202 const fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX], reg: CrbRegister) -> u32 {
203     let (base, offset, len) = get_field(reg);
204     let mask = (!(0_u32) >> (32 - len)) << offset;
205     (regs[base as usize] & mask) >> offset
206 }
207 
208 fn locality_from_addr(addr: u32) -> u8 {
209     (addr >> 12) as u8
210 }
211 
212 pub struct Tpm {
213     emulator: Emulator,
214     regs: [u32; TPM_CRB_R_MAX],
215     backend_buff_size: usize,
216     data_buff: [u8; TPM_CRB_BUFFER_MAX],
217     data_buff_len: usize,
218 }
219 
220 impl Tpm {
221     pub fn new(path: String) -> Result<Self> {
222         let emulator = Emulator::new(path)
223             .map_err(|e| Error::Init(anyhow!("Failed while initializing tpm Emulator: {:?}", e)))?;
224         let mut tpm = Tpm {
225             emulator,
226             regs: [0; TPM_CRB_R_MAX],
227             backend_buff_size: TPM_CRB_BUFFER_MAX,
228             data_buff: [0; TPM_CRB_BUFFER_MAX],
229             data_buff_len: 0,
230         };
231         tpm.reset()?;
232         Ok(tpm)
233     }
234 
235     fn get_active_locality(&mut self) -> u32 {
236         if get_reg_field(
237             &self.regs,
238             CrbRegister::LocState(LocStateFields::LocAssigned),
239         ) == 0
240         {
241             return TPM_CRB_NO_LOCALITY;
242         }
243         get_reg_field(
244             &self.regs,
245             CrbRegister::LocState(LocStateFields::ActiveLocality),
246         )
247     }
248 
249     fn request_completed(&mut self, success: bool) {
250         self.regs[CRB_CTRL_START as usize] = !CRB_START_INVOKE;
251         if !success {
252             set_reg_field(
253                 &mut self.regs,
254                 CrbRegister::CtrlSts(CtrlStsFields::TpmSts),
255                 1,
256             );
257         }
258     }
259 
260     fn reset(&mut self) -> Result<()> {
261         let cur_buff_size = self.emulator.get_buffer_size();
262         self.regs = [0; TPM_CRB_R_MAX];
263         set_reg_field(
264             &mut self.regs,
265             CrbRegister::LocState(LocStateFields::TpmRegValidSts),
266             1,
267         );
268         set_reg_field(
269             &mut self.regs,
270             CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
271             1,
272         );
273         set_reg_field(
274             &mut self.regs,
275             CrbRegister::IntfId(IntfIdFields::InterfaceType),
276             CRB_INTF_TYPE_CRB_ACTIVE,
277         );
278         set_reg_field(
279             &mut self.regs,
280             CrbRegister::IntfId(IntfIdFields::InterfaceVersion),
281             CRB_INTF_VERSION_CRB,
282         );
283         set_reg_field(
284             &mut self.regs,
285             CrbRegister::IntfId(IntfIdFields::CapLocality),
286             CRB_INTF_CAP_LOCALITY_0_ONLY,
287         );
288         set_reg_field(
289             &mut self.regs,
290             CrbRegister::IntfId(IntfIdFields::CapCRBIdleBypass),
291             CRB_INTF_CAP_IDLE_FAST,
292         );
293         set_reg_field(
294             &mut self.regs,
295             CrbRegister::IntfId(IntfIdFields::CapDataXferSizeSupport),
296             CRB_INTF_CAP_XFER_SIZE_64,
297         );
298         set_reg_field(
299             &mut self.regs,
300             CrbRegister::IntfId(IntfIdFields::CapFIFO),
301             CRB_INTF_CAP_FIFO_NOT_SUPPORTED,
302         );
303         set_reg_field(
304             &mut self.regs,
305             CrbRegister::IntfId(IntfIdFields::CapCRB),
306             CRB_INTF_CAP_CRB_SUPPORTED,
307         );
308         set_reg_field(
309             &mut self.regs,
310             CrbRegister::IntfId(IntfIdFields::InterfaceSelector),
311             CRB_INTF_IF_SELECTOR_CRB,
312         );
313         set_reg_field(
314             &mut self.regs,
315             CrbRegister::IntfId(IntfIdFields::Rid),
316             0b0000,
317         );
318         set_reg_field(
319             &mut self.regs,
320             CrbRegister::IntfId2(IntfId2Fields::Vid),
321             PCI_VENDOR_ID_IBM,
322         );
323 
324         self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = CRB_CTRL_CMD_SIZE as u32;
325         self.regs[CRB_CTRL_CMD_LADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
326         self.regs[CRB_CTRL_RSP_SIZE as usize] = CRB_CTRL_CMD_SIZE as u32;
327         self.regs[CRB_CTRL_RSP_ADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
328 
329         self.backend_buff_size = cmp::min(cur_buff_size, TPM_CRB_BUFFER_MAX);
330 
331         if let Err(e) = self.emulator.startup_tpm(self.backend_buff_size) {
332             return Err(Error::Init(anyhow!(
333                 "Failed while running Startup TPM. Error: {:?}",
334                 e
335             )));
336         }
337         Ok(())
338     }
339 }
340 
341 impl BusDevice for Tpm {
342     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
343         let mut offset: u32 = offset as u32;
344         let read_len: usize = data.len();
345 
346         if offset >= CRB_DATA_BUFFER
347             && (offset + read_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32)
348         {
349             // Read from Data Buffer
350             let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize);
351             let end: usize = start + read_len;
352             data[..].clone_from_slice(&self.data_buff[start..end]);
353         } else {
354             offset &= 0xff;
355             let mut val = self.regs[offset as usize];
356 
357             if offset == CRB_LOC_STATE && !self.emulator.get_established_flag() {
358                 val |= 0x1;
359             }
360 
361             if data.len() <= 4 {
362                 data.clone_from_slice(val.to_ne_bytes()[0..read_len].as_ref());
363             } else {
364                 error!(
365                     "Invalid tpm read: offset {:#X}, data length {:?}",
366                     offset,
367                     data.len()
368                 );
369             }
370         }
371         debug!(
372             "MMIO Read: offset {:#X} len {:?} val = {:02X?}  ",
373             offset,
374             data.len(),
375             data
376         );
377     }
378 
379     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
380         debug!(
381             "MMIO Write: offset {:#X} len {:?} input data {:02X?}",
382             offset,
383             data.len(),
384             data
385         );
386         let mut offset: u32 = offset as u32;
387         if offset < CRB_DATA_BUFFER {
388             offset &= 0xff;
389         }
390         let locality = locality_from_addr(offset) as u32;
391         let write_len = data.len();
392 
393         if offset >= CRB_DATA_BUFFER
394             && (offset + write_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32)
395         {
396             let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize);
397             if start == 0 {
398                 // If filling data_buff at index 0, reset length to 0
399                 self.data_buff_len = 0;
400                 self.data_buff.fill(0);
401             }
402             let end: usize = start + data.len();
403             self.data_buff[start..end].clone_from_slice(data);
404             self.data_buff_len += data.len();
405         } else {
406             // Ctrl Commands that take more than 4 bytes as input are not yet supported
407             // CTRL_RSP_ADDR usually gets 8 byte write request. Last 4 bytes are zeros.
408             if write_len > 4 && offset != CRB_CTRL_RSP_ADDR {
409                 error!(
410                     "Invalid tpm write: offset {:#X}, data length {}",
411                     offset,
412                     data.len()
413                 );
414                 return None;
415             }
416 
417             let mut input: [u8; 4] = [0; 4];
418             input.copy_from_slice(&data[0..4]);
419             let v = u32::from_le_bytes(input);
420 
421             match offset {
422                 CRB_CTRL_CMD_SIZE_REG => {
423                     self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = v;
424                 }
425                 CRB_CTRL_CMD_LADDR => {
426                     self.regs[CRB_CTRL_CMD_LADDR as usize] = v;
427                 }
428                 CRB_CTRL_CMD_HADDR => {
429                     self.regs[CRB_CTRL_CMD_HADDR as usize] = v;
430                 }
431                 CRB_CTRL_RSP_SIZE => {
432                     self.regs[CRB_CTRL_RSP_SIZE as usize] = v;
433                 }
434                 CRB_CTRL_RSP_ADDR => {
435                     self.regs[CRB_CTRL_RSP_ADDR as usize] = v;
436                 }
437                 CRB_CTRL_REQ => match v {
438                     CRB_CTRL_REQ_CMD_READY => {
439                         set_reg_field(
440                             &mut self.regs,
441                             CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
442                             0,
443                         );
444                     }
445                     CRB_CTRL_REQ_GO_IDLE => {
446                         set_reg_field(
447                             &mut self.regs,
448                             CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
449                             1,
450                         );
451                     }
452                     _ => {
453                         error!("Invalid value passed to CTRL_REQ register");
454                         return None;
455                     }
456                 },
457                 CRB_CTRL_CANCEL => {
458                     if v == CRB_CANCEL_INVOKE
459                         && (self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE != 0)
460                     {
461                         if let Err(e) = self.emulator.cancel_cmd() {
462                             error!("Failed to run cancel command. Error: {:?}", e);
463                         }
464                     }
465                 }
466                 CRB_CTRL_START => {
467                     if v == CRB_START_INVOKE
468                         && ((self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE) == 0)
469                         && self.get_active_locality() == locality
470                     {
471                         self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE;
472 
473                         let mut cmd = BackendCmd {
474                             buffer: &mut self.data_buff,
475                             input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX),
476                         };
477 
478                         let status = self.emulator.deliver_request(&mut cmd).is_ok();
479 
480                         self.request_completed(status);
481                     }
482                 }
483                 CRB_LOC_CTRL => {
484                     warn!(
485                         "CRB_LOC_CTRL locality to write = {:?} val = {:?}",
486                         locality, v
487                     );
488                     match v {
489                         CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT => {}
490                         CRB_LOC_CTRL_RELINQUISH => {
491                             set_reg_field(
492                                 &mut self.regs,
493                                 CrbRegister::LocState(LocStateFields::LocAssigned),
494                                 0,
495                             );
496                             set_reg_field(
497                                 &mut self.regs,
498                                 CrbRegister::LocSts(LocStsFields::Granted),
499                                 0,
500                             );
501                         }
502                         CRB_LOC_CTRL_REQUEST_ACCESS => {
503                             set_reg_field(
504                                 &mut self.regs,
505                                 CrbRegister::LocSts(LocStsFields::Granted),
506                                 1,
507                             );
508                             set_reg_field(
509                                 &mut self.regs,
510                                 CrbRegister::LocSts(LocStsFields::BeenSeized),
511                                 0,
512                             );
513                             set_reg_field(
514                                 &mut self.regs,
515                                 CrbRegister::LocState(LocStateFields::LocAssigned),
516                                 1,
517                             );
518                         }
519                         _ => {
520                             error!("Invalid value to write in CRB_LOC_CTRL {:#X} ", v);
521                         }
522                     }
523                 }
524                 _ => {
525                     error!(
526                         "Invalid tpm write: offset {:#X}, data length {:?}",
527                         offset,
528                         data.len()
529                     );
530                 }
531             }
532         }
533         None
534     }
535 }
536 
537 #[cfg(test)]
538 mod tests {
539     use super::*;
540 
541     #[test]
542     fn test_set_get_reg_field() {
543         let mut regs: [u32; TPM_CRB_R_MAX] = [0; TPM_CRB_R_MAX];
544         set_reg_field(&mut regs, CrbRegister::IntfId(IntfIdFields::Rid), 0xAC);
545         assert_eq!(
546             get_reg_field(&regs, CrbRegister::IntfId(IntfIdFields::Rid)),
547             0xAC,
548             concat!("Test: ", stringify!(set_get_reg_field))
549         );
550     }
551 }
552