VirtualBox

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

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

Devices/Security/DrvTpmEmuTpms.cpp: Fix saving/loading TPM states, where missing the volatile state which is not saved by libtpms automatically, bugref:10701 [scm]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.1 KB
Line 
1/* $Id: DrvTpmEmuTpms.cpp 105623 2024-08-08 12:33:42Z vboxsync $ */
2/** @file
3 * TPM emulation driver based on libtpms.
4 */
5
6/*
7 * Copyright (C) 2021-2023 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
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. */
90typedef 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. */
100static PDRVTPMEMU g_pDrvTpmEmuTpms = NULL;
101
102
103/*********************************************************************************************************************************
104* Internal Functions *
105*********************************************************************************************************************************/
106
107/* -=-=-=-=- PDMITPMCONNECTOR interface callabcks. -=-=-=-=- */
108
109
110/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetVersion} */
111static 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} */
119static DECLCALLBACK(uint32_t) drvTpmEmuGetLocalityMax(PPDMITPMCONNECTOR pInterface)
120{
121 RT_NOREF(pInterface);
122 return 4;
123}
124
125
126/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetBufferSize} */
127static 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} */
135static 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} */
149static 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} */
168static 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;
177 TPM_RESULT rcTpm = TPMLIB_Process(&pbRespBuf, &cbRespActual, &cbRespBuf, (uint8_t *)pvCmd, (uint32_t)cbCmd);
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} */
192static 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} */
207static 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
220static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamInit(void)
221{
222 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
223 RT_NOREF(pThis);
224
225 return TPM_SUCCESS;
226}
227
228
229static 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
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)
240 {
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 }
252
253 free(pvData);
254 }
255 }
256 else if (rc == VERR_NOT_FOUND)
257 return TPM_RETRY; /* This is fine for the first start of a new VM. */
258
259 return TPM_FAIL;
260}
261
262
263static 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
270 int rc = pThis->pDrvVfs->pfnWriteAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, pszName,
271 pvData, cbLength);
272 if (RT_SUCCESS(rc))
273 return TPM_SUCCESS;
274
275 return TPM_FAIL;
276}
277
278
279static 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
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))
289 return TPM_SUCCESS;
290
291 return TPM_FAIL;
292}
293
294
295static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoInit(void)
296{
297 return TPM_SUCCESS;
298}
299
300
301static 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
312static 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/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
322
323/**
324 * @callback_method_impl{FNSSMDRVSAVEPREP}
325 */
326static DECLCALLBACK(int) drvTpmEmuTpmsSavePrep(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
327{
328 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
329
330 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
331 RT_NOREF(pSSM);
332
333 /*
334 * libtpms never saves the volatile state on its own, we can only get at it through
335 * TPMLIB_GetState().
336 */
337 int rc = VINF_SUCCESS;
338 uint8_t *pbTpmState = NULL;
339 uint32_t cbTpmState = 0;
340 TPM_RESULT rcTpm = TPMLIB_GetState(TPMLIB_STATE_VOLATILE, &pbTpmState, &cbTpmState);
341 if (rcTpm == TPM_SUCCESS)
342 {
343 /* Save the volatile state in the VFS so it can get loaded on resume. */
344 rc = pThis->pDrvVfs->pfnWriteAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, TPM_VOLATILESTATE_NAME,
345 pbTpmState, cbTpmState);
346 free(pbTpmState);
347 if (RT_SUCCESS(rc))
348 {
349 rcTpm = TPMLIB_GetState(TPMLIB_STATE_PERMANENT, &pbTpmState, &cbTpmState);
350 if (rcTpm == TPM_SUCCESS)
351 {
352 rc = pThis->pDrvVfs->pfnWriteAll(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, TPM_PERMANENT_ALL_NAME,
353 pbTpmState, cbTpmState);
354 free(pbTpmState);
355 }
356 else
357 rc = VERR_NO_MEMORY;
358 }
359 }
360 else
361 rc = VERR_NO_MEMORY;
362
363 return rc;
364}
365
366
367/**
368 * @callback_method_impl{FNSSMDRVLOADDONE}
369 */
370static DECLCALLBACK(int) drvTpmEmuTpmsLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
371{
372 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
373
374 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
375 RT_NOREF(pSSM);
376
377 /* Need to construct the TPM here which will load the volatile state saved during the save state operation. */
378 TPM_RESULT rcTpm = TPMLIB_MainInit();
379 if (RT_UNLIKELY(rcTpm != TPM_SUCCESS))
380 {
381 LogRel(("DrvTpmEmuTpms#%u: Failed to initialize TPM emulation with %#x\n",
382 pDrvIns->iInstance, rcTpm));
383 PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, "Failed to startup the TPM with %u", rcTpm);
384 }
385
386 /*
387 * Need to delete the volatile state after loading was done or it will still be present
388 * next time the VM is powered on without a saved state.
389 */
390 int rc = pThis->pDrvVfs->pfnDelete(pThis->pDrvVfs, pThis->pDrvIns->pReg->szName, TPM_VOLATILESTATE_NAME);
391 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_FOUND); RT_NOREF(rc);
392
393 return VINF_SUCCESS;
394}
395
396
397/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
398
399/**
400 * @interface_method_impl{PDMDRVREG,pfnPowerOn}
401 */
402static DECLCALLBACK(void) drvTpmEmuTpmsPowerOn(PPDMDRVINS pDrvIns)
403{
404 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
405
406 TPM_RESULT rcTpm = TPMLIB_MainInit();
407 if (RT_UNLIKELY(rcTpm != TPM_SUCCESS))
408 {
409 LogRel(("DrvTpmEmuTpms#%u: Failed to initialize TPM emulation with %#x\n",
410 pDrvIns->iInstance, rcTpm));
411 PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, "Failed to startup the TPM with %u", rcTpm);
412 }
413}
414
415
416/**
417 * @interface_method_impl{PDMDRVREG,pfnReset}
418 */
419static DECLCALLBACK(void) drvTpmEmuTpmsReset(PPDMDRVINS pDrvIns)
420{
421 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
422
423 TPMLIB_Terminate();
424 TPM_RESULT rcTpm = TPMLIB_MainInit();
425 if (RT_UNLIKELY(rcTpm != TPM_SUCCESS))
426 {
427 LogRel(("DrvTpmEmuTpms#%u: Failed to reset TPM emulation with %#x\n",
428 pDrvIns->iInstance, rcTpm));
429 PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, "Failed to startup the TPM with %u", rcTpm);
430 }
431}
432
433
434/**
435 * @interface_method_impl{PDMDRVREG,pfnPowerOff}
436 */
437static DECLCALLBACK(void) drvTpmEmuTpmsPowerOff(PPDMDRVINS pDrvIns)
438{
439 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
440
441 TPMLIB_Terminate();
442}
443
444
445/** @copydoc FNPDMDRVCONSTRUCT */
446static DECLCALLBACK(int) drvTpmEmuTpmsConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
447{
448 RT_NOREF(fFlags);
449 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
450 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
451 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
452
453 /*
454 * Init the static parts.
455 */
456 pThis->pDrvIns = pDrvIns;
457 pThis->enmVersion = TPMVERSION_UNKNOWN;
458 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
459
460 /* IBase */
461 pDrvIns->IBase.pfnQueryInterface = drvTpmEmuTpmsQueryInterface;
462 /* ITpmConnector */
463 pThis->ITpmConnector.pfnGetVersion = drvTpmEmuTpmsGetVersion;
464 pThis->ITpmConnector.pfnGetLocalityMax = drvTpmEmuGetLocalityMax;
465 pThis->ITpmConnector.pfnGetBufferSize = drvTpmEmuGetBufferSize;
466 pThis->ITpmConnector.pfnGetEstablishedFlag = drvTpmEmuTpmsGetEstablishedFlag;
467 pThis->ITpmConnector.pfnResetEstablishedFlag = drvTpmEmuTpmsResetEstablishedFlag;
468 pThis->ITpmConnector.pfnCmdExec = drvTpmEmuTpmsCmdExec;
469 pThis->ITpmConnector.pfnCmdCancel = drvTpmEmuTpmsCmdCancel;
470
471 /*
472 * Validate and read the configuration.
473 */
474 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "TpmVersion|BufferSize", "");
475
476#if 0
477 TPMLIB_SetDebugFD(STDERR_FILENO);
478 TPMLIB_SetDebugLevel(~0);
479#endif
480
481 /*
482 * Try attach the VFS driver below and query it's VFS interface.
483 */
484 PPDMIBASE pBase = NULL;
485 int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
486 if (RT_FAILURE(rc))
487 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
488 N_("Failed to attach driver below us! %Rrc"), rc);
489 pThis->pDrvVfs = PDMIBASE_QUERY_INTERFACE(pBase, PDMIVFSCONNECTOR);
490 if (!pThis->pDrvVfs)
491 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
492 N_("No VFS interface below"));
493
494 TPMLIB_TPMVersion enmVersion = TPMLIB_TPM_VERSION_2;
495 uint32_t uTpmVersion = 0;
496 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "TpmVersion", &uTpmVersion, 2);
497 if (RT_FAILURE(rc))
498 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
499 N_("Configuration error: querying \"TpmVersion\" resulted in %Rrc"), rc);
500
501 switch (uTpmVersion)
502 {
503 case 1:
504 enmVersion = TPMLIB_TPM_VERSION_1_2;
505 pThis->enmVersion = TPMVERSION_1_2;
506 break;
507 case 2:
508 enmVersion = TPMLIB_TPM_VERSION_2;
509 pThis->enmVersion = TPMVERSION_2_0;
510 break;
511 default:
512 return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
513 N_("Configuration error: \"TpmVersion\" %u is not supported"), uTpmVersion);
514 }
515
516 TPM_RESULT rcTpm = TPMLIB_ChooseTPMVersion(enmVersion);
517 if (rcTpm != TPM_SUCCESS)
518 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
519 N_("Failed to set the TPM version for the emulated TPM with %d"), rcTpm);
520
521 int cbBufferMax = 0;
522 rcTpm = TPMLIB_GetTPMProperty(TPMPROP_TPM_BUFFER_MAX, &cbBufferMax);
523 if (rcTpm != TPM_SUCCESS)
524 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
525 N_("Querying the maximum supported buffer size failed with %u"), rcTpm);
526
527 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "BufferSize", &pThis->cbBuffer, (uint32_t)cbBufferMax);
528 if (RT_FAILURE(rc))
529 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
530 N_("Configuration error: querying \"BufferSize\" resulted in %Rrc"), rc);
531
532 uint32_t cbBufferMin = 0;
533 uint32_t cbBuffer = TPMLIB_SetBufferSize(pThis->cbBuffer, &cbBufferMin, NULL /*max_size*/);
534 if (pThis->cbBuffer != cbBuffer)
535 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
536 N_("Failed to set buffer size (%u) of the emulated TPM with %u (min %u, max %d)"),
537 pThis->cbBuffer, cbBuffer, cbBufferMin, cbBufferMax);
538
539 struct libtpms_callbacks Callbacks;
540 Callbacks.sizeOfStruct = sizeof(Callbacks);
541 Callbacks.tpm_nvram_init = drvTpmEmuTpmsCbkNvRamInit;
542 Callbacks.tpm_nvram_loaddata = drvTpmEmuTpmsCbkNvRamLoadData;
543 Callbacks.tpm_nvram_storedata = drvTpmEmuTpmsCbkNvRamStoreData;
544 Callbacks.tpm_nvram_deletename = drvTpmEmuTpmsCbkNvRamDeleteName;
545 Callbacks.tpm_io_init = drvTpmEmuTpmsCbkIoInit;
546 Callbacks.tpm_io_getlocality = drvTpmEmuTpmsCbkIoGetLocality;
547 Callbacks.tpm_io_getphysicalpresence = drvTpmEmuTpmsCbkIoGetPhysicalPresence;
548 rcTpm = TPMLIB_RegisterCallbacks(&Callbacks);
549 if (rcTpm != TPM_SUCCESS)
550 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
551 N_("Failed to register callbacks with the TPM emulation: %u"),
552 rcTpm);
553
554 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /*uVersion*/, 0 /*cbGuess*/,
555 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
556 drvTpmEmuTpmsSavePrep /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
557 NULL /*pfnLoadPrep*/, NULL /*pfnLoadExec*/, drvTpmEmuTpmsLoadDone /*pfnLoadDone*/);
558 if (RT_FAILURE(rc))
559 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
560 N_("Failed to register saved state handlers"));
561
562 /* We can only have one instance of the TPM emulation and require the global variable for the callbacks unfortunately. */
563 g_pDrvTpmEmuTpms = pThis;
564 return VINF_SUCCESS;
565}
566
567
568/**
569 * TPM libtpms emulator driver registration record.
570 */
571const PDMDRVREG g_DrvTpmEmuTpms =
572{
573 /* u32Version */
574 PDM_DRVREG_VERSION,
575 /* szName */
576 "TpmEmuTpms",
577 /* szRCMod */
578 "",
579 /* szR0Mod */
580 "",
581 /* pszDescription */
582 "TPM emulation driver based on libtpms.",
583 /* fFlags */
584 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
585 /* fClass. */
586 PDM_DRVREG_CLASS_STREAM,
587 /* cMaxInstances */
588 1,
589 /* cbInstance */
590 sizeof(DRVTPMEMU),
591 /* pfnConstruct */
592 drvTpmEmuTpmsConstruct,
593 /* pfnDestruct */
594 NULL,
595 /* pfnRelocate */
596 NULL,
597 /* pfnIOCtl */
598 NULL,
599 /* pfnPowerOn */
600 drvTpmEmuTpmsPowerOn,
601 /* pfnReset */
602 drvTpmEmuTpmsReset,
603 /* pfnSuspend */
604 NULL,
605 /* pfnResume */
606 NULL,
607 /* pfnAttach */
608 NULL,
609 /* pfnDetach */
610 NULL,
611 /* pfnPowerOff */
612 drvTpmEmuTpmsPowerOff,
613 /* pfnSoftReset */
614 NULL,
615 /* u32EndVersion */
616 PDM_DRVREG_VERSION
617};
618
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