VirtualBox

source: vbox/trunk/src/VBox/Devices/Security/DrvTpmEmuTpms.cpp@ 107328

Last change on this file since 107328 was 106259, checked in by vboxsync, 4 months ago

Devices/Security: Query the buffer size of the device above and use that to set the buffer size in libtpms, bugref:10772

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.8 KB
Line 
1/* $Id: DrvTpmEmuTpms.cpp 106259 2024-10-09 16:09:15Z vboxsync $ */
2/** @file
3 * TPM emulation driver based on libtpms.
4 */
5
6/*
7 * Copyright (C) 2021-2024 Oracle and/or its affiliates.
8 *
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
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DRV_TPM_EMU
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
49#include <iprt/formats/tpm.h>
50
51#if 0
52#include <unistd.h>
53#endif
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 */
73typedef struct DRVTPMEMU
74{
75 /** The stream interface. */
76 PDMITPMCONNECTOR ITpmConnector;
77 /** Pointer to the driver instance. */
78 PPDMDRVINS pDrvIns;
79 /** The VFS interface of the driver below for NVRAM/TPM state loading and storing. */
80 PPDMIVFSCONNECTOR pDrvVfs;
81 /** Pointer to the TPM port interface above. */
82 PPDMITPMPORT pTpmPort;
83
84 /** The TPM version we are emulating. */
85 TPMVERSION enmVersion;
86 /** The buffer size the TPM advertises. */
87 uint32_t cbBuffer;
88 /** Currently set locality. */
89 uint8_t bLoc;
90} DRVTPMEMU;
91/** Pointer to the TPM emulator instance data. */
92typedef DRVTPMEMU *PDRVTPMEMU;
93
94/** The special no current locality selected value. */
95#define TPM_NO_LOCALITY_SELECTED 0xff
96
97
98/*********************************************************************************************************************************
99* Global Variables *
100*********************************************************************************************************************************/
101/** Pointer to the (only) instance data in this driver. */
102static PDRVTPMEMU g_pDrvTpmEmuTpms = NULL;
103
104
105/*********************************************************************************************************************************
106* Internal Functions *
107*********************************************************************************************************************************/
108
109/* -=-=-=-=- PDMITPMCONNECTOR interface callabcks. -=-=-=-=- */
110
111
112/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetVersion} */
113static DECLCALLBACK(TPMVERSION) drvTpmEmuTpmsGetVersion(PPDMITPMCONNECTOR pInterface)
114{
115 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
116 return pThis->enmVersion;
117}
118
119
120/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetLocalityMax} */
121static DECLCALLBACK(uint32_t) drvTpmEmuGetLocalityMax(PPDMITPMCONNECTOR pInterface)
122{
123 RT_NOREF(pInterface);
124 return 4;
125}
126
127
128/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetBufferSize} */
129static DECLCALLBACK(uint32_t) drvTpmEmuGetBufferSize(PPDMITPMCONNECTOR pInterface)
130{
131 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
132 return pThis->cbBuffer;
133}
134
135
136/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetEstablishedFlag} */
137static DECLCALLBACK(bool) drvTpmEmuTpmsGetEstablishedFlag(PPDMITPMCONNECTOR pInterface)
138{
139 RT_NOREF(pInterface);
140
141 TPM_BOOL fTpmEst = FALSE;
142 TPM_RESULT rcTpm = TPM_IO_TpmEstablished_Get(&fTpmEst);
143 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
144 return RT_BOOL(fTpmEst);
145
146 return false;
147}
148
149
150/** @interface_method_impl{PDMITPMCONNECTOR,pfnResetEstablishedFlag} */
151static DECLCALLBACK(int) drvTpmEmuTpmsResetEstablishedFlag(PPDMITPMCONNECTOR pInterface, uint8_t bLoc)
152{
153 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
154 uint8_t bLocOld = pThis->bLoc;
155
156 pThis->bLoc = bLoc;
157 TPM_RESULT rcTpm = TPM_IO_TpmEstablished_Reset();
158 pThis->bLoc = bLocOld;
159
160 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
161 return VINF_SUCCESS;
162
163 LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to reset the established flag with %#x\n",
164 pThis->pDrvIns->iInstance, rcTpm));
165 return VERR_DEV_IO_ERROR;
166}
167
168
169/** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdExec} */
170static DECLCALLBACK(int) drvTpmEmuTpmsCmdExec(PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)
171{
172 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
173
174 pThis->bLoc = bLoc;
175
176 uint8_t *pbRespBuf = NULL;
177 uint32_t cbRespBuf = 0;
178 uint32_t cbRespActual = 0;
179 TPM_RESULT rcTpm = TPMLIB_Process(&pbRespBuf, &cbRespActual, &cbRespBuf, (uint8_t *)pvCmd, (uint32_t)cbCmd);
180 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
181 {
182 memcpy(pvResp, pbRespBuf, RT_MIN(cbResp, cbRespActual));
183 free(pbRespBuf);
184 return VINF_SUCCESS;
185 }
186
187 LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to execute command with %#x\n",
188 pThis->pDrvIns->iInstance, rcTpm));
189 return VERR_DEV_IO_ERROR;
190}
191
192
193/** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdCancel} */
194static DECLCALLBACK(int) drvTpmEmuTpmsCmdCancel(PPDMITPMCONNECTOR pInterface)
195{
196 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
197
198 TPM_RESULT rcTpm = TPMLIB_CancelCommand();
199 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
200 return VINF_SUCCESS;
201
202 LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to cancel outstanding command with %#x\n",
203 pThis->pDrvIns->iInstance, rcTpm));
204 return VERR_DEV_IO_ERROR;
205}
206
207
208/** @interface_method_impl{PDMIBASE,pfnQueryInterface} */
209static DECLCALLBACK(void *) drvTpmEmuTpmsQueryInterface(PPDMIBASE pInterface, const char *pszIID)
210{
211 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
212 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
213 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
214 PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMCONNECTOR, &pThis->ITpmConnector);
215 return NULL;
216}
217
218
219/* -=-=-=-=- libtpms_callbacks -=-=-=-=- */
220
221
222static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamInit(void)
223{
224 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
225 RT_NOREF(pThis);
226
227 return TPM_SUCCESS;
228}
229
230
231static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamLoadData(uint8_t **ppvData, uint32_t *pcbLength,
232 uint32_t idTpm, const char *pszName)
233{
234 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
235
236 AssertReturn(idTpm == 0, TPM_FAIL);
237
238 uint64_t cbState = 0;
239 int rc = pThis->pDrvVfs->pfnQuerySize(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName, &cbState);
240 if ( RT_SUCCESS(rc)
241 && cbState == (uint32_t)cbState)
242 {
243 void *pvData = malloc(cbState);
244 if (RT_LIKELY(pvData))
245 {
246 rc = pThis->pDrvVfs->pfnReadAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName,
247 pvData, cbState);
248 if (RT_SUCCESS(rc))
249 {
250 *ppvData = (uint8_t *)pvData;
251 *pcbLength = (uint32_t)cbState;
252 return VINF_SUCCESS;
253 }
254
255 free(pvData);
256 }
257 }
258 else if (rc == VERR_NOT_FOUND)
259 return TPM_RETRY; /* This is fine for the first start of a new VM. */
260
261 return TPM_FAIL;
262}
263
264
265static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamStoreData(const uint8_t *pvData, uint32_t cbLength,
266 uint32_t idTpm, const char *pszName)
267{
268 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
269
270 AssertReturn(idTpm == 0, TPM_FAIL);
271
272 int rc = pThis->pDrvVfs->pfnWriteAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName,
273 pvData, cbLength);
274 if (RT_SUCCESS(rc))
275 return TPM_SUCCESS;
276
277 return TPM_FAIL;
278}
279
280
281static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamDeleteName(uint32_t idTpm, const char *pszName, TPM_BOOL fMustExist)
282{
283 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
284
285 AssertReturn(idTpm == 0, TPM_FAIL);
286
287 int rc = pThis->pDrvVfs->pfnDelete(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName);
288 if ( RT_SUCCESS(rc)
289 || ( rc == VERR_NOT_FOUND
290 && !fMustExist))
291 return TPM_SUCCESS;
292
293 return TPM_FAIL;
294}
295
296
297static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoInit(void)
298{
299 return TPM_SUCCESS;
300}
301
302
303static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoGetLocality(TPM_MODIFIER_INDICATOR *pLocalityModifier, uint32_t idTpm)
304{
305 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
306
307 AssertReturn(idTpm == 0, TPM_FAIL);
308
309 *pLocalityModifier = pThis->bLoc;
310 return TPM_SUCCESS;
311}
312
313
314static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoGetPhysicalPresence(TPM_BOOL *pfPhysicalPresence, uint32_t idTpm)
315{
316 AssertReturn(idTpm == 0, TPM_FAIL);
317
318 *pfPhysicalPresence = TRUE;
319 return TPM_SUCCESS;
320}
321
322
323/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
324
325/**
326 * @callback_method_impl{FNSSMDRVSAVEPREP}
327 */
328static DECLCALLBACK(int) drvTpmEmuTpmsSavePrep(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
329{
330 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
331
332 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
333 RT_NOREF(pSSM);
334
335 /*
336 * libtpms never saves the volatile state on its own, we can only get at it through
337 * TPMLIB_GetState().
338 */
339 int rc = VINF_SUCCESS;
340 uint8_t *pbTpmState = NULL;
341 uint32_t cbTpmState = 0;
342 TPM_RESULT rcTpm = TPMLIB_GetState(TPMLIB_STATE_VOLATILE, &pbTpmState, &cbTpmState);
343 if (rcTpm == TPM_SUCCESS)
344 {
345 /* Save the volatile state in the VFS so it can get loaded on resume. */
346 rc = pThis->pDrvVfs->pfnWriteAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, TPM_VOLATILESTATE_NAME,
347 pbTpmState, cbTpmState);
348 free(pbTpmState);
349 if (RT_SUCCESS(rc))
350 {
351 rcTpm = TPMLIB_GetState(TPMLIB_STATE_PERMANENT, &pbTpmState, &cbTpmState);
352 if (rcTpm == TPM_SUCCESS)
353 {
354 rc = pThis->pDrvVfs->pfnWriteAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, TPM_PERMANENT_ALL_NAME,
355 pbTpmState, cbTpmState);
356 free(pbTpmState);
357 }
358 else
359 rc = VERR_NO_MEMORY;
360 }
361 }
362 else
363 rc = VERR_NO_MEMORY;
364
365 return rc;
366}
367
368
369/**
370 * @callback_method_impl{FNSSMDRVLOADDONE}
371 */
372static DECLCALLBACK(int) drvTpmEmuTpmsLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
373{
374 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
375
376 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
377 RT_NOREF(pSSM);
378
379 /* Need to construct the TPM here which will load the volatile state saved during the save state operation. */
380 TPM_RESULT rcTpm = TPMLIB_MainInit();
381 if (RT_UNLIKELY(rcTpm != TPM_SUCCESS))
382 {
383 LogRel(("DrvTpmEmuTpms#%u: Failed to initialize TPM emulation with %#x\n",
384 pDrvIns->iInstance, rcTpm));
385 PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, "Failed to startup the TPM with %u", rcTpm);
386 }
387
388 /*
389 * Need to delete the volatile state after loading was done or it will still be present
390 * next time the VM is powered on without a saved state.
391 */
392 int rc = pThis->pDrvVfs->pfnDelete(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, TPM_VOLATILESTATE_NAME);
393 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_FOUND); RT_NOREF(rc);
394
395 return VINF_SUCCESS;
396}
397
398
399/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
400
401/**
402 * @interface_method_impl{PDMDRVREG,pfnPowerOn}
403 */
404static DECLCALLBACK(void) drvTpmEmuTpmsPowerOn(PPDMDRVINS pDrvIns)
405{
406 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
407
408 TPM_RESULT rcTpm = TPMLIB_MainInit();
409 if (RT_UNLIKELY(rcTpm != TPM_SUCCESS))
410 {
411 LogRel(("DrvTpmEmuTpms#%u: Failed to initialize TPM emulation with %#x\n",
412 pDrvIns->iInstance, rcTpm));
413 PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, "Failed to startup the TPM with %u", rcTpm);
414 }
415}
416
417
418/**
419 * @interface_method_impl{PDMDRVREG,pfnReset}
420 */
421static DECLCALLBACK(void) drvTpmEmuTpmsReset(PPDMDRVINS pDrvIns)
422{
423 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
424
425 TPMLIB_Terminate();
426 TPM_RESULT rcTpm = TPMLIB_MainInit();
427 if (RT_UNLIKELY(rcTpm != TPM_SUCCESS))
428 {
429 LogRel(("DrvTpmEmuTpms#%u: Failed to reset TPM emulation with %#x\n",
430 pDrvIns->iInstance, rcTpm));
431 PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, "Failed to startup the TPM with %u", rcTpm);
432 }
433}
434
435
436/**
437 * @interface_method_impl{PDMDRVREG,pfnPowerOff}
438 */
439static DECLCALLBACK(void) drvTpmEmuTpmsPowerOff(PPDMDRVINS pDrvIns)
440{
441 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
442
443 TPMLIB_Terminate();
444}
445
446
447/** @copydoc FNPDMDRVCONSTRUCT */
448static DECLCALLBACK(int) drvTpmEmuTpmsConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
449{
450 RT_NOREF(fFlags);
451 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
452 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
453 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
454
455 /*
456 * Init the static parts.
457 */
458 pThis->pDrvIns = pDrvIns;
459 pThis->enmVersion = TPMVERSION_UNKNOWN;
460 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
461
462 /* IBase */
463 pDrvIns->IBase.pfnQueryInterface = drvTpmEmuTpmsQueryInterface;
464 /* ITpmConnector */
465 pThis->ITpmConnector.pfnGetVersion = drvTpmEmuTpmsGetVersion;
466 pThis->ITpmConnector.pfnGetLocalityMax = drvTpmEmuGetLocalityMax;
467 pThis->ITpmConnector.pfnGetBufferSize = drvTpmEmuGetBufferSize;
468 pThis->ITpmConnector.pfnGetEstablishedFlag = drvTpmEmuTpmsGetEstablishedFlag;
469 pThis->ITpmConnector.pfnResetEstablishedFlag = drvTpmEmuTpmsResetEstablishedFlag;
470 pThis->ITpmConnector.pfnCmdExec = drvTpmEmuTpmsCmdExec;
471 pThis->ITpmConnector.pfnCmdCancel = drvTpmEmuTpmsCmdCancel;
472
473 /*
474 * Validate and read the configuration.
475 */
476 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "TpmVersion|BufferSize", "");
477
478#if 0
479 TPMLIB_SetDebugFD(STDERR_FILENO);
480 TPMLIB_SetDebugLevel(~0);
481#endif
482
483 /*
484 * Query the TPM port interface of the device above.
485 */
486 pThis->pTpmPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMITPMPORT);
487 if (!pThis->pTpmPort)
488 {
489 AssertMsgFailed(("Configuration error: the above device/driver didn't export the TPM port interface!\n"));
490 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
491 N_("No TPM port interface above"));
492 }
493
494 /*
495 * Try attach the VFS driver below and query it's VFS interface.
496 */
497 PPDMIBASE pBase = NULL;
498 int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
499 if (RT_FAILURE(rc))
500 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
501 N_("Failed to attach driver below us! %Rrc"), rc);
502 pThis->pDrvVfs = PDMIBASE_QUERY_INTERFACE(pBase, PDMIVFSCONNECTOR);
503 if (!pThis->pDrvVfs)
504 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
505 N_("No VFS interface below"));
506
507 TPMLIB_TPMVersion enmVersion = TPMLIB_TPM_VERSION_2;
508 uint32_t uTpmVersion = 0;
509 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "TpmVersion", &uTpmVersion, 2);
510 if (RT_FAILURE(rc))
511 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
512 N_("Configuration error: querying \"TpmVersion\" resulted in %Rrc"), rc);
513
514 switch (uTpmVersion)
515 {
516 case 1:
517 enmVersion = TPMLIB_TPM_VERSION_1_2;
518 pThis->enmVersion = TPMVERSION_1_2;
519 break;
520 case 2:
521 enmVersion = TPMLIB_TPM_VERSION_2;
522 pThis->enmVersion = TPMVERSION_2_0;
523 break;
524 default:
525 return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
526 N_("Configuration error: \"TpmVersion\" %u is not supported"), uTpmVersion);
527 }
528
529 TPM_RESULT rcTpm = TPMLIB_ChooseTPMVersion(enmVersion);
530 if (rcTpm != TPM_SUCCESS)
531 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
532 N_("Failed to set the TPM version for the emulated TPM with %d"), rcTpm);
533
534 int cbBufferMax = 0;
535 rcTpm = TPMLIB_GetTPMProperty(TPMPROP_TPM_BUFFER_MAX, &cbBufferMax);
536 if (rcTpm != TPM_SUCCESS)
537 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
538 N_("Querying the maximum supported buffer size failed with %u"), rcTpm);
539
540 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "BufferSize", &pThis->cbBuffer, (uint32_t)cbBufferMax);
541 if (RT_FAILURE(rc))
542 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
543 N_("Configuration error: querying \"BufferSize\" resulted in %Rrc"), rc);
544
545 /* Limit to the buffer size of the device above. */
546 pThis->cbBuffer = RT_MIN(pThis->cbBuffer, pThis->pTpmPort->pfnGetMaxBufferSize(pThis->pTpmPort));
547
548 uint32_t cbBufferMin = 0;
549 uint32_t cbBuffer = TPMLIB_SetBufferSize(pThis->cbBuffer, &cbBufferMin, NULL /*max_size*/);
550 if (pThis->cbBuffer != cbBuffer)
551 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
552 N_("Failed to set buffer size (%u) of the emulated TPM with %u (min %u, max %d)"),
553 pThis->cbBuffer, cbBuffer, cbBufferMin, cbBufferMax);
554
555 struct libtpms_callbacks Callbacks;
556 Callbacks.sizeOfStruct = sizeof(Callbacks);
557 Callbacks.tpm_nvram_init = drvTpmEmuTpmsCbkNvRamInit;
558 Callbacks.tpm_nvram_loaddata = drvTpmEmuTpmsCbkNvRamLoadData;
559 Callbacks.tpm_nvram_storedata = drvTpmEmuTpmsCbkNvRamStoreData;
560 Callbacks.tpm_nvram_deletename = drvTpmEmuTpmsCbkNvRamDeleteName;
561 Callbacks.tpm_io_init = drvTpmEmuTpmsCbkIoInit;
562 Callbacks.tpm_io_getlocality = drvTpmEmuTpmsCbkIoGetLocality;
563 Callbacks.tpm_io_getphysicalpresence = drvTpmEmuTpmsCbkIoGetPhysicalPresence;
564 rcTpm = TPMLIB_RegisterCallbacks(&Callbacks);
565 if (rcTpm != TPM_SUCCESS)
566 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
567 N_("Failed to register callbacks with the TPM emulation: %u"),
568 rcTpm);
569
570 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /*uVersion*/, 0 /*cbGuess*/,
571 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
572 drvTpmEmuTpmsSavePrep /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
573 NULL /*pfnLoadPrep*/, NULL /*pfnLoadExec*/, drvTpmEmuTpmsLoadDone /*pfnLoadDone*/);
574 if (RT_FAILURE(rc))
575 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
576 N_("Failed to register saved state handlers"));
577
578 /* We can only have one instance of the TPM emulation and require the global variable for the callbacks unfortunately. */
579 g_pDrvTpmEmuTpms = pThis;
580 return VINF_SUCCESS;
581}
582
583
584/**
585 * TPM libtpms emulator driver registration record.
586 */
587const PDMDRVREG g_DrvTpmEmuTpms =
588{
589 /* u32Version */
590 PDM_DRVREG_VERSION,
591 /* szName */
592 "TpmEmuTpms",
593 /* szRCMod */
594 "",
595 /* szR0Mod */
596 "",
597 /* pszDescription */
598 "TPM emulation driver based on libtpms.",
599 /* fFlags */
600 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
601 /* fClass. */
602 PDM_DRVREG_CLASS_STREAM,
603 /* cMaxInstances */
604 1,
605 /* cbInstance */
606 sizeof(DRVTPMEMU),
607 /* pfnConstruct */
608 drvTpmEmuTpmsConstruct,
609 /* pfnDestruct */
610 NULL,
611 /* pfnRelocate */
612 NULL,
613 /* pfnIOCtl */
614 NULL,
615 /* pfnPowerOn */
616 drvTpmEmuTpmsPowerOn,
617 /* pfnReset */
618 drvTpmEmuTpmsReset,
619 /* pfnSuspend */
620 NULL,
621 /* pfnResume */
622 NULL,
623 /* pfnAttach */
624 NULL,
625 /* pfnDetach */
626 NULL,
627 /* pfnPowerOff */
628 drvTpmEmuTpmsPowerOff,
629 /* pfnSoftReset */
630 NULL,
631 /* u32EndVersion */
632 PDM_DRVREG_VERSION
633};
634
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette