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