VirtualBox

source: vbox/trunk/src/VBox/Devices/Security/DevTpm.cpp@ 90492

Last change on this file since 90492 was 90492, checked in by vboxsync, 3 years ago

Devices: Rename TPM directory to Security, bugref:10075

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.8 KB
Line 
1/* $Id: DevTpm.cpp 90492 2021-08-03 10:16:28Z vboxsync $ */
2/** @file
3 * DevTpm - Trusted Platform Module emulation.
4 *
5 * 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 */
8
9/*
10 * Copyright (C) 2021 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21
22/*********************************************************************************************************************************
23* Header Files *
24*********************************************************************************************************************************/
25#define LOG_GROUP LOG_GROUP_DEFAULT /** @todo DEV_TPM */
26#include <VBox/vmm/pdmdev.h>
27#include <iprt/assert.h>
28#include <iprt/string.h>
29
30#include "VBoxDD.h"
31
32
33/*********************************************************************************************************************************
34* Defined Constants And Macros *
35*********************************************************************************************************************************/
36
37/** The TPM saved state version. */
38#define TPM_SAVED_STATE_VERSION 1
39
40/** Default vendor ID. */
41#define TPM_VID_DEFAULT 0x1014
42/** Default device ID. */
43#define TPM_DID_DEFAULT 0x0001
44/** Default revision ID. */
45#define TPM_RID_DEFAULT 0x01
46
47/** The TPM MMIO base default as defined in chapter 5.2. */
48#define TPM_MMIO_BASE_DEFAULT 0xfed40000
49/** The size of the TPM MMIO area. */
50#define TPM_MMIO_SIZE 0x5000
51
52/** Number of localities as mandated by the TPM spec. */
53#define TPM_LOCALITY_COUNT 5
54/** Size of each locality in the TPM MMIO area (chapter 6.5.2).*/
55#define TPM_LOCALITY_MMIO_SIZE 0x1000
56
57/** @name TPM locality register related defines.
58 * @{ */
59/** Ownership management for a particular locality. */
60#define TPM_LOCALITY_REG_ACCESS 0x00
61/** INdicates whether a dynamic OS has been established on this platform before.. */
62# define TPM_LOCALITY_REG_ESTABLISHMENT RT_BIT(0)
63/** On reads indicates whether the locality requests use of the TPM (1) or not or is already active locality (0),
64 * writing a 1 requests the locality to be granted getting the active locality.. */
65# define TPM_LOCALITY_REG_REQUEST_USE RT_BIT(1)
66/** Indicates whether another locality is requesting usage of the TPM. */
67# define TPM_LOCALITY_REG_PENDING_REQUEST RT_BIT(2)
68/** Writing a 1 forces the TPM to give control to the locality if it has a higher priority. */
69# define TPM_LOCALITY_REG_ACCESS_SEIZE RT_BIT(3)
70/** On reads indicates whether this locality has been seized by a higher locality (1) or not (0), writing a 1 clears this bit. */
71# define TPM_LOCALITY_REG_ACCESS_BEEN_SEIZED RT_BIT(4)
72/** On reads indicates whether this locality is active (1) or not (0), writing a 1 relinquishes control for this locality. */
73# define TPM_LOCALITY_REG_ACCESS_ACTIVE RT_BIT(5)
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
78
79/** Interrupt enable register. */
80#define TPM_LOCALITY_REG_INT_ENABLE 0x08
81/** Data available interrupt enable bit. */
82# define TPM_LOCALITY_REG_INT_ENABLE_DATA_AVAIL RT_BIT_32(0)
83/** Status valid interrupt enable bit. */
84# define TPM_LOCALITY_REG_INT_ENABLE_STS_VALID RT_BIT_32(1)
85/** Locality change interrupt enable bit. */
86# define TPM_LOCALITY_REG_INT_ENABLE_LOCALITY_CHANGE RT_BIT_32(2)
87/** Interrupt polarity configuration. */
88# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_MASK 0x18
89# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_SHIFT 3
90# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_SET(a) ((a) << TPM_LOCALITY_REG_INT_POLARITY_SHIFT)
91# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_GET(a) (((a) & TPM_LOCALITY_REG_INT_POLARITY_MASK) >> TPM_LOCALITY_REG_INT_POLARITY_SHIFT)
92/** High level interrupt trigger. */
93# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_HIGH 0
94/** Low level interrupt trigger. */
95# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_LOW 1
96/** Rising edge interrupt trigger. */
97# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_RISING 2
98/** Falling edge interrupt trigger. */
99# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_FALLING 3
100/** Command ready enable bit. */
101# define TPM_LOCALITY_REG_INT_ENABLE_CMD_RDY RT_BIT_32(7)
102/** Global interrupt enable/disable bit. */
103# define TPM_LOCALITY_REG_INT_ENABLE_GLOBAL RT_BIT_32(31)
104
105/** Configured interrupt vector register. */
106#define TPM_LOCALITY_REG_INT_VEC 0x0c
107
108/** Interrupt status register. */
109#define TPM_LOCALITY_REG_INT_STS 0x10
110/** Data available interrupt occured bit, writing a 1 clears the bit. */
111# define TPM_LOCALITY_REG_INT_STS_DATA_AVAIL RT_BIT_32(0)
112/** Status valid interrupt occured bit, writing a 1 clears the bit. */
113# define TPM_LOCALITY_REG_INT_STS_STS_VALID RT_BIT_32(1)
114/** Locality change interrupt occured bit, writing a 1 clears the bit. */
115# define TPM_LOCALITY_REG_INT_STS_LOCALITY_CHANGE RT_BIT_32(2)
116/** Command ready occured bit, writing a 1 clears the bit. */
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)
120
121/** Interfacce capabilities register. */
122#define TPM_LOCALITY_REG_IF_CAP 0x14
123/** Flag whether the TPM supports the data avilable interrupt. */
124# define TPM_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL RT_BIT(0)
125/** Flag whether the TPM supports the status valid interrupt. */
126# define TPM_LOCALITY_REG_IF_CAP_INT_STS_VALID RT_BIT(1)
127/** Flag whether the TPM supports the data avilable interrupt. */
128# define TPM_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE RT_BIT(2)
129/** Flag whether the TPM supports high level interrupts. */
130# define TPM_LOCALITY_REG_IF_CAP_INT_LVL_HIGH RT_BIT(3)
131/** Flag whether the TPM supports low level interrupts. */
132# define TPM_LOCALITY_REG_IF_CAP_INT_LVL_LOW RT_BIT(4)
133/** Flag whether the TPM supports rising edge interrupts. */
134# define TPM_LOCALITY_REG_IF_CAP_INT_RISING_EDGE RT_BIT(5)
135/** Flag whether the TPM supports falling edge interrupts. */
136# define TPM_LOCALITY_REG_IF_CAP_INT_FALLING_EDGE RT_BIT(6)
137/** Flag whether the TPM supports the command ready interrupt. */
138# define TPM_LOCALITY_REG_IF_CAP_INT_CMD_RDY RT_BIT(7)
139/** Flag whether the busrt count field is static or dynamic. */
140# define TPM_LOCALITY_REG_IF_CAP_BURST_CNT_STATIC RT_BIT(8)
141/** Maximum transfer size support. */
142# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_MASK 0x600
143# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT 9
144# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(a) ((a) << TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT)
145/** Only legacy transfers supported. */
146# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_LEGACY 0x0
147/** 8B maximum transfer size. */
148# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_8B 0x1
149/** 32B maximum transfer size. */
150# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_32B 0x2
151/** 64B maximum transfer size. */
152# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B 0x3
153/** Interface version. */
154# define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_MASK UINT32_C(0x70000000)
155# define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT 28
156# define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_SET(a) ((a) << TPM_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT)
157/** Interface 1.21 or ealier. */
158# define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_21 0
159/** Interface 1.3. */
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
163
164/** TPM status register. */
165#define TPM_LOCALITY_REG_STS 0x18
166/** Writing a 1 forces the TPM to re-send the response. */
167# define TPM_LOCALITY_REG_STS_RESPONSE_RETRY RT_BIT_32(1)
168/** Indicating whether the TPM has finished a self test. */
169# define TPM_LOCALITY_REG_STS_SELF_TEST_DONE RT_BIT_32(2)
170/** Flag indicating whether the TPM expects more data for the command. */
171# define TPM_LOCALITY_REG_STS_EXPECT RT_BIT_32(3)
172/** Flag indicating whether the TPM has more response data available. */
173# define TPM_LOCALITY_REG_STS_DATA_AVAIL RT_BIT_32(4)
174/** Written by software to cause the TPM to execute a previously transfered command. */
175# define TPM_LOCALITY_REG_STS_TPM_GO RT_BIT_32(5)
176/** On reads indicates whether the TPM is ready to receive a new command (1) or not (0),
177 * a write of 1 causes the TPM to transition to this state. */
178# define TPM_LOCALITY_REG_STS_CMD_RDY RT_BIT_32(6)
179/** Indicates whether the Expect and data available bits are valid. */
180# define TPM_LOCALITY_REG_STS_VALID RT_BIT_32(7)
181# define TPM_LOCALITY_REG_STS_BURST_CNT_MASK UINT32_C(0xffff00)
182# define TPM_LOCALITY_REG_STS_BURST_CNT_SHIFT 8
183# define TPM_LOCALITY_REG_STS_BURST_CNT_SET(a) ((a) << TPM_LOCALITY_REG_STS_BURST_CNT_SHIFT)
184
185/** TPM end of HASH operation signal register for locality 4. */
186#define TPM_LOCALITY_REG_HASH_END 0x20
187/** Data FIFO read/write register. */
188#define TPM_LOCALITY_REG_DATA_FIFO 0x24
189/** TPM start of HASH operation signal register for locality 4. */
190#define TPM_LOCALITY_REG_HASH_START 0x28
191/** Extended data FIFO read/write register. */
192#define TPM_LOCALITY_REG_XDATA_FIFO 0x80
193/** TPM device and vendor ID. */
194#define TPM_LOCALITY_REG_DID_VID 0xf00
195/** TPM revision ID. */
196#define TPM_LOCALITY_REG_RID 0xf04
197/** @} */
198
199
200/*********************************************************************************************************************************
201* Structures and Typedefs *
202*********************************************************************************************************************************/
203
204/**
205 * Possible locality states
206 * (see chapter 5.6.12.1 Figure 3 State Transition Diagram).
207 */
208typedef 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/**
228 * Locality state.
229 */
230typedef struct DEVTPMLOCALITY
231{
232 /** The current state of the locality. */
233 DEVTPMLOCALITYSTATE enmState;
234 /** Access register state. */
235 uint32_t uRegAccess;
236 /** The interrupt enable register. */
237 uint32_t uRegIntEn;
238 /** The interrupt status register. */
239 uint32_t uRegIntSts;
240} DEVTPMLOCALITY;
241typedef DEVTPMLOCALITY *PDEVTPMLOCALITY;
242typedef const DEVTPMLOCALITY *PCDEVTPMLOCALITY;
243
244
245/**
246 * Shared TPM device state.
247 */
248typedef struct DEVTPM
249{
250 /** The handle of the MMIO region. */
251 IOMMMIOHANDLE hMmio;
252 /** The vendor ID configured. */
253 uint16_t uVenId;
254 /** The device ID configured. */
255 uint16_t uDevId;
256 /** The revision ID configured. */
257 uint8_t bRevId;
258 /** The IRQ value. */
259 uint8_t uIrq;
260
261 /** Currently selected locality. */
262 uint8_t bLoc;
263 /** States of the implemented localities. */
264 DEVTPMLOCALITY aLoc[TPM_LOCALITY_COUNT];
265
266} DEVTPM;
267/** Pointer to the shared TPM device state. */
268typedef DEVTPM *PDEVTPM;
269
270/** The special no current locality selected value. */
271#define TPM_NO_LOCALITY_SELECTED 0xff
272
273
274/**
275 * TPM device state for ring-3.
276 */
277typedef struct DEVTPMR3
278{
279 uint8_t bDummy;
280} DEVTPMR3;
281/** Pointer to the TPM device state for ring-3. */
282typedef DEVTPMR3 *PDEVTPMR3;
283
284
285/**
286 * TPM device state for ring-0.
287 */
288typedef struct DEVTPMR0
289{
290 uint8_t bDummy;
291} DEVTPMR0;
292/** Pointer to the TPM device state for ring-0. */
293typedef DEVTPMR0 *PDEVTPMR0;
294
295
296/**
297 * TPM device state for raw-mode.
298 */
299typedef struct DEVTPMRC
300{
301 uint8_t bDummy;
302} DEVTPMRC;
303/** Pointer to the TPM device state for raw-mode. */
304typedef DEVTPMRC *PDEVTPMRC;
305
306/** The TPM device state for the current context. */
307typedef CTX_SUFF(DEVTPM) DEVTPMCC;
308/** Pointer to the TPM device state for the current context. */
309typedef CTX_SUFF(PDEVTPM) PDEVTPMCC;
310
311
312#ifndef VBOX_DEVICE_STRUCT_TESTCASE
313
314
315
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 */
324DECLINLINE(void) tpmIrqReq(PPDMDEVINS pDevIns, PDEVTPM pThis, int iLvl)
325{
326 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl);
327}
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 */
338PDMBOTHCBDECL(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 */
353DECLINLINE(uint8_t) tpmGetLocalityFromOffset(RTGCPHYS off)
354{
355 return off / TPM_LOCALITY_MMIO_SIZE;
356}
357
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 */
365DECLINLINE(uint32_t) tpmGetRegisterFromOffset(RTGCPHYS off)
366{
367 return off % TPM_LOCALITY_MMIO_SIZE;
368}
369
370
371/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
372
373
374/**
375 * @callback_method_impl{FNIOMMMIONEWREAD}
376 */
377static DECLCALLBACK(VBOXSTRICTRC) tpmMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
378{
379 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
380 RT_NOREF(pvUser);
381
382 Assert(!(off & (cb - 1)));
383
384 LogFlowFunc((": %RGp %#x\n", off, cb));
385 VBOXSTRICTRC rc = VINF_SUCCESS;
386 uint32_t uReg = tpmGetRegisterFromOffset(off);
387 uint8_t bLoc = tpmGetLocalityFromOffset(off);
388 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
389 uint32_t u32;
390 switch (uReg)
391 {
392 case TPM_LOCALITY_REG_ACCESS:
393 u32 = 0;
394 break;
395 case TPM_LOCALITY_REG_INT_ENABLE:
396 u32 = pLoc->uRegIntEn;
397 break;
398 case TPM_LOCALITY_REG_INT_VEC:
399 u32 = pThis->uIrq;
400 break;
401 case TPM_LOCALITY_REG_INT_STS:
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 */
424 break;
425 case TPM_LOCALITY_REG_DID_VID:
426 u32 = RT_H2BE_U32(RT_MAKE_U32(pThis->uVenId, pThis->uDevId));
427 break;
428 case TPM_LOCALITY_REG_RID:
429 u32 = pThis->bRevId;
430 break;
431 default: /* Return ~0. */
432 u32 = UINT32_MAX;
433 break;
434 }
435
436 switch (cb)
437 {
438 case 1: *(uint8_t *)pv = (uint8_t)u32; break;
439 case 2: *(uint16_t *)pv = (uint16_t)u32; break;
440 case 4: *(uint32_t *)pv = u32; break;
441 default: AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR);
442 }
443
444 return rc;
445}
446
447
448/**
449 * @callback_method_impl{FNIOMMMIONEWWRITE}
450 */
451static DECLCALLBACK(VBOXSTRICTRC) tpmMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
452{
453 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
454 RT_NOREF(pvUser);
455
456 Assert(!(off & (cb - 1)));
457
458 uint32_t u32;
459 switch (cb)
460 {
461 case 1: u32 = *(const uint8_t *)pv; break;
462 case 2: u32 = *(const uint16_t *)pv; break;
463 case 4: u32 = *(const uint32_t *)pv; break;
464 default: AssertFailedReturn(VERR_INTERNAL_ERROR);
465 }
466
467 LogFlowFunc((": %RGp %#x\n", off, u32));
468
469 VBOXSTRICTRC rc = VINF_SUCCESS;
470 uint32_t uReg = tpmGetRegisterFromOffset(off);
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
522 return rc;
523}
524
525
526#ifdef IN_RING3
527
528
529/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
530
531/**
532 * @callback_method_impl{FNSSMDEVLIVEEXEC}
533 */
534static DECLCALLBACK(int) tpmR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
535{
536 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
537 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
538 RT_NOREF(uPass);
539
540 pHlp->pfnSSMPutU8(pSSM, pThis->uIrq);
541 return VINF_SSM_DONT_CALL_AGAIN;
542}
543
544
545/**
546 * @callback_method_impl{FNSSMDEVSAVEEXEC}
547 */
548static DECLCALLBACK(int) tpmR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
549{
550 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
551 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
552
553 pHlp->pfnSSMPutU8(pSSM, pThis->uIrq);
554
555 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
556}
557
558
559/**
560 * @callback_method_impl{FNSSMDEVLOADEXEC}
561 */
562static DECLCALLBACK(int) tpmR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
563{
564 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
565 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
566 uint8_t bIrq;
567 int rc;
568
569 AssertMsgReturn(uVersion >= TPM_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
570 pHlp->pfnSSMGetU8( pSSM, &bIrq);
571 if (uPass == SSM_PASS_FINAL)
572 {
573 /* The marker. */
574 uint32_t u32;
575 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
576 AssertRCReturn(rc, rc);
577 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
578 }
579
580 /*
581 * Check the config.
582 */
583 if (pThis->uIrq != bIrq)
584 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
585 N_("Config mismatch - saved IRQ=%#x; configured IRQ=%#x"),
586 bIrq, pThis->uIrq);
587
588 return VINF_SUCCESS;
589}
590
591
592/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
593
594/**
595 * @interface_method_impl{PDMDEVREG,pfnReset}
596 */
597static DECLCALLBACK(void) tpmR3Reset(PPDMDEVINS pDevIns)
598{
599 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
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 }
610}
611
612
613/**
614 * @interface_method_impl{PDMDEVREG,pfnDestruct}
615 */
616static DECLCALLBACK(int) tpmR3Destruct(PPDMDEVINS pDevIns)
617{
618 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
619 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
620
621 /** @todo */
622 RT_NOREF(pThis);
623 return VINF_SUCCESS;
624}
625
626
627/**
628 * @interface_method_impl{PDMDEVREG,pfnConstruct}
629 */
630static DECLCALLBACK(int) tpmR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
631{
632 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
633 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
634 //PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
635 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
636 int rc;
637
638 RT_NOREF(iInstance);
639
640 /*
641 * Validate and read the configuration.
642 */
643 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq"
644 "|MmioBase"
645 "|VendorId"
646 "|DeviceId"
647 "|RevisionId",
648 "");
649
650 uint8_t uIrq = 0;
651 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Irq", &uIrq, 10);
652 if (RT_FAILURE(rc))
653 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
654
655 RTGCPHYS GCPhysMmio;
656 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioBase", &GCPhysMmio, TPM_MMIO_BASE_DEFAULT);
657 if (RT_FAILURE(rc))
658 return PDMDEV_SET_ERROR(pDevIns, rc,
659 N_("Configuration error: Failed to get the \"MmioBase\" value"));
660
661 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "VendorId", &pThis->uDevId, TPM_VID_DEFAULT);
662 if (RT_FAILURE(rc))
663 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"VendorId\" value"));
664
665 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "DeviceId", &pThis->uDevId, TPM_DID_DEFAULT);
666 if (RT_FAILURE(rc))
667 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"DeviceId\" value"));
668
669 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "RevisionId", &pThis->bRevId, TPM_RID_DEFAULT);
670 if (RT_FAILURE(rc))
671 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"RevisionId\" value"));
672
673 pThis->uIrq = uIrq;
674
675 /*
676 * Register the MMIO range, PDM API requests page aligned
677 * addresses and sizes.
678 */
679 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmio, TPM_MMIO_SIZE, tpmMmioWrite, tpmMmioRead,
680 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
681 "TPM MMIO", &pThis->hMmio);
682 AssertRCReturn(rc, rc);
683
684 /*
685 * Saved state.
686 */
687 rc = PDMDevHlpSSMRegister3(pDevIns, TPM_SAVED_STATE_VERSION, sizeof(*pThis),
688 tpmR3LiveExec, tpmR3SaveExec, tpmR3LoadExec);
689 AssertRCReturn(rc, rc);
690
691 tpmR3Reset(pDevIns);
692 return VINF_SUCCESS;
693}
694
695#else /* !IN_RING3 */
696
697/**
698 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
699 */
700static DECLCALLBACK(int) tpmRZConstruct(PPDMDEVINS pDevIns)
701{
702 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
703 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
704 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
705
706 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, tpmMmioWrite, tpmMmioRead, NULL /*pvUser*/);
707 AssertRCReturn(rc, rc);
708
709 return VINF_SUCCESS;
710}
711
712#endif /* !IN_RING3 */
713
714/**
715 * The device registration structure.
716 */
717const PDMDEVREG g_DeviceTpm =
718{
719 /* .u32Version = */ PDM_DEVREG_VERSION,
720 /* .uReserved0 = */ 0,
721 /* .szName = */ "tpm",
722 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
723 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
724 /* .cMaxInstances = */ 1,
725 /* .uSharedVersion = */ 42,
726 /* .cbInstanceShared = */ sizeof(DEVTPM),
727 /* .cbInstanceCC = */ sizeof(DEVTPMCC),
728 /* .cbInstanceRC = */ sizeof(DEVTPMRC),
729 /* .cMaxPciDevices = */ 0,
730 /* .cMaxMsixVectors = */ 0,
731 /* .pszDescription = */ "Trusted Platform Module",
732#if defined(IN_RING3)
733 /* .pszRCMod = */ "VBoxDDRC.rc",
734 /* .pszR0Mod = */ "VBoxDDR0.r0",
735 /* .pfnConstruct = */ tpmR3Construct,
736 /* .pfnDestruct = */ tpmR3Destruct,
737 /* .pfnRelocate = */ NULL,
738 /* .pfnMemSetup = */ NULL,
739 /* .pfnPowerOn = */ NULL,
740 /* .pfnReset = */ tpmR3Reset,
741 /* .pfnSuspend = */ NULL,
742 /* .pfnResume = */ NULL,
743 /* .pfnAttach = */ NULL,
744 /* .pfnDetach = */ NULL,
745 /* .pfnQueryInterface = */ NULL,
746 /* .pfnInitComplete = */ NULL,
747 /* .pfnPowerOff = */ NULL,
748 /* .pfnSoftReset = */ NULL,
749 /* .pfnReserved0 = */ NULL,
750 /* .pfnReserved1 = */ NULL,
751 /* .pfnReserved2 = */ NULL,
752 /* .pfnReserved3 = */ NULL,
753 /* .pfnReserved4 = */ NULL,
754 /* .pfnReserved5 = */ NULL,
755 /* .pfnReserved6 = */ NULL,
756 /* .pfnReserved7 = */ NULL,
757#elif defined(IN_RING0)
758 /* .pfnEarlyConstruct = */ NULL,
759 /* .pfnConstruct = */ tpmRZConstruct,
760 /* .pfnDestruct = */ NULL,
761 /* .pfnFinalDestruct = */ NULL,
762 /* .pfnRequest = */ NULL,
763 /* .pfnReserved0 = */ NULL,
764 /* .pfnReserved1 = */ NULL,
765 /* .pfnReserved2 = */ NULL,
766 /* .pfnReserved3 = */ NULL,
767 /* .pfnReserved4 = */ NULL,
768 /* .pfnReserved5 = */ NULL,
769 /* .pfnReserved6 = */ NULL,
770 /* .pfnReserved7 = */ NULL,
771#elif defined(IN_RC)
772 /* .pfnConstruct = */ tpmRZConstruct,
773 /* .pfnReserved0 = */ NULL,
774 /* .pfnReserved1 = */ NULL,
775 /* .pfnReserved2 = */ NULL,
776 /* .pfnReserved3 = */ NULL,
777 /* .pfnReserved4 = */ NULL,
778 /* .pfnReserved5 = */ NULL,
779 /* .pfnReserved6 = */ NULL,
780 /* .pfnReserved7 = */ NULL,
781#else
782# error "Not in IN_RING3, IN_RING0 or IN_RC!"
783#endif
784 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
785};
786
787#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
788
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