VirtualBox

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

Last change on this file since 90689 was 90587, checked in by vboxsync, 4 years ago

Devices/Security: EFI can communicate with the external TPM emulator over our own TPM interface emulation, bugref:10075

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.0 KB
Line 
1/* $Id: DevTpm.cpp 90587 2021-08-10 09:39:57Z 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 <VBox/vmm/pdmtpmifs.h>
28#include <iprt/assert.h>
29#include <iprt/string.h>
30#include <iprt/uuid.h>
31
32#include <iprt/formats/tpm.h>
33
34#include "VBoxDD.h"
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40
41/** The TPM saved state version. */
42#define TPM_SAVED_STATE_VERSION 1
43
44/** Default vendor ID. */
45#define TPM_VID_DEFAULT 0x1014
46/** Default device ID. */
47#define TPM_DID_DEFAULT 0x0001
48/** Default revision ID. */
49#define TPM_RID_DEFAULT 0x01
50
51/** The TPM MMIO base default as defined in chapter 5.2. */
52#define TPM_MMIO_BASE_DEFAULT 0xfed40000
53/** The size of the TPM MMIO area. */
54#define TPM_MMIO_SIZE 0x5000
55
56/** Number of localities as mandated by the TPM spec. */
57#define TPM_LOCALITY_COUNT 5
58/** Size of each locality in the TPM MMIO area (chapter 6.5.2).*/
59#define TPM_LOCALITY_MMIO_SIZE 0x1000
60
61/** @name TPM locality register related defines for the FIFO interface.
62 * @{ */
63/** Ownership management for a particular locality. */
64#define TPM_FIFO_LOCALITY_REG_ACCESS 0x00
65/** Indicates whether a dynamic OS has been established on this platform before.. */
66# define TPM_FIFO_LOCALITY_REG_ESTABLISHMENT RT_BIT(0)
67/** On reads indicates whether the locality requests use of the TPM (1) or not or is already active locality (0),
68 * writing a 1 requests the locality to be granted getting the active locality.. */
69# define TPM_FIFO_LOCALITY_REG_REQUEST_USE RT_BIT(1)
70/** Indicates whether another locality is requesting usage of the TPM. */
71# define TPM_FIFO_LOCALITY_REG_PENDING_REQUEST RT_BIT(2)
72/** Writing a 1 forces the TPM to give control to the locality if it has a higher priority. */
73# define TPM_FIFO_LOCALITY_REG_ACCESS_SEIZE RT_BIT(3)
74/** On reads indicates whether this locality has been seized by a higher locality (1) or not (0), writing a 1 clears this bit. */
75# define TPM_FIFO_LOCALITY_REG_ACCESS_BEEN_SEIZED RT_BIT(4)
76/** On reads indicates whether this locality is active (1) or not (0), writing a 1 relinquishes control for this locality. */
77# define TPM_FIFO_LOCALITY_REG_ACCESS_ACTIVE RT_BIT(5)
78/** Set bit indicates whether all other bits in this register have valid data. */
79# define TPM_FIFO_LOCALITY_REG_ACCESS_VALID RT_BIT(7)
80/** Writable mask. */
81# define TPM_FIFO_LOCALITY_REG_ACCESS_WR_MASK 0x3a
82
83/** Interrupt enable register. */
84#define TPM_FIFO_LOCALITY_REG_INT_ENABLE 0x08
85/** Data available interrupt enable bit. */
86# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_DATA_AVAIL RT_BIT_32(0)
87/** Status valid interrupt enable bit. */
88# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_STS_VALID RT_BIT_32(1)
89/** Locality change interrupt enable bit. */
90# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_LOCALITY_CHANGE RT_BIT_32(2)
91/** Interrupt polarity configuration. */
92# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_MASK 0x18
93# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_SHIFT 3
94# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_INT_POLARITY_SHIFT)
95# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_GET(a) (((a) & TPM_FIFO_LOCALITY_REG_INT_POLARITY_MASK) >> TPM_FIFO_LOCALITY_REG_INT_POLARITY_SHIFT)
96/** High level interrupt trigger. */
97# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_HIGH 0
98/** Low level interrupt trigger. */
99# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_LOW 1
100/** Rising edge interrupt trigger. */
101# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_RISING 2
102/** Falling edge interrupt trigger. */
103# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_FALLING 3
104/** Command ready enable bit. */
105# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_CMD_RDY RT_BIT_32(7)
106/** Global interrupt enable/disable bit. */
107# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_GLOBAL RT_BIT_32(31)
108
109/** Configured interrupt vector register. */
110#define TPM_FIFO_LOCALITY_REG_INT_VEC 0x0c
111
112/** Interrupt status register. */
113#define TPM_FIFO_LOCALITY_REG_INT_STS 0x10
114/** Data available interrupt occured bit, writing a 1 clears the bit. */
115# define TPM_FIFO_LOCALITY_REG_INT_STS_DATA_AVAIL RT_BIT_32(0)
116/** Status valid interrupt occured bit, writing a 1 clears the bit. */
117# define TPM_FIFO_LOCALITY_REG_INT_STS_STS_VALID RT_BIT_32(1)
118/** Locality change interrupt occured bit, writing a 1 clears the bit. */
119# define TPM_FIFO_LOCALITY_REG_INT_STS_LOCALITY_CHANGE RT_BIT_32(2)
120/** Command ready occured bit, writing a 1 clears the bit. */
121# define TPM_FIFO_LOCALITY_REG_INT_STS_CMD_RDY RT_BIT_32(7)
122/** Writable mask. */
123# define TPM_FIFO_LOCALITY_REG_INT_STS_WR_MASK UINT32_C(0x87)
124
125/** Interfacce capabilities register. */
126#define TPM_FIFO_LOCALITY_REG_IF_CAP 0x14
127/** Flag whether the TPM supports the data avilable interrupt. */
128# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL RT_BIT(0)
129/** Flag whether the TPM supports the status valid interrupt. */
130# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_STS_VALID RT_BIT(1)
131/** Flag whether the TPM supports the data avilable interrupt. */
132# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE RT_BIT(2)
133/** Flag whether the TPM supports high level interrupts. */
134# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_HIGH RT_BIT(3)
135/** Flag whether the TPM supports low level interrupts. */
136# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_LOW RT_BIT(4)
137/** Flag whether the TPM supports rising edge interrupts. */
138# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_RISING_EDGE RT_BIT(5)
139/** Flag whether the TPM supports falling edge interrupts. */
140# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_FALLING_EDGE RT_BIT(6)
141/** Flag whether the TPM supports the command ready interrupt. */
142# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_CMD_RDY RT_BIT(7)
143/** Flag whether the busrt count field is static or dynamic. */
144# define TPM_FIFO_LOCALITY_REG_IF_CAP_BURST_CNT_STATIC RT_BIT(8)
145/** Maximum transfer size support. */
146# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_MASK 0x600
147# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT 9
148# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT)
149/** Only legacy transfers supported. */
150# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_LEGACY 0x0
151/** 8B maximum transfer size. */
152# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_8B 0x1
153/** 32B maximum transfer size. */
154# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_32B 0x2
155/** 64B maximum transfer size. */
156# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B 0x3
157/** Interface version. */
158# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_MASK UINT32_C(0x70000000)
159# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT 28
160# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT)
161/** Interface 1.21 or ealier. */
162# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_21 0
163/** Interface 1.3. */
164# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3 2
165/** Interface 1.3 for TPM 2.0. */
166# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3_TPM2 3
167
168/** TPM status register. */
169#define TPM_FIFO_LOCALITY_REG_STS 0x18
170/** Writing a 1 forces the TPM to re-send the response. */
171# define TPM_FIFO_LOCALITY_REG_STS_RESPONSE_RETRY RT_BIT_32(1)
172/** Indicating whether the TPM has finished a self test. */
173# define TPM_FIFO_LOCALITY_REG_STS_SELF_TEST_DONE RT_BIT_32(2)
174/** Flag indicating whether the TPM expects more data for the command. */
175# define TPM_FIFO_LOCALITY_REG_STS_EXPECT RT_BIT_32(3)
176/** Flag indicating whether the TPM has more response data available. */
177# define TPM_FIFO_LOCALITY_REG_STS_DATA_AVAIL RT_BIT_32(4)
178/** Written by software to cause the TPM to execute a previously transfered command. */
179# define TPM_FIFO_LOCALITY_REG_STS_TPM_GO RT_BIT_32(5)
180/** On reads indicates whether the TPM is ready to receive a new command (1) or not (0),
181 * a write of 1 causes the TPM to transition to this state. */
182# define TPM_FIFO_LOCALITY_REG_STS_CMD_RDY RT_BIT_32(6)
183/** Indicates whether the Expect and data available bits are valid. */
184# define TPM_FIFO_LOCALITY_REG_STS_VALID RT_BIT_32(7)
185# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_MASK UINT32_C(0xffff00)
186# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SHIFT 8
187# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SHIFT)
188
189/** TPM end of HASH operation signal register for locality 4. */
190#define TPM_FIFO_LOCALITY_REG_HASH_END 0x20
191/** Data FIFO read/write register. */
192#define TPM_FIFO_LOCALITY_REG_DATA_FIFO 0x24
193/** TPM start of HASH operation signal register for locality 4. */
194#define TPM_FIFO_LOCALITY_REG_HASH_START 0x28
195/** Extended data FIFO read/write register. */
196#define TPM_FIFO_LOCALITY_REG_XDATA_FIFO 0x80
197/** TPM device and vendor ID. */
198#define TPM_FIFO_LOCALITY_REG_DID_VID 0xf00
199/** TPM revision ID. */
200#define TPM_FIFO_LOCALITY_REG_RID 0xf04
201/** @} */
202
203
204/** @name TPM locality register related defines for the CRB interface.
205 * @{ */
206/** Locality state register. */
207#define TPM_CRB_LOCALITY_REG_STATE 0x00
208/** Indicates whether a dynamic OS has been established on this platform before.. */
209# define TPM_CRB_LOCALITY_REG_ESTABLISHMENT RT_BIT(0)
210/** Flag whether the host has a locality assigned (1) or not (0). */
211# define TPM_CRB_LOCALITY_REG_STATE_LOC_ASSIGNED RT_BIT(1)
212/** Indicates the currently active locality. */
213# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_MASK UINT32_C(0x1c)
214# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SHIFT 2
215# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(a) ((a) << TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SHIFT)
216/** Flag whether the register contains valid values. */
217# define TPM_CRB_LOCALITY_REG_STATE_VALID RT_BIT(7)
218
219/** Locality control register. */
220#define TPM_CRB_LOCALITY_REG_CTRL 0x08
221/** Request TPM access from this locality. */
222# define TPM_CRB_LOCALITY_REG_CTRL_REQ_ACCESS RT_BIT(0)
223/** Release TPM access from this locality. */
224# define TPM_CRB_LOCALITY_REG_CTRL_RELINQUISH RT_BIT(1)
225/** Seize TPM access in favor of this locality if it has a higher priority. */
226# define TPM_CRB_LOCALITY_REG_CTRL_SEIZE RT_BIT(2)
227/** Resets the established bit if written from locality 3 or 4. */
228# define TPM_CRB_LOCALITY_REG_CTRL_RST_ESTABLISHMENT RT_BIT(3)
229
230/** Locality status register. */
231#define TPM_CRB_LOCALITY_REG_STS 0x0c
232/** Locality has been granted access to the TPM. */
233# define TPM_CRB_LOCALITY_REG_STS_GRANTED RT_BIT(0)
234/** A higher locality has seized the TPM from this locality. */
235# define TPM_CRB_LOCALITY_REG_STS_SEIZED RT_BIT(1)
236
237/** Locality interface ID register. */
238#define TPM_CRB_LOCALITY_REG_INTF_ID 0x30
239/** Interface type field. */
240# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_MASK UINT32_C(0xf)
241# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SHIFT 0
242# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SET(a) ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SHIFT)
243/** FIFO interface as defined in PTP for TPM 2.0 is active. */
244# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_FIFO_TPM20 0x0
245/** CRB interface is active. */
246# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_CRB 0x1
247/** FIFO interface as defined in TIS 1.3 is active. */
248# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_TIS1_3 0xf
249/** Interface type field. */
250# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_MASK UINT32_C(0xf)
251# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SHIFT 4
252# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SET(a) ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SHIFT)
253/** FIFO interface for TPM 2.0 */
254# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_FIFO 0
255/** CRB interface version 0. */
256# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_CRB 1
257/** Only locality 0 is supported when clear, set if 5 localities are supported. */
258# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_LOCALITY RT_BIT(8)
259/** @todo TPM supports ... */
260# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB_IDLE_BYPASS RT_BIT(9)
261/** Maximum transfer size support. */
262# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_MASK 0x1800
263# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SHIFT 11
264# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT)
265/** Only legacy transfers supported. */
266# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_LEGACY 0x0
267/** 8B maximum transfer size. */
268# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_8B 0x1
269/** 32B maximum transfer size. */
270# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_32B 0x2
271/** 64B maximum transfer size. */
272# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B 0x3
273/** FIFO interface is supported and may be selected. */
274# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_FIFO RT_BIT(13)
275/** CRB interface is supported and may be selected. */
276# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB RT_BIT(14)
277/** Interrupt polarity configuration. */
278# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_MASK 0x60000
279# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT 17
280# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SET(a) ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT)
281# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_GET(a) (((a) & TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_MASK) >> TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT)
282/** Selects the FIFO interface, takes effect on next _TPM_INIT. */
283# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_FIFO 0
284/** Selects the CRB interface, takes effect on next _TPM_INIT. */
285# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_CRB 1
286/** Locks the interface selector field and prevents further changes. */
287# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_LOCK RT_BIT(19)
288/** Revision ID field. */
289# define TPM_CRB_LOCALITY_REG_INTF_ID_RID_SHIFT 17
290# define TPM_CRB_LOCALITY_REG_INTF_ID_RID_SET(a) ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_RID_SHIFT)
291/** Vendor ID field. */
292# define TPM_CRB_LOCALITY_REG_INTF_ID_VID_SHIFT 32
293# define TPM_CRB_LOCALITY_REG_INTF_ID_VID_SET(a) ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_VID_SHIFT)
294/** Device ID field. */
295# define TPM_CRB_LOCALITY_REG_INTF_ID_DID_SHIFT 48
296# define TPM_CRB_LOCALITY_REG_INTF_ID_DID_SET(a) ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_DID_SHIFT)
297
298/** Locality CRB extension register (optional and locality 0 only). */
299#define TPM_CRB_LOCALITY_REG_CTRL_EXT 0x38
300
301/** Locality CRB request register. */
302#define TPM_CRB_LOCALITY_REG_CTRL_REQ 0x40
303/** The TPM should transition to the ready state to receive a new command. */
304# define TPM_CRB_LOCALITY_REG_CTRL_REQ_CMD_RDY RT_BIT(0)
305/** The TPM should transition to the idle state. */
306# define TPM_CRB_LOCALITY_REG_CTRL_REQ_IDLE RT_BIT(1)
307
308/** Locality CRB status register. */
309#define TPM_CRB_LOCALITY_REG_CTRL_STS 0x44
310/** This bit indicates that the TPM ran into a fatal error if set. */
311# define TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_FATAL_ERR RT_BIT(0)
312/** This bit indicates that the TPM is in the idle state. */
313# define TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_IDLE RT_BIT(1)
314
315/** Locality CRB cancel register. */
316#define TPM_CRB_LOCALITY_REG_CTRL_CANCEL 0x48
317/** Locality CRB start register. */
318#define TPM_CRB_LOCALITY_REG_CTRL_START 0x4c
319
320/** Locality interrupt enable register. */
321#define TPM_CRB_LOCALITY_REG_INT_ENABLE 0x50
322/** Enable the "TPM has executed a reqeust and response is available" interrupt. */
323# define TPM_CRB_LOCALITY_REG_INT_ENABLE_START RT_BIT(0)
324/** Enable the "TPM has transitioned to the command ready state" interrupt. */
325# define TPM_CRB_LOCALITY_REG_INT_CMD_RDY RT_BIT(1)
326/** Enable the "TPM has cleared the establishment flag" interrupt. */
327# define TPM_CRB_LOCALITY_REG_INT_ESTABLISHMENT_CLR RT_BIT(2)
328/** Enable the "active locality has changed" interrupt. */
329# define TPM_CRB_LOCALITY_REG_INT_LOC_CHANGED RT_BIT(3)
330/** Enables interrupts globally as defined by the individual bits in this register. */
331# define TPM_CRB_LOCALITY_REG_INT_GLOBAL_ENABLE RT_BIT(31)
332
333/** Locality interrupt status register. */
334#define TPM_CRB_LOCALITY_REG_INT_STS 0x54
335/** Indicates that the TPM as executed a command and the response is available for reading, writing a 1 clears the bit. */
336# define TPM_CRB_LOCALITY_REG_INT_STS_START RT_BIT(0)
337/** Indicates that the TPM has finished the transition to the ready state, writing a 1 clears this bit. */
338# define TPM_CRB_LOCALITY_REG_INT_STS_CMD_RDY RT_BIT(1)
339/** Indicates that the TPM has cleared the establishment flag, writing a 1 clears this bit. */
340# define TPM_CRB_LOCALITY_REG_INT_STS_ESTABLISHMENT_CLR RT_BIT(2)
341/** Indicates that a locality change has occurrec, writing a 1 clears this bit. */
342# define TPM_CRB_LOCALITY_REG_INT_STS_LOC_CHANGED RT_BIT(3)
343
344/** Locality command buffer size register. */
345#define TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ 0x58
346/** Locality command buffer low address register. */
347#define TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR 0x5c
348/** Locality command buffer low address register. */
349#define TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR 0x60
350/** Locality response buffer size register. */
351#define TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ 0x64
352/** Locality response buffer address register. */
353#define TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR 0x68
354/** Locality data buffer. */
355#define TPM_CRB_LOCALITY_REG_DATA_BUFFER 0x80
356/** Size of the data buffer. */
357#define TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE 3968
358/** @} */
359
360
361/*********************************************************************************************************************************
362* Structures and Typedefs *
363*********************************************************************************************************************************/
364
365/**
366 * Possible TPM states
367 * (see chapter 5.6.12.1 Figure 3 State Transition Diagram).
368 */
369typedef enum DEVTPMSTATE
370{
371 /** Invalid state, do not use. */
372 DEVTPMSTATE_INVALID = 0,
373 /** Idle state. */
374 DEVTPMSTATE_IDLE,
375 /** Ready to accept command data. */
376 DEVTPMSTATE_READY,
377 /** Command data being transfered. */
378 DEVTPMSTATE_CMD_RECEPTION,
379 /** Command is being executed by the TPM. */
380 DEVTPMSTATE_CMD_EXEC,
381 /** Command has completed and data can be read. */
382 DEVTPMSTATE_CMD_COMPLETION,
383 /** Command is being canceled. */
384 DEVTPMSTATE_CMD_CANCEL,
385 /** TPM ran into a fatal error and is not operational. */
386 DEVTPMSTATE_FATAL_ERROR,
387 /** 32bit hack. */
388 DEVTPMSTATE_32BIT_HACK = 0x7fffffff
389} DEVTPMSTATE;
390
391
392/**
393 * Locality state.
394 */
395typedef struct DEVTPMLOCALITY
396{
397 /** The interrupt enable register. */
398 uint32_t uRegIntEn;
399 /** The interrupt status register. */
400 uint32_t uRegIntSts;
401} DEVTPMLOCALITY;
402/** Pointer to a locality state. */
403typedef DEVTPMLOCALITY *PDEVTPMLOCALITY;
404/** Pointer to a const locality state. */
405typedef const DEVTPMLOCALITY *PCDEVTPMLOCALITY;
406
407
408/**
409 * Shared TPM device state.
410 */
411typedef struct DEVTPM
412{
413 /** Base MMIO address of the TPM device. */
414 RTGCPHYS GCPhysMmio;
415 /** The handle of the MMIO region. */
416 IOMMMIOHANDLE hMmio;
417 /** The handle for the ring-3 task. */
418 PDMTASKHANDLE hTpmCmdTask;
419 /** The vendor ID configured. */
420 uint16_t uVenId;
421 /** The device ID configured. */
422 uint16_t uDevId;
423 /** The revision ID configured. */
424 uint8_t bRevId;
425 /** The IRQ value. */
426 uint8_t uIrq;
427 /** Flag whether CRB access mode is used. */
428 bool fCrb;
429
430 /** Currently selected locality. */
431 uint8_t bLoc;
432 /** States of the implemented localities. */
433 DEVTPMLOCALITY aLoc[TPM_LOCALITY_COUNT];
434 /** Bitmask of localities having requested access to the TPM. */
435 uint32_t bmLocReqAcc;
436 /** Bitmask of localities having been seized access from the TPM. */
437 uint32_t bmLocSeizedAcc;
438 /** The current state of the TPM. */
439 DEVTPMSTATE enmState;
440
441 /** Command/Response buffer. */
442 uint8_t abCmdResp[TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE];
443} DEVTPM;
444/** Pointer to the shared TPM device state. */
445typedef DEVTPM *PDEVTPM;
446
447/** The special no current locality selected value. */
448#define TPM_NO_LOCALITY_SELECTED 0xff
449
450
451/**
452 * TPM device state for ring-3.
453 */
454typedef struct DEVTPMR3
455{
456 /** Pointer to the device instance. */
457 PPDMDEVINS pDevIns;
458 /** The base interface for LUN\#0. */
459 PDMIBASE IBase;
460 /** The base interface below. */
461 R3PTRTYPE(PPDMIBASE) pDrvBase;
462 /** The TPM connector interface below. */
463 R3PTRTYPE(PPDMITPMCONNECTOR) pDrvTpm;
464} DEVTPMR3;
465/** Pointer to the TPM device state for ring-3. */
466typedef DEVTPMR3 *PDEVTPMR3;
467
468
469/**
470 * TPM device state for ring-0.
471 */
472typedef struct DEVTPMR0
473{
474 uint32_t u32Dummy;
475} DEVTPMR0;
476/** Pointer to the TPM device state for ring-0. */
477typedef DEVTPMR0 *PDEVTPMR0;
478
479
480/**
481 * TPM device state for raw-mode.
482 */
483typedef struct DEVTPMRC
484{
485 uint32_t u32Dummy;
486} DEVTPMRC;
487/** Pointer to the TPM device state for raw-mode. */
488typedef DEVTPMRC *PDEVTPMRC;
489
490/** The TPM device state for the current context. */
491typedef CTX_SUFF(DEVTPM) DEVTPMCC;
492/** Pointer to the TPM device state for the current context. */
493typedef CTX_SUFF(PDEVTPM) PDEVTPMCC;
494
495
496#ifndef VBOX_DEVICE_STRUCT_TESTCASE
497
498
499
500/**
501 * Sets the IRQ line of the given device to the given state.
502 *
503 * @returns nothing.
504 * @param pDevIns Pointer to the PDM device instance data.
505 * @param pThis Pointer to the shared TPM device.
506 * @param iLvl The interrupt level to set.
507 */
508DECLINLINE(void) tpmIrqReq(PPDMDEVINS pDevIns, PDEVTPM pThis, int iLvl)
509{
510 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl);
511}
512
513
514/**
515 * Updates the IRQ status of the given locality.
516 *
517 * @returns nothing.
518 * @param pDevIns Pointer to the PDM device instance data.
519 * @param pThis Pointer to the shared TPM device.
520 * @param pLoc The locality state.
521 */
522PDMBOTHCBDECL(void) tpmLocIrqUpdate(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc)
523{
524 if ( (pLoc->uRegIntEn & TPM_CRB_LOCALITY_REG_INT_GLOBAL_ENABLE)
525 && (pLoc->uRegIntEn & pLoc->uRegIntSts))
526 tpmIrqReq(pDevIns, pThis, 1);
527 else
528 tpmIrqReq(pDevIns, pThis, 0);
529}
530
531
532/**
533 * Sets the interrupt status for the given locality, firing an interrupt if necessary.
534 *
535 * @returns nothing.
536 * @param pDevIns Pointer to the PDM device instance data.
537 * @param pThis Pointer to the shared TPM device.
538 * @param pLoc The locality state.
539 * @param uSts The interrupt status bit to set.
540 */
541static void tpmLocSetIntSts(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc, uint32_t uSts)
542{
543 pLoc->uRegIntSts |= uSts;
544 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
545}
546
547
548/**
549 * Selects the next locality which has requested access.
550 *
551 * @returns nothing.
552 * @param pDevIns Pointer to the PDM device instance data.
553 * @param pThis Pointer to the shared TPM device.
554 */
555static void tpmLocSelectNext(PPDMDEVINS pDevIns, PDEVTPM pThis)
556{
557 Assert(pThis->bmLocReqAcc);
558 Assert(pThis->bLoc == TPM_NO_LOCALITY_SELECTED);
559 pThis->bLoc = (uint8_t)ASMBitLastSetU32(pThis->bmLocReqAcc) - 1; /* Select one with highest priority. */
560
561 tpmLocSetIntSts(pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_CRB_LOCALITY_REG_INT_STS_LOC_CHANGED);
562}
563
564
565/**
566 * Returns the given locality being accessed from the given TPM MMIO offset.
567 *
568 * @returns Locality number.
569 * @param off The offset into the TPM MMIO region.
570 */
571DECLINLINE(uint8_t) tpmGetLocalityFromOffset(RTGCPHYS off)
572{
573 return off / TPM_LOCALITY_MMIO_SIZE;
574}
575
576
577/**
578 * Returns the given register of a particular locality being accessed from the given TPM MMIO offset.
579 *
580 * @returns Register index being accessed.
581 * @param off The offset into the TPM MMIO region.
582 */
583DECLINLINE(uint32_t) tpmGetRegisterFromOffset(RTGCPHYS off)
584{
585 return off % TPM_LOCALITY_MMIO_SIZE;
586}
587
588
589/**
590 * Read from a FIFO interface register.
591 *
592 * @returns VBox strict status code.
593 * @param pDevIns Pointer to the PDM device instance data.
594 * @param pThis Pointer to the shared TPM device.
595 * @param pLoc The locality state being read from.
596 * @param bLoc The locality index.
597 * @param uReg The register offset being accessed.
598 * @param pu64 Where to store the read data.
599 */
600static VBOXSTRICTRC tpmMmioFifoRead(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
601 uint8_t bLoc, uint32_t uReg, uint64_t *pu64)
602{
603 RT_NOREF(pDevIns, pThis, pLoc, bLoc, uReg, pu64);
604 VBOXSTRICTRC rc = VINF_SUCCESS;
605
606#if 0
607 uint64_t u64;
608 switch (uReg)
609 {
610 case TPM_FIFO_LOCALITY_REG_ACCESS:
611 u64 = 0;
612 break;
613 case TPM_FIFO_LOCALITY_REG_INT_ENABLE:
614 u64 = pLoc->uRegIntEn;
615 break;
616 case TPM_FIFO_LOCALITY_REG_INT_VEC:
617 u64 = pThis->uIrq;
618 break;
619 case TPM_FIFO_LOCALITY_REG_INT_STS:
620 u64 = pLoc->uRegIntSts;
621 break;
622 case TPM_FIFO_LOCALITY_REG_IF_CAP:
623 u64 = TPM_FIFO_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL
624 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_STS_VALID
625 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE
626 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_LOW
627 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_CMD_RDY
628 | TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B)
629 | TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3); /** @todo Make some of them configurable? */
630 break;
631 case TPM_FIFO_LOCALITY_REG_STS:
632 if (bLoc != pThis->bLoc)
633 {
634 u64 = UINT64_MAX;
635 break;
636 }
637 /** @todo */
638 break;
639 case TPM_FIFO_LOCALITY_REG_DATA_FIFO:
640 //case TPM_FIFO_LOCALITY_REG_DATA_XFIFO:
641 /** @todo */
642 break;
643 case TPM_FIFO_LOCALITY_REG_DID_VID:
644 u64 = RT_H2BE_U32(RT_MAKE_U32(pThis->uVenId, pThis->uDevId));
645 break;
646 case TPM_FIFO_LOCALITY_REG_RID:
647 u64 = pThis->bRevId;
648 break;
649 default: /* Return ~0. */
650 u64 = UINT64_MAX;
651 break;
652 }
653
654 *pu64 = u64;
655#endif
656
657 return rc;
658}
659
660
661/**
662 * Read to a FIFO interface register.
663 *
664 * @returns VBox strict status code.
665 * @param pDevIns Pointer to the PDM device instance data.
666 * @param pThis Pointer to the shared TPM device.
667 * @param pLoc The locality state being written to.
668 * @param bLoc The locality index.
669 * @param uReg The register offset being accessed.
670 * @param u64 The value to write.
671 */
672static VBOXSTRICTRC tpmMmioFifoWrite(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
673 uint8_t bLoc, uint32_t uReg, uint64_t u64)
674{
675 RT_NOREF(pDevIns, pThis, pLoc, bLoc, uReg, u64);
676
677 VBOXSTRICTRC rc = VINF_SUCCESS;
678#if 0
679 uint32_t u32 = (uint32_t)u64;
680
681 switch (uReg)
682 {
683 case TPM_FIFO_LOCALITY_REG_ACCESS:
684 u32 &= TPM_FIFO_LOCALITY_REG_ACCESS_WR_MASK;
685 /*
686 * Chapter 5.6.11, 2 states that writing to this register with more than one
687 * bit set to '1' is vendor specific, we decide to ignore such writes to make the logic
688 * below simpler.
689 */
690 if (!RT_IS_POWER_OF_TWO(u32))
691 break;
692 /** @todo */
693 break;
694 case TPM_FIFO_LOCALITY_REG_INT_ENABLE:
695 if (bLoc != pThis->bLoc)
696 break;
697 /** @todo */
698 break;
699 case TPM_FIFO_LOCALITY_REG_INT_STS:
700 if (bLoc != pThis->bLoc)
701 break;
702 pLoc->uRegSts &= ~(u32 & TPM_FIFO_LOCALITY_REG_INT_STS_WR_MASK);
703 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
704 break;
705 case TPM_FIFO_LOCALITY_REG_STS:
706 /*
707 * Writes are ignored completely if the locality being accessed is not the
708 * current active one or if the value has multiple bits set (not a power of two),
709 * see chapter 5.6.12.1.
710 */
711 if ( bLoc != pThis->bLoc
712 || !RT_IS_POWER_OF_TWO(u64))
713 break;
714 /** @todo */
715 break;
716 case TPM_FIFO_LOCALITY_REG_DATA_FIFO:
717 case TPM_FIFO_LOCALITY_REG_DATA_XFIFO:
718 if (bLoc != pThis->bLoc)
719 break;
720 /** @todo */
721 break;
722 case TPM_FIFO_LOCALITY_REG_INT_VEC:
723 case TPM_FIFO_LOCALITY_REG_IF_CAP:
724 case TPM_FIFO_LOCALITY_REG_DID_VID:
725 case TPM_FIFO_LOCALITY_REG_RID:
726 default: /* Ignore. */
727 break;
728 }
729#endif
730 return rc;
731}
732
733
734/**
735 * Read from a CRB interface register.
736 *
737 * @returns VBox strict status code.
738 * @param pDevIns Pointer to the PDM device instance data.
739 * @param pThis Pointer to the shared TPM device.
740 * @param pLoc The locality state being read from.
741 * @param bLoc The locality index.
742 * @param uReg The register offset being accessed.
743 * @param pu64 Where to store the read data.
744 * @param cb Size of the read in bytes.
745 */
746static VBOXSTRICTRC tpmMmioCrbRead(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
747 uint8_t bLoc, uint32_t uReg, uint64_t *pu64, size_t cb)
748{
749 RT_NOREF(pDevIns);
750
751 /* Special path for the data buffer. */
752 if ( uReg >= TPM_CRB_LOCALITY_REG_DATA_BUFFER
753 && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE
754 && bLoc == pThis->bLoc
755 && pThis->enmState == DEVTPMSTATE_CMD_COMPLETION)
756 {
757 memcpy(pu64, &pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], cb);
758 return VINF_SUCCESS;
759 }
760
761 VBOXSTRICTRC rc = VINF_SUCCESS;
762 uint64_t u64 = UINT64_MAX;
763 switch (uReg)
764 {
765 case TPM_CRB_LOCALITY_REG_STATE:
766 u64 = TPM_CRB_LOCALITY_REG_STATE_VALID
767 | ( pThis->bLoc != TPM_NO_LOCALITY_SELECTED
768 ? TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(pThis->bLoc) | TPM_CRB_LOCALITY_REG_STATE_LOC_ASSIGNED
769 : TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(0));
770 break;
771 case TPM_CRB_LOCALITY_REG_STS:
772 u64 = pThis->bLoc == bLoc
773 ? TPM_CRB_LOCALITY_REG_STS_GRANTED
774 : 0;
775 u64 |= pThis->bmLocSeizedAcc & RT_BIT_32(bLoc)
776 ? TPM_CRB_LOCALITY_REG_STS_SEIZED
777 : 0;
778 break;
779 case TPM_CRB_LOCALITY_REG_INTF_ID:
780 u64 = TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_CRB)
781 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_CRB)
782 | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_LOCALITY
783 | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B)
784 | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB
785 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_GET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_CRB)
786 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_LOCK
787 | TPM_CRB_LOCALITY_REG_INTF_ID_RID_SET(pThis->bRevId)
788 | TPM_CRB_LOCALITY_REG_INTF_ID_VID_SET(pThis->uVenId)
789 | TPM_CRB_LOCALITY_REG_INTF_ID_DID_SET(pThis->uDevId);
790 break;
791 case TPM_CRB_LOCALITY_REG_CTRL_REQ:
792 if (bLoc != pThis->bLoc)
793 break;
794 /*
795 * Command ready and go idle are always 0 upon read
796 * as we don't need time to transition to this state
797 * when written by the guest.
798 */
799 u64 = 0;
800 break;
801 case TPM_CRB_LOCALITY_REG_CTRL_STS:
802 if (bLoc != pThis->bLoc)
803 break;
804 if (pThis->enmState == DEVTPMSTATE_FATAL_ERROR)
805 u64 = TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_FATAL_ERR;
806 else if (pThis->enmState == DEVTPMSTATE_IDLE)
807 u64 = TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_IDLE;
808 else
809 u64 = 0;
810 break;
811 case TPM_CRB_LOCALITY_REG_CTRL_CANCEL:
812 if (bLoc != pThis->bLoc)
813 break;
814 if (pThis->enmState == DEVTPMSTATE_CMD_CANCEL)
815 u64 = 0x1;
816 else
817 u64 = 0;
818 break;
819 case TPM_CRB_LOCALITY_REG_CTRL_START:
820 if (bLoc != pThis->bLoc)
821 break;
822 if (pThis->enmState == DEVTPMSTATE_CMD_EXEC)
823 u64 = 0x1;
824 else
825 u64 = 0;
826 break;
827 case TPM_CRB_LOCALITY_REG_INT_ENABLE:
828 u64 = pLoc->uRegIntEn;
829 break;
830 case TPM_CRB_LOCALITY_REG_INT_STS:
831 u64 = pLoc->uRegIntSts;
832 break;
833 case TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR:
834 u64 = pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER;
835 break;
836 case TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR:
837 u64 = (pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER) >> 32;
838 break;
839 case TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ:
840 case TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ:
841 u64 = TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE;
842 break;
843 case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR:
844 u64 = pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER;
845 break;
846 case TPM_CRB_LOCALITY_REG_CTRL: /* Writeonly */
847 u64 = 0;
848 break;
849 case TPM_CRB_LOCALITY_REG_CTRL_EXT:
850 default:
851 break; /* Return ~0 */
852 }
853
854 *pu64 = u64;
855 return rc;
856}
857
858
859/**
860 * Read to a CRB interface register.
861 *
862 * @returns VBox strict status code.
863 * @param pDevIns Pointer to the PDM device instance data.
864 * @param pThis Pointer to the shared TPM device.
865 * @param pLoc The locality state being written to.
866 * @param bLoc The locality index.
867 * @param uReg The register offset being accessed.
868 * @param u64 The value to write.
869 * @param cb Size of the write in bytes.
870 */
871static VBOXSTRICTRC tpmMmioCrbWrite(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
872 uint8_t bLoc, uint32_t uReg, uint64_t u64, size_t cb)
873{
874 VBOXSTRICTRC rc = VINF_SUCCESS;
875 uint32_t u32 = (uint32_t)u64;
876
877 /* Special path for the data buffer. */
878 if ( uReg >= TPM_CRB_LOCALITY_REG_DATA_BUFFER
879 && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE
880 && bLoc == pThis->bLoc
881 && ( pThis->enmState == DEVTPMSTATE_READY
882 || pThis->enmState == DEVTPMSTATE_CMD_RECEPTION))
883 {
884 pThis->enmState = DEVTPMSTATE_CMD_RECEPTION;
885 memcpy(&pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], &u64, cb);
886 return VINF_SUCCESS;
887 }
888
889 switch (uReg)
890 {
891 case TPM_CRB_LOCALITY_REG_CTRL:
892 {
893 /* See chapter 6.5.3.2.2.1. */
894#if 0
895 if (u64 & TPM_CRB_LOCALITY_REG_CTRL_RST_ESTABLISHMENT)
896 /** @todo */;
897#endif
898
899 /*
900 * The following three checks should be mutually exclusive as the writer shouldn't
901 * request, relinquish and seize access in the same write.
902 */
903 /* Seize access only if this locality has a higher priority than the currently selected one. */
904 if ( (u64 & TPM_CRB_LOCALITY_REG_CTRL_SEIZE)
905 && pThis->bLoc != TPM_NO_LOCALITY_SELECTED
906 && bLoc > pThis->bLoc)
907 {
908 pThis->bmLocSeizedAcc |= RT_BIT_32(pThis->bLoc);
909 /** @todo Abort command. */
910 pThis->bLoc = bLoc;
911 }
912
913 if ( (u64 & TPM_CRB_LOCALITY_REG_CTRL_REQ_ACCESS)
914 && !(pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
915 {
916 pThis->bmLocReqAcc |= RT_BIT_32(bLoc);
917 if (pThis->bLoc == TPM_NO_LOCALITY_SELECTED)
918 {
919 pThis->bLoc = bLoc; /* Doesn't fire an interrupt. */
920 pThis->bmLocSeizedAcc &= ~RT_BIT_32(bLoc);
921 }
922 }
923
924 if ( (u64 & TPM_CRB_LOCALITY_REG_CTRL_RELINQUISH)
925 && (pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
926 {
927 pThis->bmLocReqAcc &= ~RT_BIT_32(bLoc);
928 if (pThis->bLoc == bLoc)
929 {
930 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
931 if (pThis->bmLocReqAcc)
932 tpmLocSelectNext(pDevIns, pThis); /* Select the next locality. */
933 }
934 }
935 break;
936 }
937 case TPM_CRB_LOCALITY_REG_CTRL_REQ:
938 if ( bLoc != pThis->bLoc
939 || !RT_IS_POWER_OF_TWO(u32)) /* Ignore if multiple bits are set. */
940 break;
941 if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_CMD_RDY)
942 && ( pThis->enmState == DEVTPMSTATE_IDLE
943 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
944 {
945 pThis->enmState = DEVTPMSTATE_READY;
946 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_CMD_RDY);
947 }
948 else if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_IDLE)
949 && pThis->enmState != DEVTPMSTATE_CMD_EXEC)
950 {
951 /* Invalidate the command/response buffer. */
952 RT_ZERO(pThis->abCmdResp);
953 pThis->enmState = DEVTPMSTATE_IDLE;
954 }
955 break;
956 case TPM_CRB_LOCALITY_REG_CTRL_CANCEL:
957 if (bLoc != pThis->bLoc)
958 break;
959 if ( pThis->enmState == DEVTPMSTATE_CMD_EXEC
960 && u32 == 0x1)
961 {
962 pThis->enmState == DEVTPMSTATE_CMD_CANCEL;
963 /** @todo Cancel. */
964 pThis->enmState == DEVTPMSTATE_CMD_COMPLETION;
965 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_START);
966 }
967 break;
968 case TPM_CRB_LOCALITY_REG_CTRL_START:
969 if (bLoc != pThis->bLoc)
970 break;
971 if ( pThis->enmState == DEVTPMSTATE_CMD_RECEPTION
972 && u32 == 0x1)
973 {
974 pThis->enmState = DEVTPMSTATE_CMD_EXEC;
975 rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hTpmCmdTask);
976 }
977 break;
978 case TPM_CRB_LOCALITY_REG_INT_ENABLE:
979 pLoc->uRegIntEn = u32;
980 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
981 break;
982 case TPM_CRB_LOCALITY_REG_INT_STS:
983 pLoc->uRegIntSts &= ~u32;
984 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
985 break;
986 case TPM_CRB_LOCALITY_REG_CTRL_EXT: /* Not implemented. */
987 case TPM_CRB_LOCALITY_REG_STATE: /* Readonly */
988 case TPM_CRB_LOCALITY_REG_INTF_ID:
989 case TPM_CRB_LOCALITY_REG_CTRL_STS:
990 case TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR:
991 case TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR:
992 case TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ:
993 case TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ:
994 case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR:
995 default: /* Ignore. */
996 break;
997 }
998
999 return rc;
1000}
1001
1002
1003/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
1004
1005/**
1006 * @callback_method_impl{FNIOMMMIONEWREAD}
1007 */
1008static DECLCALLBACK(VBOXSTRICTRC) tpmMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1009{
1010 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1011 RT_NOREF(pvUser);
1012
1013 Assert(!(off & (cb - 1)));
1014
1015 VBOXSTRICTRC rc = VINF_SUCCESS;
1016 uint32_t uReg = tpmGetRegisterFromOffset(off);
1017 uint8_t bLoc = tpmGetLocalityFromOffset(off);
1018 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
1019
1020 uint64_t u64;
1021 if (pThis->fCrb)
1022 rc = tpmMmioCrbRead(pDevIns, pThis, pLoc, bLoc, uReg, &u64, cb);
1023 else
1024 rc = tpmMmioFifoRead(pDevIns, pThis, pLoc, bLoc, uReg, &u64);
1025
1026 LogFlowFunc((": %RGp %#x %#llx\n", off, cb, u64));
1027
1028 if (rc == VINF_SUCCESS)
1029 {
1030 switch (cb)
1031 {
1032 case 1: *(uint8_t *)pv = (uint8_t)u64; break;
1033 case 2: *(uint16_t *)pv = (uint16_t)u64; break;
1034 case 4: *(uint32_t *)pv = (uint32_t)u64; break;
1035 case 8: *(uint64_t *)pv = u64; break;
1036 default: AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR);
1037 }
1038 }
1039
1040 return rc;
1041}
1042
1043
1044/**
1045 * @callback_method_impl{FNIOMMMIONEWWRITE}
1046 */
1047static DECLCALLBACK(VBOXSTRICTRC) tpmMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1048{
1049 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1050 RT_NOREF(pvUser);
1051
1052 Assert(!(off & (cb - 1)));
1053
1054 uint64_t u64;
1055 switch (cb)
1056 {
1057 case 1: u64 = *(const uint8_t *)pv; break;
1058 case 2: u64 = *(const uint16_t *)pv; break;
1059 case 4: u64 = *(const uint32_t *)pv; break;
1060 case 8: u64 = *(const uint64_t *)pv; break;
1061 default: AssertFailedReturn(VERR_INTERNAL_ERROR);
1062 }
1063
1064 LogFlowFunc((": %RGp %#llx\n", off, u64));
1065
1066 VBOXSTRICTRC rc = VINF_SUCCESS;
1067 uint32_t uReg = tpmGetRegisterFromOffset(off);
1068 uint8_t bLoc = tpmGetLocalityFromOffset(off);
1069 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
1070
1071 if (pThis->fCrb)
1072 rc = tpmMmioCrbWrite(pDevIns, pThis, pLoc, bLoc, uReg, u64, cb);
1073 else
1074 rc = tpmMmioFifoWrite(pDevIns, pThis, pLoc, bLoc, uReg, u64);
1075
1076 return rc;
1077}
1078
1079
1080#ifdef IN_RING3
1081
1082/**
1083 * @callback_method_impl{FNPDMTASKDEV, Execute a command in ring-3}
1084 */
1085static DECLCALLBACK(void) tpmR3CmdExecWorker(PPDMDEVINS pDevIns, void *pvUser)
1086{
1087 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1088 PDEVTPMR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMR3);
1089 RT_NOREF(pvUser);
1090 LogFlowFunc(("\n"));
1091
1092 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1093 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1094
1095 if (pThisCC->pDrvTpm)
1096 {
1097 size_t cbCmd = RTTpmReqGetSz((PCTPMREQHDR)&pThis->abCmdResp[0]);
1098 int rc = pThisCC->pDrvTpm->pfnCmdExec(pThisCC->pDrvTpm, pThis->bLoc, &pThis->abCmdResp[0], cbCmd,
1099 &pThis->abCmdResp[0], sizeof(pThis->abCmdResp));
1100 if (RT_SUCCESS(rc))
1101 {
1102 pThis->enmState = DEVTPMSTATE_CMD_COMPLETION;
1103 tpmLocSetIntSts(pThisCC->pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_CRB_LOCALITY_REG_INT_STS_START);
1104 }
1105 else
1106 {
1107 /* Set fatal error. */
1108 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1109 }
1110 }
1111
1112 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1113}
1114
1115
1116/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
1117
1118/**
1119 * @callback_method_impl{FNSSMDEVLIVEEXEC}
1120 */
1121static DECLCALLBACK(int) tpmR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1122{
1123 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1124 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1125 RT_NOREF(uPass);
1126
1127 pHlp->pfnSSMPutU8(pSSM, pThis->uIrq);
1128 return VINF_SSM_DONT_CALL_AGAIN;
1129}
1130
1131
1132/**
1133 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1134 */
1135static DECLCALLBACK(int) tpmR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1136{
1137 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1138 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1139
1140 pHlp->pfnSSMPutU8(pSSM, pThis->uIrq);
1141
1142 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1143}
1144
1145
1146/**
1147 * @callback_method_impl{FNSSMDEVLOADEXEC}
1148 */
1149static DECLCALLBACK(int) tpmR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1150{
1151 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1152 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1153 uint8_t bIrq;
1154 int rc;
1155
1156 AssertMsgReturn(uVersion >= TPM_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1157 pHlp->pfnSSMGetU8( pSSM, &bIrq);
1158 if (uPass == SSM_PASS_FINAL)
1159 {
1160 /* The marker. */
1161 uint32_t u32;
1162 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
1163 AssertRCReturn(rc, rc);
1164 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1165 }
1166
1167 /*
1168 * Check the config.
1169 */
1170 if (pThis->uIrq != bIrq)
1171 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1172 N_("Config mismatch - saved IRQ=%#x; configured IRQ=%#x"),
1173 bIrq, pThis->uIrq);
1174
1175 return VINF_SUCCESS;
1176}
1177
1178
1179/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
1180
1181/**
1182 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1183 */
1184static DECLCALLBACK(void *) tpmR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1185{
1186 PDEVTPMCC pThisCC = RT_FROM_MEMBER(pInterface, DEVTPMCC, IBase);
1187 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
1188 //PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMPORT, &pThisCC->ITpmPort);
1189 return NULL;
1190}
1191
1192
1193/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
1194
1195/**
1196 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
1197 */
1198static DECLCALLBACK(void) tpmR3PowerOff(PPDMDEVINS pDevIns)
1199{
1200 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1201
1202 if (pThisCC->pDrvTpm)
1203 {
1204 int rc = pThisCC->pDrvTpm->pfnShutdown(pThisCC->pDrvTpm);
1205 AssertRC(rc);
1206 }
1207}
1208
1209
1210/**
1211 * @interface_method_impl{PDMDEVREG,pfnReset}
1212 */
1213static DECLCALLBACK(void) tpmR3Reset(PPDMDEVINS pDevIns)
1214{
1215 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1216
1217 pThis->enmState = DEVTPMSTATE_IDLE;
1218 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
1219 RT_ZERO(pThis->abCmdResp);
1220
1221 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aLoc); i++)
1222 {
1223 PDEVTPMLOCALITY pLoc = &pThis->aLoc[i];
1224 pLoc->uRegIntEn = 0;
1225 pLoc->uRegIntSts = 0;
1226 }
1227}
1228
1229
1230/**
1231 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1232 */
1233static DECLCALLBACK(int) tpmR3Destruct(PPDMDEVINS pDevIns)
1234{
1235 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1236 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1237
1238 /** @todo */
1239 RT_NOREF(pThis);
1240 return VINF_SUCCESS;
1241}
1242
1243
1244/**
1245 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1246 */
1247static DECLCALLBACK(int) tpmR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1248{
1249 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1250 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1251 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1252 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1253 int rc;
1254
1255 RT_NOREF(iInstance);
1256
1257 pThis->hTpmCmdTask = NIL_PDMTASKHANDLE;
1258
1259 pThisCC->pDevIns = pDevIns;
1260
1261 /* IBase */
1262 pThisCC->IBase.pfnQueryInterface = tpmR3QueryInterface;
1263
1264 /*
1265 * Validate and read the configuration.
1266 */
1267 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq"
1268 "|MmioBase"
1269 "|VendorId"
1270 "|DeviceId"
1271 "|RevisionId"
1272 "|Crb",
1273 "");
1274
1275 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Irq", &pThis->uIrq, 10);
1276 if (RT_FAILURE(rc))
1277 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
1278
1279 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioBase", &pThis->GCPhysMmio, TPM_MMIO_BASE_DEFAULT);
1280 if (RT_FAILURE(rc))
1281 return PDMDEV_SET_ERROR(pDevIns, rc,
1282 N_("Configuration error: Failed to get the \"MmioBase\" value"));
1283
1284 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "VendorId", &pThis->uDevId, TPM_VID_DEFAULT);
1285 if (RT_FAILURE(rc))
1286 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"VendorId\" value"));
1287
1288 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "DeviceId", &pThis->uDevId, TPM_DID_DEFAULT);
1289 if (RT_FAILURE(rc))
1290 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"DeviceId\" value"));
1291
1292 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "RevisionId", &pThis->bRevId, TPM_RID_DEFAULT);
1293 if (RT_FAILURE(rc))
1294 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"RevisionId\" value"));
1295
1296 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Crb", &pThis->fCrb, true);
1297 if (RT_FAILURE(rc))
1298 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Crb\" value"));
1299
1300 /*
1301 * Register the MMIO range, PDM API requests page aligned
1302 * addresses and sizes.
1303 */
1304 rc = PDMDevHlpMmioCreateAndMap(pDevIns, pThis->GCPhysMmio, TPM_MMIO_SIZE, tpmMmioWrite, tpmMmioRead,
1305 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
1306 "TPM MMIO", &pThis->hMmio);
1307 AssertRCReturn(rc, rc);
1308
1309 /*
1310 * Attach any TPM driver below.
1311 */
1312 rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "TPM");
1313 if (RT_SUCCESS(rc))
1314 {
1315 pThisCC->pDrvTpm = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMITPMCONNECTOR);
1316 AssertLogRelMsgReturn(pThisCC->pDrvTpm, ("TPM#%d: Driver is missing the TPM interface.\n", iInstance), VERR_PDM_MISSING_INTERFACE);
1317
1318 /* Startup the TPM here instead of in the power on callback as we can convey errors here to the upper layer. */
1319 rc = pThisCC->pDrvTpm->pfnStartup(pThisCC->pDrvTpm, sizeof(pThis->abCmdResp));
1320 if (RT_FAILURE(rc))
1321 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to startup the TPM"));
1322 }
1323 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1324 {
1325 pThisCC->pDrvBase = NULL;
1326 pThisCC->pDrvTpm = NULL;
1327 LogRel(("TPM#%d: no unit\n", iInstance));
1328 }
1329 else
1330 AssertLogRelMsgRCReturn(rc, ("TPM#%d: Failed to attach to TPM driver. rc=%Rrc\n", iInstance, rc), rc);
1331
1332 /* Create task for executing requests in ring-3. */
1333 rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "TPMCmdWrk",
1334 tpmR3CmdExecWorker, NULL /*pvUser*/, &pThis->hTpmCmdTask);
1335 AssertRCReturn(rc,rc);
1336
1337 /*
1338 * Saved state.
1339 */
1340 rc = PDMDevHlpSSMRegister3(pDevIns, TPM_SAVED_STATE_VERSION, sizeof(*pThis),
1341 tpmR3LiveExec, tpmR3SaveExec, tpmR3LoadExec);
1342 AssertRCReturn(rc, rc);
1343
1344 tpmR3Reset(pDevIns);
1345 return VINF_SUCCESS;
1346}
1347
1348#else /* !IN_RING3 */
1349
1350/**
1351 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1352 */
1353static DECLCALLBACK(int) tpmRZConstruct(PPDMDEVINS pDevIns)
1354{
1355 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1356 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1357 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1358
1359 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, tpmMmioWrite, tpmMmioRead, NULL /*pvUser*/);
1360 AssertRCReturn(rc, rc);
1361
1362 return VINF_SUCCESS;
1363}
1364
1365#endif /* !IN_RING3 */
1366
1367/**
1368 * The device registration structure.
1369 */
1370const PDMDEVREG g_DeviceTpm =
1371{
1372 /* .u32Version = */ PDM_DEVREG_VERSION,
1373 /* .uReserved0 = */ 0,
1374 /* .szName = */ "tpm",
1375 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1376 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
1377 /* .cMaxInstances = */ 1,
1378 /* .uSharedVersion = */ 42,
1379 /* .cbInstanceShared = */ sizeof(DEVTPM),
1380 /* .cbInstanceCC = */ sizeof(DEVTPMCC),
1381 /* .cbInstanceRC = */ sizeof(DEVTPMRC),
1382 /* .cMaxPciDevices = */ 0,
1383 /* .cMaxMsixVectors = */ 0,
1384 /* .pszDescription = */ "Trusted Platform Module",
1385#if defined(IN_RING3)
1386 /* .pszRCMod = */ "VBoxDDRC.rc",
1387 /* .pszR0Mod = */ "VBoxDDR0.r0",
1388 /* .pfnConstruct = */ tpmR3Construct,
1389 /* .pfnDestruct = */ tpmR3Destruct,
1390 /* .pfnRelocate = */ NULL,
1391 /* .pfnMemSetup = */ NULL,
1392 /* .pfnPowerOn = */ NULL,
1393 /* .pfnReset = */ tpmR3Reset,
1394 /* .pfnSuspend = */ NULL,
1395 /* .pfnResume = */ NULL,
1396 /* .pfnAttach = */ NULL,
1397 /* .pfnDetach = */ NULL,
1398 /* .pfnQueryInterface = */ NULL,
1399 /* .pfnInitComplete = */ NULL,
1400 /* .pfnPowerOff = */ tpmR3PowerOff,
1401 /* .pfnSoftReset = */ NULL,
1402 /* .pfnReserved0 = */ NULL,
1403 /* .pfnReserved1 = */ NULL,
1404 /* .pfnReserved2 = */ NULL,
1405 /* .pfnReserved3 = */ NULL,
1406 /* .pfnReserved4 = */ NULL,
1407 /* .pfnReserved5 = */ NULL,
1408 /* .pfnReserved6 = */ NULL,
1409 /* .pfnReserved7 = */ NULL,
1410#elif defined(IN_RING0)
1411 /* .pfnEarlyConstruct = */ NULL,
1412 /* .pfnConstruct = */ tpmRZConstruct,
1413 /* .pfnDestruct = */ NULL,
1414 /* .pfnFinalDestruct = */ NULL,
1415 /* .pfnRequest = */ NULL,
1416 /* .pfnReserved0 = */ NULL,
1417 /* .pfnReserved1 = */ NULL,
1418 /* .pfnReserved2 = */ NULL,
1419 /* .pfnReserved3 = */ NULL,
1420 /* .pfnReserved4 = */ NULL,
1421 /* .pfnReserved5 = */ NULL,
1422 /* .pfnReserved6 = */ NULL,
1423 /* .pfnReserved7 = */ NULL,
1424#elif defined(IN_RC)
1425 /* .pfnConstruct = */ tpmRZConstruct,
1426 /* .pfnReserved0 = */ NULL,
1427 /* .pfnReserved1 = */ NULL,
1428 /* .pfnReserved2 = */ NULL,
1429 /* .pfnReserved3 = */ NULL,
1430 /* .pfnReserved4 = */ NULL,
1431 /* .pfnReserved5 = */ NULL,
1432 /* .pfnReserved6 = */ NULL,
1433 /* .pfnReserved7 = */ NULL,
1434#else
1435# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1436#endif
1437 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1438};
1439
1440#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1441
Note: See TracBrowser for help on using the repository browser.

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