Changeset 90492 in vbox for trunk/src/VBox/Devices/Security/DevTpm.cpp
- Timestamp:
- Aug 3, 2021 10:16:28 AM (3 years ago)
- Location:
- trunk/src/VBox/Devices/Security
- Files:
-
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Security/DevTpm.cpp
r90465 r90492 3 3 * DevTpm - Trusted Platform Module emulation. 4 4 * 5 * This emulation is based on the spec available under (as of 2021-0 7-30):6 * https://trustedcomputinggroup.org/wp-content/uploads/ TCG_PCClientTPMInterfaceSpecification_TIS__1-3_27_03212013.pdf5 * This emulation is based on the spec available under (as of 2021-08-02): 6 * https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p05p_r14_pub.pdf 7 7 */ 8 8 … … 52 52 /** Number of localities as mandated by the TPM spec. */ 53 53 #define TPM_LOCALITY_COUNT 5 54 /** Size of each locality in the TPM MMIO area (chapter 5.2).*/54 /** Size of each locality in the TPM MMIO area (chapter 6.5.2).*/ 55 55 #define TPM_LOCALITY_MMIO_SIZE 0x1000 56 56 … … 72 72 /** On reads indicates whether this locality is active (1) or not (0), writing a 1 relinquishes control for this locality. */ 73 73 # define TPM_LOCALITY_REG_ACCESS_ACTIVE RT_BIT(5) 74 /** Set bit indicates whether all other bits in the status register have valid data. */ 75 # define TPM_LOCALITY_REG_ACCESS_STS_VALID RT_BIT(7) 74 /** Set bit indicates whether all other bits in this register have valid data. */ 75 # define TPM_LOCALITY_REG_ACCESS_VALID RT_BIT(7) 76 /** Writable mask. */ 77 # define TPM_LOCALITY_REG_ACCESS_WR_MASK 0x3a 76 78 77 79 /** Interrupt enable register. */ … … 114 116 /** Command ready occured bit, writing a 1 clears the bit. */ 115 117 # define TPM_LOCALITY_REG_INT_STS_CMD_RDY RT_BIT_32(7) 118 /** Writable mask. */ 119 # define TPM_LOCALITY_REG_INT_STS_WR_MASK UINT32_C(0x87) 116 120 117 121 /** Interfacce capabilities register. */ … … 154 158 # define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_21 0 155 159 /** Interface 1.3. */ 156 # define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3 1 160 # define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3 2 161 /** Interface 1.3 for TPM 2.0. */ 162 # define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3_TPM2 3 157 163 158 164 /** TPM status register. */ … … 197 203 198 204 /** 205 * Possible locality states 206 * (see chapter 5.6.12.1 Figure 3 State Transition Diagram). 207 */ 208 typedef enum DEVTPMLOCALITYSTATE 209 { 210 /** Invalid state, do not use. */ 211 DEVTPMLOCALITYSTATE_INVALID = 0, 212 /** Init state. */ 213 DEVTPMLOCALITYSTATE_INIT, 214 /** Ready to accept command data. */ 215 DEVTPMLOCALITYSTATE_READY, 216 /** Command data being transfered. */ 217 DEVTPMLOCALITYSTATE_CMD_RECEPTION, 218 /** Command is being executed by the TPM. */ 219 DEVTPMLOCALITYSTATE_CMD_EXEC, 220 /** Command has completed and data can be read. */ 221 DEVTPMLOCALITYSTATE_CMD_COMPLETION, 222 /** 32bit hack. */ 223 DEVTPMLOCALITYSTATE_32BIT_HACK = 0x7fffffff 224 } DEVTPMLOCALITYSTATE; 225 226 227 /** 199 228 * Locality state. 200 229 */ 201 230 typedef struct DEVTPMLOCALITY 202 231 { 232 /** The current state of the locality. */ 233 DEVTPMLOCALITYSTATE enmState; 234 /** Access register state. */ 235 uint32_t uRegAccess; 203 236 /** The interrupt enable register. */ 204 237 uint32_t uRegIntEn; … … 226 259 uint8_t uIrq; 227 260 261 /** Currently selected locality. */ 262 uint8_t bLoc; 228 263 /** States of the implemented localities. */ 229 264 DEVTPMLOCALITY aLoc[TPM_LOCALITY_COUNT]; … … 232 267 /** Pointer to the shared TPM device state. */ 233 268 typedef DEVTPM *PDEVTPM; 269 270 /** The special no current locality selected value. */ 271 #define TPM_NO_LOCALITY_SELECTED 0xff 234 272 235 273 … … 276 314 277 315 278 #if 0 279 PDMBOTHCBDECL(void) tpmIrqReq(PPDMDEVINS pDevIns, int iLvl) 280 { 281 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM); 316 /** 317 * Sets the IRQ line of the given device to the given state. 318 * 319 * @returns nothing. 320 * @param pDevIns Pointer to the PDM device instance data. 321 * @param pThis Pointer to the shared TPM device. 322 * @param iLvl The interrupt level to set. 323 */ 324 DECLINLINE(void) tpmIrqReq(PPDMDEVINS pDevIns, PDEVTPM pThis, int iLvl) 325 { 282 326 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl); 283 327 } 284 #endif 285 286 328 329 330 /** 331 * Updates the IRQ status of the given locality. 332 * 333 * @returns nothing. 334 * @param pDevIns Pointer to the PDM device instance data. 335 * @param pThis Pointer to the shared TPM device. 336 * @param pLoc The locality state. 337 */ 338 PDMBOTHCBDECL(void) tpmLocIrqUpdate(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc) 339 { 340 if (pLoc->uRegIntEn & pLoc->uRegIntSts) 341 tpmIrqReq(pDevIns, pThis, 1); 342 else 343 tpmIrqReq(pDevIns, pThis, 0); 344 } 345 346 347 /** 348 * Returns the given locality being accessed from the given TPM MMIO offset. 349 * 350 * @returns Locality number. 351 * @param off The offset into the TPM MMIO region. 352 */ 287 353 DECLINLINE(uint8_t) tpmGetLocalityFromOffset(RTGCPHYS off) 288 354 { … … 291 357 292 358 359 /** 360 * Returns the given register of a particular locality being accessed from the given TPM MMIO offset. 361 * 362 * @returns Register index being accessed. 363 * @param off The offset into the TPM MMIO region. 364 */ 293 365 DECLINLINE(uint32_t) tpmGetRegisterFromOffset(RTGCPHYS off) 294 366 { … … 313 385 VBOXSTRICTRC rc = VINF_SUCCESS; 314 386 uint32_t uReg = tpmGetRegisterFromOffset(off); 315 uint8_t uLoc = tpmGetLocalityFromOffset(off);316 PDEVTPMLOCALITY pLoc = &pThis->aLoc[ uLoc];387 uint8_t bLoc = tpmGetLocalityFromOffset(off); 388 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc]; 317 389 uint32_t u32; 318 390 switch (uReg) 319 391 { 392 case TPM_LOCALITY_REG_ACCESS: 393 u32 = 0; 394 break; 320 395 case TPM_LOCALITY_REG_INT_ENABLE: 321 396 u32 = pLoc->uRegIntEn; 322 397 break; 398 case TPM_LOCALITY_REG_INT_VEC: 399 u32 = pThis->uIrq; 400 break; 323 401 case TPM_LOCALITY_REG_INT_STS: 324 402 u32 = pLoc->uRegIntSts; 403 break; 404 case TPM_LOCALITY_REG_IF_CAP: 405 u32 = TPM_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL 406 | TPM_LOCALITY_REG_IF_CAP_INT_STS_VALID 407 | TPM_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE 408 | TPM_LOCALITY_REG_IF_CAP_INT_LVL_LOW 409 | TPM_LOCALITY_REG_IF_CAP_INT_CMD_RDY 410 | TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B) 411 | TPM_LOCALITY_REG_IF_CAP_IF_VERSION_SET(TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3); /** @todo Make some of them configurable? */ 412 break; 413 case TPM_LOCALITY_REG_STS: 414 if (bLoc != pThis->bLoc) 415 { 416 u32 = UINT32_MAX; 417 break; 418 } 419 /** @todo */ 420 break; 421 case TPM_LOCALITY_REG_DATA_FIFO: 422 case TPM_LOCALITY_REG_DATA_XFIFO: 423 /** @todo */ 325 424 break; 326 425 case TPM_LOCALITY_REG_DID_VID: … … 368 467 LogFlowFunc((": %RGp %#x\n", off, u32)); 369 468 469 VBOXSTRICTRC rc = VINF_SUCCESS; 370 470 uint32_t uReg = tpmGetRegisterFromOffset(off); 371 uint8_t uLoc = tpmGetLocalityFromOffset(off); 372 PDEVTPMLOCALITY pLoc = &pThis->aLoc[uLoc]; 373 RT_NOREF(uReg, uLoc, pLoc); 374 375 VBOXSTRICTRC rc = VINF_SUCCESS; 471 uint8_t bLoc = tpmGetLocalityFromOffset(off); 472 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc]; 473 switch (uReg) 474 { 475 case TPM_LOCALITY_REG_ACCESS: 476 u32 &= TPM_LOCALITY_REG_ACCESS_WR_MASK; 477 /* 478 * Chapter 5.6.11, 2 states that writing to this register with more than one 479 * bit set to '1' is vendor specific, we decide to ignore such writes to make the logic 480 * below simpler. 481 */ 482 if (!RT_IS_POWER_OF_TWO(u32)) 483 break; 484 /** @todo */ 485 break; 486 case TPM_LOCALITY_REG_INT_ENABLE: 487 if (bLoc != pThis->bLoc) 488 break; 489 /** @todo */ 490 break; 491 case TPM_LOCALITY_REG_INT_STS: 492 if (bLoc != pThis->bLoc) 493 break; 494 pLoc->uRegSts &= ~(u32 & TPM_LOCALITY_REG_INT_STS_WR_MASK); 495 tpmLocIrqUpdate(pDevIns, pThis, pLoc); 496 break; 497 case TPM_LOCALITY_REG_STS: 498 /* 499 * Writes are ignored completely if the locality being accessed is not the 500 * current active one or if the value has multiple bits set (not a power of two), 501 * see chapter 5.6.12.1. 502 */ 503 if ( bLoc != pThis->bLoc 504 || !RT_IS_POWER_OF_TWO(u32)) 505 break; 506 /** @todo */ 507 break; 508 case TPM_LOCALITY_REG_DATA_FIFO: 509 case TPM_LOCALITY_REG_DATA_XFIFO: 510 if (bLoc != pThis->bLoc) 511 break; 512 /** @todo */ 513 break; 514 case TPM_LOCALITY_REG_INT_VEC: 515 case TPM_LOCALITY_REG_IF_CAP: 516 case TPM_LOCALITY_REG_DID_VID: 517 case TPM_LOCALITY_REG_RID: 518 default: /* Ignore. */ 519 break; 520 } 521 376 522 return rc; 377 523 } … … 452 598 { 453 599 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM); 454 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC); 455 RT_NOREF(pThis, pThisCC); 456 /** @todo */ 600 601 pThis->bLoc = TPM_NO_LOCALITY_SELECTED; 602 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aLoc); i++) 603 { 604 PDEVTPMLOCALITY pLoc = &pThis->aLoc[i]; 605 606 pLoc->enmState = DEVTPMLOCALITYSTATE_INIT; 607 pLoc->aRegIntEn = 0; 608 pLoc->aRegIntSts = 0; 609 } 457 610 } 458 611
Note:
See TracChangeset
for help on using the changeset viewer.