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: {0}")] 22 CheckCaps(#[source] anyhow::Error), 23 #[error("Failed to initialize tpm: {0}")] 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(®s, CrbRegister::IntfId(IntfIdFields::Rid)), 548 0xAC, 549 concat!("Test: ", stringify!(set_get_reg_field)) 550 ); 551 } 552 } 553