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
get_crb_loc_state_field(f: LocStateFields) -> (u32, u32, u32)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;
get_crb_loc_sts_field(f: LocStsFields) -> (u32, u32, u32)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;
get_crb_intf_id_field(f: IntfIdFields) -> (u32, u32, u32)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;
get_crb_intf_id2_field(f: IntfId2Fields) -> (u32, u32, u32)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;
get_crb_ctrl_sts_field(f: CtrlStsFields) -> (u32, u32, u32)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)
get_field(reg: CrbRegister) -> (u32, u32, u32)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
set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX], reg: CrbRegister, value: u32)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
get_reg_field(regs: &[u32; TPM_CRB_R_MAX], reg: CrbRegister) -> u32203 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
locality_from_addr(addr: u32) -> u8209 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 {
new(path: String) -> Result<Self>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
get_active_locality(&mut self) -> u32236 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
request_completed(&mut self, success: bool)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
reset(&mut self) -> Result<()>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 {
read(&mut self, _base: u64, offset: u64, data: &mut [u8])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
write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>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]
test_set_get_reg_field()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(®s, CrbRegister::IntfId(IntfIdFields::Rid)),
548 0xAC,
549 concat!("Test: ", stringify!(set_get_reg_field))
550 );
551 }
552 }
553