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 phf::phf_map; 12 use std::cmp; 13 use std::sync::{Arc, Barrier}; 14 use thiserror::Error; 15 use tpm::emulator::{BackendCmd, Emulator}; 16 use tpm::TPM_CRB_BUFFER_MAX; 17 use tpm::TPM_SUCCESS; 18 use vm_device::BusDevice; 19 20 #[derive(Error, Debug)] 21 pub enum Error { 22 #[error("Emulator doesn't implement min required capabilities: {0}")] 23 CheckCaps(#[source] anyhow::Error), 24 #[error("Failed to initialize tpm: {0}")] 25 Init(#[source] anyhow::Error), 26 #[error("Failed to deliver tpm Command: {0}")] 27 DeliverRequest(#[source] anyhow::Error), 28 } 29 type Result<T> = anyhow::Result<T, Error>; 30 31 /* crb 32-bit registers */ 32 const CRB_LOC_STATE: u32 = 0x0; 33 //Register Fields 34 // Field => (start, length) 35 // start: lowest bit in the bit field numbered from 0 36 // length: length of the bit field 37 const CRB_LOC_STATE_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! { 38 "tpmEstablished" => [0, 1], 39 "locAssigned" => [1,1], 40 "activeLocality"=> [2, 3], 41 "reserved" => [5, 2], 42 "tpmRegValidSts" => [7, 1] 43 }; 44 const CRB_LOC_CTRL: u32 = 0x08; 45 const CRB_LOC_CTRL_REQUEST_ACCESS: u32 = 1 << 0; 46 const CRB_LOC_CTRL_RELINQUISH: u32 = 1 << 1; 47 const CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: u32 = 1 << 3; 48 const CRB_LOC_STS: u32 = 0x0C; 49 const CRB_LOC_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! { 50 "Granted" => [0, 1], 51 "beenSeized" => [1,1] 52 }; 53 const CRB_INTF_ID: u32 = 0x30; 54 const CRB_INTF_ID_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! { 55 "InterfaceType" => [0, 4], 56 "InterfaceVersion" => [4, 4], 57 "CapLocality" => [8, 1], 58 "CapCRBIdleBypass" => [9, 1], 59 "Reserved1" => [10, 1], 60 "CapDataXferSizeSupport" => [11, 2], 61 "CapFIFO" => [13, 1], 62 "CapCRB" => [14, 1], 63 "CapIFRes" => [15, 2], 64 "InterfaceSelector" => [17, 2], 65 "IntfSelLock" => [19, 1], 66 "Reserved2" => [20, 4], 67 "RID" => [24, 8] 68 }; 69 const CRB_INTF_ID2: u32 = 0x34; 70 const CRB_INTF_ID2_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! { 71 "VID" => [0, 16], 72 "DID" => [16, 16] 73 }; 74 const CRB_CTRL_REQ: u32 = 0x40; 75 const CRB_CTRL_REQ_CMD_READY: u32 = 1 << 0; 76 const CRB_CTRL_REQ_GO_IDLE: u32 = 1 << 1; 77 const CRB_CTRL_STS: u32 = 0x44; 78 const CRB_CTRL_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! { 79 "tpmSts" => [0, 1], 80 "tpmIdle" => [1, 1] 81 }; 82 const CRB_CTRL_CANCEL: u32 = 0x48; 83 const CRB_CANCEL_INVOKE: u32 = 1 << 0; 84 const CRB_CTRL_START: u32 = 0x4C; 85 const CRB_START_INVOKE: u32 = 1 << 0; 86 const CRB_CTRL_CMD_LADDR: u32 = 0x5C; 87 const CRB_CTRL_CMD_HADDR: u32 = 0x60; 88 const CRB_CTRL_RSP_SIZE: u32 = 0x64; 89 const CRB_CTRL_RSP_ADDR: u32 = 0x68; 90 const CRB_DATA_BUFFER: u32 = 0x80; 91 92 const TPM_CRB_NO_LOCALITY: u32 = 0xff; 93 94 const TPM_CRB_ADDR_BASE: u32 = TPM_START.0 as u32; 95 const TPM_CRB_ADDR_SIZE: usize = TPM_SIZE as usize; 96 97 const TPM_CRB_R_MAX: u32 = CRB_DATA_BUFFER; 98 99 // CRB Protocol details 100 const CRB_INTF_TYPE_CRB_ACTIVE: u32 = 0b1; 101 const CRB_INTF_VERSION_CRB: u32 = 0b1; 102 const CRB_INTF_CAP_LOCALITY_0_ONLY: u32 = 0b0; 103 const CRB_INTF_CAP_IDLE_FAST: u32 = 0b0; 104 const CRB_INTF_CAP_XFER_SIZE_64: u32 = 0b11; 105 const CRB_INTF_CAP_FIFO_NOT_SUPPORTED: u32 = 0b0; 106 const CRB_INTF_CAP_CRB_SUPPORTED: u32 = 0b1; 107 const CRB_INTF_IF_SELECTOR_CRB: u32 = 0b1; 108 const PCI_VENDOR_ID_IBM: u32 = 0x1014; 109 const CRB_CTRL_CMD_SIZE_REG: u32 = 0x58; 110 const CRB_CTRL_CMD_SIZE: usize = TPM_CRB_ADDR_SIZE - CRB_DATA_BUFFER as usize; 111 112 fn get_fields_map(reg: u32) -> phf::Map<&'static str, [u32; 2]> { 113 match reg { 114 CRB_LOC_STATE => CRB_LOC_STATE_FIELDS, 115 CRB_LOC_STS => CRB_LOC_STS_FIELDS, 116 CRB_INTF_ID => CRB_INTF_ID_FIELDS, 117 CRB_INTF_ID2 => CRB_INTF_ID2_FIELDS, 118 CRB_CTRL_STS => CRB_CTRL_STS_FIELDS, 119 _ => { 120 panic!( 121 "Fields in '{:?}' register were accessed which are Invalid", 122 reg 123 ); 124 } 125 } 126 } 127 128 /// Set a particular field in a Register 129 fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str, value: u32) { 130 let reg_fields = get_fields_map(reg); 131 if reg_fields.contains_key(field) { 132 let start = reg_fields.get(field).unwrap()[0]; 133 let len = reg_fields.get(field).unwrap()[1]; 134 let mask = (!(0_u32) >> (32 - len)) << start; 135 regs[reg as usize] = (regs[reg as usize] & !mask) | ((value << start) & mask); 136 } else { 137 error!( 138 "Failed to tpm Register. {:?} is not a valid field in Reg {:#X}", 139 field, reg 140 ) 141 } 142 } 143 144 /// Get the value of a particular field in a Register 145 fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str) -> u32 { 146 let reg_fields = get_fields_map(reg); 147 if reg_fields.contains_key(field) { 148 let start = reg_fields.get(field).unwrap()[0]; 149 let len = reg_fields.get(field).unwrap()[1]; 150 let mask = (!(0_u32) >> (32 - len)) << start; 151 (regs[reg as usize] & mask) >> start 152 } else { 153 // TODO: Sensible return value if fields do not exist 154 0x0 155 } 156 } 157 158 fn locality_from_addr(addr: u32) -> u8 { 159 (addr >> 12) as u8 160 } 161 162 pub struct Tpm { 163 emulator: Emulator, 164 cmd: Option<BackendCmd>, 165 regs: [u32; TPM_CRB_R_MAX as usize], 166 backend_buff_size: usize, 167 data_buff: [u8; TPM_CRB_BUFFER_MAX], 168 data_buff_len: usize, 169 } 170 171 impl Tpm { 172 pub fn new(path: String) -> Result<Self> { 173 let emulator = Emulator::new(path) 174 .map_err(|e| Error::Init(anyhow!("Failed while initializing tpm Emulator: {:?}", e)))?; 175 let mut tpm = Tpm { 176 emulator, 177 cmd: None, 178 regs: [0; TPM_CRB_R_MAX as usize], 179 backend_buff_size: TPM_CRB_BUFFER_MAX, 180 data_buff: [0; TPM_CRB_BUFFER_MAX], 181 data_buff_len: 0, 182 }; 183 tpm.reset()?; 184 Ok(tpm) 185 } 186 187 fn get_active_locality(&mut self) -> u32 { 188 if get_reg_field(&self.regs, CRB_LOC_STATE, "locAssigned") == 0 { 189 return TPM_CRB_NO_LOCALITY; 190 } 191 get_reg_field(&self.regs, CRB_LOC_STATE, "activeLocality") 192 } 193 194 fn request_completed(&mut self, result: isize) { 195 self.regs[CRB_CTRL_START as usize] = !CRB_START_INVOKE; 196 if result != 0 { 197 set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmSts", 1); 198 } 199 } 200 201 fn reset(&mut self) -> Result<()> { 202 let cur_buff_size = self.emulator.get_buffer_size().unwrap(); 203 self.regs = [0; TPM_CRB_R_MAX as usize]; 204 set_reg_field(&mut self.regs, CRB_LOC_STATE, "tpmRegValidSts", 1); 205 set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1); 206 set_reg_field( 207 &mut self.regs, 208 CRB_INTF_ID, 209 "InterfaceType", 210 CRB_INTF_TYPE_CRB_ACTIVE, 211 ); 212 set_reg_field( 213 &mut self.regs, 214 CRB_INTF_ID, 215 "InterfaceVersion", 216 CRB_INTF_VERSION_CRB, 217 ); 218 set_reg_field( 219 &mut self.regs, 220 CRB_INTF_ID, 221 "CapLocality", 222 CRB_INTF_CAP_LOCALITY_0_ONLY, 223 ); 224 set_reg_field( 225 &mut self.regs, 226 CRB_INTF_ID, 227 "CapCRBIdleBypass", 228 CRB_INTF_CAP_IDLE_FAST, 229 ); 230 set_reg_field( 231 &mut self.regs, 232 CRB_INTF_ID, 233 "CapDataXferSizeSupport", 234 CRB_INTF_CAP_XFER_SIZE_64, 235 ); 236 set_reg_field( 237 &mut self.regs, 238 CRB_INTF_ID, 239 "CapFIFO", 240 CRB_INTF_CAP_FIFO_NOT_SUPPORTED, 241 ); 242 set_reg_field( 243 &mut self.regs, 244 CRB_INTF_ID, 245 "CapCRB", 246 CRB_INTF_CAP_CRB_SUPPORTED, 247 ); 248 set_reg_field( 249 &mut self.regs, 250 CRB_INTF_ID, 251 "InterfaceSelector", 252 CRB_INTF_IF_SELECTOR_CRB, 253 ); 254 set_reg_field(&mut self.regs, CRB_INTF_ID, "RID", 0b0000); 255 set_reg_field(&mut self.regs, CRB_INTF_ID2, "VID", PCI_VENDOR_ID_IBM); 256 257 self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = CRB_CTRL_CMD_SIZE as u32; 258 self.regs[CRB_CTRL_CMD_LADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER; 259 self.regs[CRB_CTRL_RSP_SIZE as usize] = CRB_CTRL_CMD_SIZE as u32; 260 self.regs[CRB_CTRL_RSP_ADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER; 261 262 self.backend_buff_size = cmp::min(cur_buff_size, TPM_CRB_BUFFER_MAX); 263 264 if let Err(e) = self.emulator.startup_tpm(self.backend_buff_size) { 265 return Err(Error::Init(anyhow!( 266 "Failed while running Startup TPM. Error: {:?}", 267 e 268 ))); 269 } 270 Ok(()) 271 } 272 } 273 274 //impl BusDevice for TPM 275 impl BusDevice for Tpm { 276 fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) { 277 let mut offset: u32 = offset as u32; 278 let read_len: usize = data.len(); 279 280 if offset >= CRB_DATA_BUFFER 281 && (offset + read_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32) 282 { 283 // Read from Data Buffer 284 let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize); 285 let end: usize = start + read_len; 286 data[..].clone_from_slice(&self.data_buff[start..end]); 287 } else { 288 offset &= 0xff; 289 let mut val = self.regs[offset as usize]; 290 291 if offset == CRB_LOC_STATE && !self.emulator.get_established_flag() { 292 val |= 0x1; 293 } 294 295 if data.len() <= 4 { 296 data.clone_from_slice(val.to_ne_bytes()[0..read_len].as_ref()); 297 } else { 298 error!( 299 "Invalid tpm read: offset {:#X}, data length {:?}", 300 offset, 301 data.len() 302 ); 303 } 304 } 305 debug!( 306 "MMIO Read: offset {:#X} len {:?} val = {:02X?} ", 307 offset, 308 data.len(), 309 data 310 ); 311 } 312 313 fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> { 314 debug!( 315 "MMIO Write: offset {:#X} len {:?} input data {:02X?}", 316 offset, 317 data.len(), 318 data 319 ); 320 let mut offset: u32 = offset as u32; 321 if offset < CRB_DATA_BUFFER { 322 offset &= 0xff; 323 } 324 let locality = locality_from_addr(offset) as u32; 325 let write_len = data.len(); 326 327 if offset >= CRB_DATA_BUFFER 328 && (offset + write_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32) 329 { 330 let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize); 331 if start == 0 { 332 // If filling data_buff at index 0, reset length to 0 333 self.data_buff_len = 0; 334 self.data_buff.fill(0); 335 } 336 let end: usize = start + data.len(); 337 self.data_buff[start..end].clone_from_slice(data); 338 self.data_buff_len += data.len(); 339 } else { 340 // Ctrl Commands that take more than 4 bytes as input are not yet supported 341 // CTRL_RSP_ADDR usually gets 8 byte write request. Last 4 bytes are zeros. 342 if write_len > 4 && offset != CRB_CTRL_RSP_ADDR { 343 error!( 344 "Invalid tpm write: offset {:#X}, data length {}", 345 offset, 346 data.len() 347 ); 348 return None; 349 } 350 351 let mut input: [u8; 4] = [0; 4]; 352 input.copy_from_slice(&data[0..4]); 353 let v = u32::from_le_bytes(input); 354 355 match offset { 356 CRB_CTRL_CMD_SIZE_REG => { 357 self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = v; 358 } 359 CRB_CTRL_CMD_LADDR => { 360 self.regs[CRB_CTRL_CMD_LADDR as usize] = v; 361 } 362 CRB_CTRL_CMD_HADDR => { 363 self.regs[CRB_CTRL_CMD_HADDR as usize] = v; 364 } 365 CRB_CTRL_RSP_SIZE => { 366 self.regs[CRB_CTRL_RSP_SIZE as usize] = v; 367 } 368 CRB_CTRL_RSP_ADDR => { 369 self.regs[CRB_CTRL_RSP_ADDR as usize] = v; 370 } 371 CRB_CTRL_REQ => match v { 372 CRB_CTRL_REQ_CMD_READY => { 373 set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 0); 374 } 375 CRB_CTRL_REQ_GO_IDLE => { 376 set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1); 377 } 378 _ => { 379 error!("Invalid value passed to CRTL_REQ register"); 380 return None; 381 } 382 }, 383 CRB_CTRL_CANCEL => { 384 if v == CRB_CANCEL_INVOKE 385 && (self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE != 0) 386 { 387 if let Err(e) = self.emulator.cancel_cmd() { 388 error!("Failed to run cancel command. Error: {:?}", e); 389 } 390 } 391 } 392 CRB_CTRL_START => { 393 if v == CRB_START_INVOKE 394 && ((self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE) == 0) 395 && self.get_active_locality() == locality 396 { 397 self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE; 398 399 self.cmd = Some(BackendCmd { 400 locality: locality as u8, 401 input: self.data_buff[0..self.data_buff_len].to_vec(), 402 input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX), 403 output: self.data_buff.to_vec(), 404 output_len: TPM_CRB_BUFFER_MAX, 405 selftest_done: false, 406 }); 407 408 let mut cmd = self.cmd.as_ref().unwrap().clone(); 409 let output = self.emulator.deliver_request(&mut cmd).map_err(|e| { 410 Error::DeliverRequest(anyhow!( 411 "Failed to deliver tpm request. Error :{:?}", 412 e 413 )) 414 }); 415 //TODO: drop the copy here 416 self.data_buff.fill(0); 417 self.data_buff.clone_from_slice(output.unwrap().as_slice()); 418 419 self.request_completed(TPM_SUCCESS as isize); 420 } 421 } 422 CRB_LOC_CTRL => { 423 warn!( 424 "CRB_LOC_CTRL locality to write = {:?} val = {:?}", 425 locality, v 426 ); 427 match v { 428 CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT => {} 429 CRB_LOC_CTRL_RELINQUISH => { 430 set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 0); 431 set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 0); 432 } 433 CRB_LOC_CTRL_REQUEST_ACCESS => { 434 set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 1); 435 set_reg_field(&mut self.regs, CRB_LOC_STS, "beenSeized", 0); 436 set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 1); 437 } 438 _ => { 439 error!("Invalid value to write in CRB_LOC_CTRL {:#X} ", v); 440 } 441 } 442 } 443 _ => { 444 error!( 445 "Invalid tpm write: offset {:#X}, data length {:?}", 446 offset, 447 data.len() 448 ); 449 } 450 } 451 } 452 None 453 } 454 } 455 456 #[cfg(test)] 457 mod tests { 458 use super::*; 459 460 #[test] 461 fn test_set_get_reg_field() { 462 let mut regs: [u32; TPM_CRB_R_MAX as usize] = [0; TPM_CRB_R_MAX as usize]; 463 set_reg_field(&mut regs, CRB_INTF_ID, "RID", 0xAC); 464 assert_eq!( 465 get_reg_field(®s, CRB_INTF_ID, "RID"), 466 0xAC, 467 concat!("Test: ", stringify!(set_get_reg_field)) 468 ); 469 } 470 } 471