[91092] | 1 | /* $Id: DrvTpmEmuTpms.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * TPM emulation driver based on libtpms.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2021-2023 Oracle and/or its affiliates.
|
---|
[91092] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[91092] | 26 | */
|
---|
| 27 |
|
---|
| 28 |
|
---|
| 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
[91137] | 32 | #define LOG_GROUP LOG_GROUP_DRV_TPM_EMU
|
---|
[91092] | 33 | #include <VBox/vmm/pdmdrv.h>
|
---|
| 34 | #include <VBox/vmm/pdmtpmifs.h>
|
---|
| 35 | #include <iprt/assert.h>
|
---|
| 36 | #include <iprt/file.h>
|
---|
| 37 | #include <iprt/mem.h>
|
---|
| 38 | #include <iprt/string.h>
|
---|
| 39 | #include <iprt/semaphore.h>
|
---|
| 40 | #include <iprt/uuid.h>
|
---|
| 41 | #include <iprt/vfs.h>
|
---|
| 42 | #include <iprt/zip.h>
|
---|
| 43 |
|
---|
| 44 | #include <libtpms/tpm_library.h>
|
---|
| 45 | #include <libtpms/tpm_error.h>
|
---|
| 46 | #include <libtpms/tpm_tis.h>
|
---|
| 47 | #include <libtpms/tpm_nvfilename.h>
|
---|
| 48 |
|
---|
[91595] | 49 | #include <iprt/formats/tpm.h>
|
---|
| 50 |
|
---|
| 51 | #if 0
|
---|
[91092] | 52 | #include <unistd.h>
|
---|
[91595] | 53 | #endif
|
---|
[91092] | 54 | #include <stdlib.h>
|
---|
| 55 |
|
---|
| 56 | #include "VBoxDD.h"
|
---|
| 57 |
|
---|
| 58 |
|
---|
| 59 | /*********************************************************************************************************************************
|
---|
| 60 | * Defined Constants And Macros *
|
---|
| 61 | *********************************************************************************************************************************/
|
---|
| 62 |
|
---|
| 63 |
|
---|
| 64 | /*********************************************************************************************************************************
|
---|
| 65 | * Structures and Typedefs *
|
---|
| 66 | *********************************************************************************************************************************/
|
---|
| 67 |
|
---|
| 68 | /**
|
---|
| 69 | * TPM emulation driver instance data.
|
---|
| 70 | *
|
---|
| 71 | * @implements PDMITPMCONNECTOR
|
---|
| 72 | */
|
---|
| 73 | typedef struct DRVTPMEMU
|
---|
| 74 | {
|
---|
| 75 | /** The stream interface. */
|
---|
| 76 | PDMITPMCONNECTOR ITpmConnector;
|
---|
| 77 | /** Pointer to the driver instance. */
|
---|
| 78 | PPDMDRVINS pDrvIns;
|
---|
[91311] | 79 | /** The VFS interface of the driver below for NVRAM/TPM state loading and storing. */
|
---|
| 80 | PPDMIVFSCONNECTOR pDrvVfs;
|
---|
[91092] | 81 |
|
---|
| 82 | /** The TPM version we are emulating. */
|
---|
| 83 | TPMVERSION enmVersion;
|
---|
| 84 | /** The buffer size the TPM advertises. */
|
---|
| 85 | uint32_t cbBuffer;
|
---|
| 86 | /** Currently set locality. */
|
---|
| 87 | uint8_t bLoc;
|
---|
| 88 | } DRVTPMEMU;
|
---|
| 89 | /** Pointer to the TPM emulator instance data. */
|
---|
| 90 | typedef DRVTPMEMU *PDRVTPMEMU;
|
---|
| 91 |
|
---|
| 92 | /** The special no current locality selected value. */
|
---|
| 93 | #define TPM_NO_LOCALITY_SELECTED 0xff
|
---|
| 94 |
|
---|
| 95 |
|
---|
| 96 | /*********************************************************************************************************************************
|
---|
| 97 | * Global Variables *
|
---|
| 98 | *********************************************************************************************************************************/
|
---|
| 99 | /** Pointer to the (only) instance data in this driver. */
|
---|
| 100 | static PDRVTPMEMU g_pDrvTpmEmuTpms = NULL;
|
---|
| 101 |
|
---|
| 102 |
|
---|
| 103 | /*********************************************************************************************************************************
|
---|
| 104 | * Internal Functions *
|
---|
| 105 | *********************************************************************************************************************************/
|
---|
| 106 |
|
---|
[91311] | 107 | /* -=-=-=-=- PDMITPMCONNECTOR interface callabcks. -=-=-=-=- */
|
---|
| 108 |
|
---|
| 109 |
|
---|
[91092] | 110 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnGetVersion} */
|
---|
| 111 | static DECLCALLBACK(TPMVERSION) drvTpmEmuTpmsGetVersion(PPDMITPMCONNECTOR pInterface)
|
---|
| 112 | {
|
---|
| 113 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 114 | return pThis->enmVersion;
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 |
|
---|
| 118 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnGetLocalityMax} */
|
---|
| 119 | static DECLCALLBACK(uint32_t) drvTpmEmuGetLocalityMax(PPDMITPMCONNECTOR pInterface)
|
---|
| 120 | {
|
---|
| 121 | RT_NOREF(pInterface);
|
---|
| 122 | return 4;
|
---|
| 123 | }
|
---|
| 124 |
|
---|
| 125 |
|
---|
| 126 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnGetBufferSize} */
|
---|
| 127 | static DECLCALLBACK(uint32_t) drvTpmEmuGetBufferSize(PPDMITPMCONNECTOR pInterface)
|
---|
| 128 | {
|
---|
| 129 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 130 | return pThis->cbBuffer;
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 |
|
---|
| 134 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnGetEstablishedFlag} */
|
---|
| 135 | static DECLCALLBACK(bool) drvTpmEmuTpmsGetEstablishedFlag(PPDMITPMCONNECTOR pInterface)
|
---|
| 136 | {
|
---|
| 137 | RT_NOREF(pInterface);
|
---|
| 138 |
|
---|
| 139 | TPM_BOOL fTpmEst = FALSE;
|
---|
| 140 | TPM_RESULT rcTpm = TPM_IO_TpmEstablished_Get(&fTpmEst);
|
---|
| 141 | if (RT_LIKELY(rcTpm == TPM_SUCCESS))
|
---|
| 142 | return RT_BOOL(fTpmEst);
|
---|
| 143 |
|
---|
| 144 | return false;
|
---|
| 145 | }
|
---|
| 146 |
|
---|
| 147 |
|
---|
| 148 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnResetEstablishedFlag} */
|
---|
| 149 | static DECLCALLBACK(int) drvTpmEmuTpmsResetEstablishedFlag(PPDMITPMCONNECTOR pInterface, uint8_t bLoc)
|
---|
| 150 | {
|
---|
| 151 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 152 | uint8_t bLocOld = pThis->bLoc;
|
---|
| 153 |
|
---|
| 154 | pThis->bLoc = bLoc;
|
---|
| 155 | TPM_RESULT rcTpm = TPM_IO_TpmEstablished_Reset();
|
---|
| 156 | pThis->bLoc = bLocOld;
|
---|
| 157 |
|
---|
| 158 | if (RT_LIKELY(rcTpm == TPM_SUCCESS))
|
---|
| 159 | return VINF_SUCCESS;
|
---|
| 160 |
|
---|
| 161 | LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to reset the established flag with %#x\n",
|
---|
| 162 | pThis->pDrvIns->iInstance, rcTpm));
|
---|
| 163 | return VERR_DEV_IO_ERROR;
|
---|
| 164 | }
|
---|
| 165 |
|
---|
| 166 |
|
---|
| 167 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdExec} */
|
---|
| 168 | static DECLCALLBACK(int) drvTpmEmuTpmsCmdExec(PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)
|
---|
| 169 | {
|
---|
| 170 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 171 |
|
---|
| 172 | pThis->bLoc = bLoc;
|
---|
| 173 |
|
---|
| 174 | uint8_t *pbRespBuf = NULL;
|
---|
| 175 | uint32_t cbRespBuf = 0;
|
---|
| 176 | uint32_t cbRespActual = 0;
|
---|
[91595] | 177 | TPM_RESULT rcTpm = TPMLIB_Process(&pbRespBuf, &cbRespActual, &cbRespBuf, (uint8_t *)pvCmd, (uint32_t)cbCmd);
|
---|
[91092] | 178 | if (RT_LIKELY(rcTpm == TPM_SUCCESS))
|
---|
| 179 | {
|
---|
| 180 | memcpy(pvResp, pbRespBuf, RT_MIN(cbResp, cbRespActual));
|
---|
| 181 | free(pbRespBuf);
|
---|
| 182 | return VINF_SUCCESS;
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to execute command with %#x\n",
|
---|
| 186 | pThis->pDrvIns->iInstance, rcTpm));
|
---|
| 187 | return VERR_DEV_IO_ERROR;
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 |
|
---|
| 191 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdCancel} */
|
---|
| 192 | static DECLCALLBACK(int) drvTpmEmuTpmsCmdCancel(PPDMITPMCONNECTOR pInterface)
|
---|
| 193 | {
|
---|
| 194 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 195 |
|
---|
| 196 | TPM_RESULT rcTpm = TPMLIB_CancelCommand();
|
---|
| 197 | if (RT_LIKELY(rcTpm == TPM_SUCCESS))
|
---|
| 198 | return VINF_SUCCESS;
|
---|
| 199 |
|
---|
| 200 | LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to cancel outstanding command with %#x\n",
|
---|
| 201 | pThis->pDrvIns->iInstance, rcTpm));
|
---|
| 202 | return VERR_DEV_IO_ERROR;
|
---|
| 203 | }
|
---|
| 204 |
|
---|
| 205 |
|
---|
| 206 | /** @interface_method_impl{PDMIBASE,pfnQueryInterface} */
|
---|
| 207 | static DECLCALLBACK(void *) drvTpmEmuTpmsQueryInterface(PPDMIBASE pInterface, const char *pszIID)
|
---|
| 208 | {
|
---|
| 209 | PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
|
---|
| 210 | PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
|
---|
| 211 | PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
|
---|
| 212 | PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMCONNECTOR, &pThis->ITpmConnector);
|
---|
| 213 | return NULL;
|
---|
| 214 | }
|
---|
| 215 |
|
---|
| 216 |
|
---|
| 217 | /* -=-=-=-=- libtpms_callbacks -=-=-=-=- */
|
---|
| 218 |
|
---|
| 219 |
|
---|
| 220 | static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamInit(void)
|
---|
| 221 | {
|
---|
| 222 | PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
|
---|
| 223 | RT_NOREF(pThis);
|
---|
| 224 |
|
---|
| 225 | return TPM_SUCCESS;
|
---|
| 226 | }
|
---|
| 227 |
|
---|
| 228 |
|
---|
| 229 | static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamLoadData(uint8_t **ppvData, uint32_t *pcbLength,
|
---|
| 230 | uint32_t idTpm, const char *pszName)
|
---|
| 231 | {
|
---|
| 232 | PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
|
---|
| 233 |
|
---|
| 234 | AssertReturn(idTpm == 0, TPM_FAIL);
|
---|
| 235 |
|
---|
[91347] | 236 | uint64_t cbState = 0;
|
---|
| 237 | int rc = pThis->pDrvVfs->pfnQuerySize(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName, &cbState);
|
---|
| 238 | if ( RT_SUCCESS(rc)
|
---|
| 239 | && cbState == (uint32_t)cbState)
|
---|
[91092] | 240 | {
|
---|
[91347] | 241 | void *pvData = malloc(cbState);
|
---|
| 242 | if (RT_LIKELY(pvData))
|
---|
| 243 | {
|
---|
| 244 | rc = pThis->pDrvVfs->pfnReadAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName,
|
---|
| 245 | pvData, cbState);
|
---|
| 246 | if (RT_SUCCESS(rc))
|
---|
| 247 | {
|
---|
| 248 | *ppvData = (uint8_t *)pvData;
|
---|
| 249 | *pcbLength = (uint32_t)cbState;
|
---|
| 250 | return VINF_SUCCESS;
|
---|
| 251 | }
|
---|
[91092] | 252 |
|
---|
[91347] | 253 | free(pvData);
|
---|
[91092] | 254 | }
|
---|
| 255 | }
|
---|
[91347] | 256 | else if (rc == VERR_NOT_FOUND)
|
---|
| 257 | return TPM_RETRY; /* This is fine for the first start of a new VM. */
|
---|
[91092] | 258 |
|
---|
[91347] | 259 | return TPM_FAIL;
|
---|
[91092] | 260 | }
|
---|
| 261 |
|
---|
| 262 |
|
---|
| 263 | static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamStoreData(const uint8_t *pvData, uint32_t cbLength,
|
---|
| 264 | uint32_t idTpm, const char *pszName)
|
---|
| 265 | {
|
---|
| 266 | PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
|
---|
| 267 |
|
---|
| 268 | AssertReturn(idTpm == 0, TPM_FAIL);
|
---|
| 269 |
|
---|
[91347] | 270 | int rc = pThis->pDrvVfs->pfnWriteAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName,
|
---|
| 271 | pvData, cbLength);
|
---|
| 272 | if (RT_SUCCESS(rc))
|
---|
[91092] | 273 | return TPM_SUCCESS;
|
---|
| 274 |
|
---|
| 275 | return TPM_FAIL;
|
---|
| 276 | }
|
---|
| 277 |
|
---|
| 278 |
|
---|
| 279 | static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamDeleteName(uint32_t idTpm, const char *pszName, TPM_BOOL fMustExist)
|
---|
| 280 | {
|
---|
| 281 | PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
|
---|
| 282 |
|
---|
| 283 | AssertReturn(idTpm == 0, TPM_FAIL);
|
---|
| 284 |
|
---|
[91347] | 285 | int rc = pThis->pDrvVfs->pfnDelete(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName);
|
---|
| 286 | if ( RT_SUCCESS(rc)
|
---|
| 287 | || ( rc == VERR_NOT_FOUND
|
---|
| 288 | && !fMustExist))
|
---|
[91092] | 289 | return TPM_SUCCESS;
|
---|
| 290 |
|
---|
[91347] | 291 | return TPM_FAIL;
|
---|
[91092] | 292 | }
|
---|
| 293 |
|
---|
| 294 |
|
---|
| 295 | static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoInit(void)
|
---|
| 296 | {
|
---|
| 297 | return TPM_SUCCESS;
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 |
|
---|
| 301 | static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoGetLocality(TPM_MODIFIER_INDICATOR *pLocalityModifier, uint32_t idTpm)
|
---|
| 302 | {
|
---|
| 303 | PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
|
---|
| 304 |
|
---|
| 305 | AssertReturn(idTpm == 0, TPM_FAIL);
|
---|
| 306 |
|
---|
| 307 | *pLocalityModifier = pThis->bLoc;
|
---|
| 308 | return TPM_SUCCESS;
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 |
|
---|
| 312 | static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoGetPhysicalPresence(TPM_BOOL *pfPhysicalPresence, uint32_t idTpm)
|
---|
| 313 | {
|
---|
| 314 | AssertReturn(idTpm == 0, TPM_FAIL);
|
---|
| 315 |
|
---|
| 316 | *pfPhysicalPresence = TRUE;
|
---|
| 317 | return TPM_SUCCESS;
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 |
|
---|
| 321 | /* -=-=-=-=- PDMDRVREG -=-=-=-=- */
|
---|
| 322 |
|
---|
[91137] | 323 | /**
|
---|
| 324 | * @interface_method_impl{PDMDRVREG,pfnPowerOn}
|
---|
| 325 | */
|
---|
| 326 | static DECLCALLBACK(void) drvTpmEmuTpmsPowerOn(PPDMDRVINS pDrvIns)
|
---|
| 327 | {
|
---|
| 328 | PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
|
---|
| 329 |
|
---|
| 330 | TPM_RESULT rcTpm = TPMLIB_MainInit();
|
---|
| 331 | if (RT_UNLIKELY(rcTpm != TPM_SUCCESS))
|
---|
| 332 | {
|
---|
| 333 | LogRel(("DrvTpmEmuTpms#%u: Failed to initialize TPM emulation with %#x\n",
|
---|
| 334 | pDrvIns->iInstance, rcTpm));
|
---|
| 335 | PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, "Failed to startup the TPM with %u", rcTpm);
|
---|
| 336 | }
|
---|
| 337 | }
|
---|
| 338 |
|
---|
| 339 |
|
---|
| 340 | /**
|
---|
[91615] | 341 | * @interface_method_impl{PDMDRVREG,pfnReset}
|
---|
| 342 | */
|
---|
| 343 | static DECLCALLBACK(void) drvTpmEmuTpmsReset(PPDMDRVINS pDrvIns)
|
---|
| 344 | {
|
---|
| 345 | PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
|
---|
| 346 |
|
---|
| 347 | TPMLIB_Terminate();
|
---|
| 348 | TPM_RESULT rcTpm = TPMLIB_MainInit();
|
---|
| 349 | if (RT_UNLIKELY(rcTpm != TPM_SUCCESS))
|
---|
| 350 | {
|
---|
| 351 | LogRel(("DrvTpmEmuTpms#%u: Failed to reset TPM emulation with %#x\n",
|
---|
| 352 | pDrvIns->iInstance, rcTpm));
|
---|
| 353 | PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, "Failed to startup the TPM with %u", rcTpm);
|
---|
| 354 | }
|
---|
| 355 | }
|
---|
| 356 |
|
---|
| 357 |
|
---|
| 358 | /**
|
---|
[91137] | 359 | * @interface_method_impl{PDMDRVREG,pfnPowerOff}
|
---|
| 360 | */
|
---|
| 361 | static DECLCALLBACK(void) drvTpmEmuTpmsPowerOff(PPDMDRVINS pDrvIns)
|
---|
| 362 | {
|
---|
| 363 | PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
|
---|
| 364 |
|
---|
| 365 | TPMLIB_Terminate();
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 |
|
---|
[91092] | 369 | /** @copydoc FNPDMDRVCONSTRUCT */
|
---|
| 370 | static DECLCALLBACK(int) drvTpmEmuTpmsConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
|
---|
| 371 | {
|
---|
| 372 | RT_NOREF(fFlags);
|
---|
| 373 | PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
|
---|
[91867] | 374 | PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
|
---|
| 375 | PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
|
---|
[91092] | 376 |
|
---|
| 377 | /*
|
---|
| 378 | * Init the static parts.
|
---|
| 379 | */
|
---|
| 380 | pThis->pDrvIns = pDrvIns;
|
---|
| 381 | pThis->enmVersion = TPMVERSION_UNKNOWN;
|
---|
| 382 | pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
|
---|
| 383 |
|
---|
| 384 | /* IBase */
|
---|
| 385 | pDrvIns->IBase.pfnQueryInterface = drvTpmEmuTpmsQueryInterface;
|
---|
| 386 | /* ITpmConnector */
|
---|
| 387 | pThis->ITpmConnector.pfnGetVersion = drvTpmEmuTpmsGetVersion;
|
---|
| 388 | pThis->ITpmConnector.pfnGetLocalityMax = drvTpmEmuGetLocalityMax;
|
---|
| 389 | pThis->ITpmConnector.pfnGetBufferSize = drvTpmEmuGetBufferSize;
|
---|
| 390 | pThis->ITpmConnector.pfnGetEstablishedFlag = drvTpmEmuTpmsGetEstablishedFlag;
|
---|
| 391 | pThis->ITpmConnector.pfnResetEstablishedFlag = drvTpmEmuTpmsResetEstablishedFlag;
|
---|
| 392 | pThis->ITpmConnector.pfnCmdExec = drvTpmEmuTpmsCmdExec;
|
---|
| 393 | pThis->ITpmConnector.pfnCmdCancel = drvTpmEmuTpmsCmdCancel;
|
---|
| 394 |
|
---|
| 395 | /*
|
---|
| 396 | * Validate and read the configuration.
|
---|
| 397 | */
|
---|
[91347] | 398 | PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "TpmVersion|BufferSize", "");
|
---|
[91092] | 399 |
|
---|
[91595] | 400 | #if 0
|
---|
[91092] | 401 | TPMLIB_SetDebugFD(STDERR_FILENO);
|
---|
| 402 | TPMLIB_SetDebugLevel(~0);
|
---|
[91595] | 403 | #endif
|
---|
[91092] | 404 |
|
---|
[91311] | 405 | /*
|
---|
| 406 | * Try attach the VFS driver below and query it's VFS interface.
|
---|
| 407 | */
|
---|
| 408 | PPDMIBASE pBase = NULL;
|
---|
| 409 | int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
|
---|
[91347] | 410 | if (RT_FAILURE(rc))
|
---|
[91092] | 411 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
[91311] | 412 | N_("Failed to attach driver below us! %Rrc"), rc);
|
---|
[91347] | 413 | pThis->pDrvVfs = PDMIBASE_QUERY_INTERFACE(pBase, PDMIVFSCONNECTOR);
|
---|
| 414 | if (!pThis->pDrvVfs)
|
---|
| 415 | return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
|
---|
| 416 | N_("No VFS interface below"));
|
---|
[91092] | 417 |
|
---|
| 418 | TPMLIB_TPMVersion enmVersion = TPMLIB_TPM_VERSION_2;
|
---|
| 419 | uint32_t uTpmVersion = 0;
|
---|
[91867] | 420 | rc = pHlp->pfnCFGMQueryU32Def(pCfg, "TpmVersion", &uTpmVersion, 2);
|
---|
[91092] | 421 | if (RT_FAILURE(rc))
|
---|
| 422 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
| 423 | N_("Configuration error: querying \"TpmVersion\" resulted in %Rrc"), rc);
|
---|
| 424 |
|
---|
| 425 | switch (uTpmVersion)
|
---|
| 426 | {
|
---|
| 427 | case 1:
|
---|
| 428 | enmVersion = TPMLIB_TPM_VERSION_1_2;
|
---|
| 429 | pThis->enmVersion = TPMVERSION_1_2;
|
---|
| 430 | break;
|
---|
| 431 | case 2:
|
---|
| 432 | enmVersion = TPMLIB_TPM_VERSION_2;
|
---|
| 433 | pThis->enmVersion = TPMVERSION_2_0;
|
---|
| 434 | break;
|
---|
| 435 | default:
|
---|
| 436 | return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
|
---|
| 437 | N_("Configuration error: \"TpmVersion\" %u is not supported"), uTpmVersion);
|
---|
| 438 | }
|
---|
| 439 |
|
---|
| 440 | TPM_RESULT rcTpm = TPMLIB_ChooseTPMVersion(enmVersion);
|
---|
| 441 | if (rcTpm != TPM_SUCCESS)
|
---|
| 442 | return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
|
---|
| 443 | N_("Failed to set the TPM version for the emulated TPM with %d"), rcTpm);
|
---|
| 444 |
|
---|
| 445 | int cbBufferMax = 0;
|
---|
| 446 | rcTpm = TPMLIB_GetTPMProperty(TPMPROP_TPM_BUFFER_MAX, &cbBufferMax);
|
---|
| 447 | if (rcTpm != TPM_SUCCESS)
|
---|
| 448 | return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
|
---|
| 449 | N_("Querying the maximum supported buffer size failed with %u"), rcTpm);
|
---|
| 450 |
|
---|
[91867] | 451 | rc = pHlp->pfnCFGMQueryU32Def(pCfg, "BufferSize", &pThis->cbBuffer, (uint32_t)cbBufferMax);
|
---|
[91092] | 452 | if (RT_FAILURE(rc))
|
---|
| 453 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
| 454 | N_("Configuration error: querying \"BufferSize\" resulted in %Rrc"), rc);
|
---|
| 455 |
|
---|
| 456 | uint32_t cbBufferMin = 0;
|
---|
| 457 | uint32_t cbBuffer = TPMLIB_SetBufferSize(pThis->cbBuffer, &cbBufferMin, NULL /*max_size*/);
|
---|
| 458 | if (pThis->cbBuffer != cbBuffer)
|
---|
| 459 | return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
|
---|
| 460 | N_("Failed to set buffer size (%u) of the emulated TPM with %u (min %u, max %d)"),
|
---|
| 461 | pThis->cbBuffer, cbBuffer, cbBufferMin, cbBufferMax);
|
---|
| 462 |
|
---|
| 463 | struct libtpms_callbacks Callbacks;
|
---|
| 464 | Callbacks.sizeOfStruct = sizeof(Callbacks);
|
---|
| 465 | Callbacks.tpm_nvram_init = drvTpmEmuTpmsCbkNvRamInit;
|
---|
| 466 | Callbacks.tpm_nvram_loaddata = drvTpmEmuTpmsCbkNvRamLoadData;
|
---|
| 467 | Callbacks.tpm_nvram_storedata = drvTpmEmuTpmsCbkNvRamStoreData;
|
---|
| 468 | Callbacks.tpm_nvram_deletename = drvTpmEmuTpmsCbkNvRamDeleteName;
|
---|
| 469 | Callbacks.tpm_io_init = drvTpmEmuTpmsCbkIoInit;
|
---|
| 470 | Callbacks.tpm_io_getlocality = drvTpmEmuTpmsCbkIoGetLocality;
|
---|
| 471 | Callbacks.tpm_io_getphysicalpresence = drvTpmEmuTpmsCbkIoGetPhysicalPresence;
|
---|
| 472 | rcTpm = TPMLIB_RegisterCallbacks(&Callbacks);
|
---|
| 473 | if (rcTpm != TPM_SUCCESS)
|
---|
| 474 | return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
|
---|
| 475 | N_("Failed to register callbacks with the TPM emulation: %u"),
|
---|
| 476 | rcTpm);
|
---|
| 477 |
|
---|
| 478 | /* We can only have one instance of the TPM emulation and require the global variable for the callbacks unfortunately. */
|
---|
| 479 | g_pDrvTpmEmuTpms = pThis;
|
---|
| 480 | return VINF_SUCCESS;
|
---|
| 481 | }
|
---|
| 482 |
|
---|
| 483 |
|
---|
| 484 | /**
|
---|
[91093] | 485 | * TPM libtpms emulator driver registration record.
|
---|
[91092] | 486 | */
|
---|
| 487 | const PDMDRVREG g_DrvTpmEmuTpms =
|
---|
| 488 | {
|
---|
| 489 | /* u32Version */
|
---|
| 490 | PDM_DRVREG_VERSION,
|
---|
| 491 | /* szName */
|
---|
| 492 | "TpmEmuTpms",
|
---|
| 493 | /* szRCMod */
|
---|
| 494 | "",
|
---|
| 495 | /* szR0Mod */
|
---|
| 496 | "",
|
---|
| 497 | /* pszDescription */
|
---|
| 498 | "TPM emulation driver based on libtpms.",
|
---|
| 499 | /* fFlags */
|
---|
| 500 | PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
|
---|
| 501 | /* fClass. */
|
---|
| 502 | PDM_DRVREG_CLASS_STREAM,
|
---|
| 503 | /* cMaxInstances */
|
---|
| 504 | 1,
|
---|
| 505 | /* cbInstance */
|
---|
| 506 | sizeof(DRVTPMEMU),
|
---|
| 507 | /* pfnConstruct */
|
---|
| 508 | drvTpmEmuTpmsConstruct,
|
---|
| 509 | /* pfnDestruct */
|
---|
[91347] | 510 | NULL,
|
---|
[91092] | 511 | /* pfnRelocate */
|
---|
| 512 | NULL,
|
---|
| 513 | /* pfnIOCtl */
|
---|
| 514 | NULL,
|
---|
| 515 | /* pfnPowerOn */
|
---|
[91137] | 516 | drvTpmEmuTpmsPowerOn,
|
---|
[91092] | 517 | /* pfnReset */
|
---|
[91615] | 518 | drvTpmEmuTpmsReset,
|
---|
[91092] | 519 | /* pfnSuspend */
|
---|
| 520 | NULL,
|
---|
| 521 | /* pfnResume */
|
---|
| 522 | NULL,
|
---|
| 523 | /* pfnAttach */
|
---|
| 524 | NULL,
|
---|
| 525 | /* pfnDetach */
|
---|
| 526 | NULL,
|
---|
| 527 | /* pfnPowerOff */
|
---|
[91137] | 528 | drvTpmEmuTpmsPowerOff,
|
---|
[91092] | 529 | /* pfnSoftReset */
|
---|
| 530 | NULL,
|
---|
| 531 | /* u32EndVersion */
|
---|
| 532 | PDM_DRVREG_VERSION
|
---|
| 533 | };
|
---|
| 534 |
|
---|