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(®s, CrbRegister::IntfId(IntfIdFields::Rid)), 547 0xAC, 548 concat!("Test: ", stringify!(set_get_reg_field)) 549 ); 550 } 551 } 552