VirtualBox

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

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

Devices/Security/DevTpm: Another addendum for r161223, need to set the FIFO capability bit in order for UEFI to properly detect the TPM

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.6 KB
Line 
1/* $Id: DevTpm.cpp 102998 2024-01-23 10:37:47Z 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-2023 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * SPDX-License-Identifier: GPL-3.0-only
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#define LOG_GROUP LOG_GROUP_DEV_TPM
36#include <VBox/vmm/pdmdev.h>
37#include <VBox/vmm/pdmtpmifs.h>
38#include <iprt/assert.h>
39#include <iprt/string.h>
40#include <iprt/uuid.h>
41
42#include <iprt/formats/tpm.h>
43
44#include "VBoxDD.h"
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50
51/** The TPM saved state version. */
52#define TPM_SAVED_STATE_VERSION 1
53
54/** Default vendor ID. */
55#define TPM_VID_DEFAULT 0x1014
56/** Default device ID. */
57#define TPM_DID_DEFAULT 0x0001
58/** Default revision ID. */
59#define TPM_RID_DEFAULT 0x01
60/** Maximum size of the data buffer in bytes. */
61#define TPM_DATA_BUFFER_SIZE_MAX 3968
62
63/** The TPM MMIO base default as defined in chapter 5.2. */
64#define TPM_MMIO_BASE_DEFAULT 0xfed40000
65/** The size of the TPM MMIO area. */
66#define TPM_MMIO_SIZE 0x5000
67
68/** Number of localities as mandated by the TPM spec. */
69#define TPM_LOCALITY_COUNT 5
70/** Size of each locality in the TPM MMIO area (chapter 6.5.2).*/
71#define TPM_LOCALITY_MMIO_SIZE 0x1000
72
73/** @name TPM locality register related defines for the FIFO interface.
74 * @{ */
75/** Ownership management for a particular locality. */
76#define TPM_FIFO_LOCALITY_REG_ACCESS 0x00
77/** Indicates whether a dynamic OS has been established on this platform before.. */
78# define TPM_FIFO_LOCALITY_REG_ACCESS_ESTABLISHMENT RT_BIT(0)
79/** On reads indicates whether the locality requests use of the TPM (1) or not or is already active locality (0),
80 * writing a 1 requests the locality to be granted getting the active locality.. */
81# define TPM_FIFO_LOCALITY_REG_ACCESS_REQUEST_USE RT_BIT(1)
82/** Indicates whether another locality is requesting usage of the TPM. */
83# define TPM_FIFO_LOCALITY_REG_ACCESS_PENDING_REQUEST RT_BIT(2)
84/** Writing a 1 forces the TPM to give control to the locality if it has a higher priority. */
85# define TPM_FIFO_LOCALITY_REG_ACCESS_SEIZE RT_BIT(3)
86/** On reads indicates whether this locality has been seized by a higher locality (1) or not (0), writing a 1 clears this bit. */
87# define TPM_FIFO_LOCALITY_REG_ACCESS_BEEN_SEIZED RT_BIT(4)
88/** On reads indicates whether this locality is active (1) or not (0), writing a 1 relinquishes control for this locality. */
89# define TPM_FIFO_LOCALITY_REG_ACCESS_ACTIVE RT_BIT(5)
90/** Set bit indicates whether all other bits in this register have valid data. */
91# define TPM_FIFO_LOCALITY_REG_ACCESS_VALID RT_BIT(7)
92/** Writable mask. */
93# define TPM_FIFO_LOCALITY_REG_ACCESS_WR_MASK 0x3a
94
95/** Interrupt enable register. */
96#define TPM_FIFO_LOCALITY_REG_INT_ENABLE 0x08
97/** Data available interrupt enable bit. */
98# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_DATA_AVAIL RT_BIT_32(0)
99/** Status valid interrupt enable bit. */
100# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_STS_VALID RT_BIT_32(1)
101/** Locality change interrupt enable bit. */
102# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_LOCALITY_CHANGE RT_BIT_32(2)
103/** Interrupt polarity configuration. */
104# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_MASK 0x18
105# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_SHIFT 3
106# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_INT_POLARITY_SHIFT)
107# 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)
108/** High level interrupt trigger. */
109# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_HIGH 0
110/** Low level interrupt trigger. */
111# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_LOW 1
112/** Rising edge interrupt trigger. */
113# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_RISING 2
114/** Falling edge interrupt trigger. */
115# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_FALLING 3
116/** Command ready enable bit. */
117# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_CMD_RDY RT_BIT_32(7)
118/** Global interrupt enable/disable bit. */
119# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_GLOBAL RT_BIT_32(31)
120
121/** Configured interrupt vector register. */
122#define TPM_FIFO_LOCALITY_REG_INT_VEC 0x0c
123
124/** Interrupt status register. */
125#define TPM_FIFO_LOCALITY_REG_INT_STS 0x10
126/** Data available interrupt occured bit, writing a 1 clears the bit. */
127# define TPM_FIFO_LOCALITY_REG_INT_STS_DATA_AVAIL RT_BIT_32(0)
128/** Status valid interrupt occured bit, writing a 1 clears the bit. */
129# define TPM_FIFO_LOCALITY_REG_INT_STS_STS_VALID RT_BIT_32(1)
130/** Locality change interrupt occured bit, writing a 1 clears the bit. */
131# define TPM_FIFO_LOCALITY_REG_INT_STS_LOCALITY_CHANGE RT_BIT_32(2)
132/** Command ready occured bit, writing a 1 clears the bit. */
133# define TPM_FIFO_LOCALITY_REG_INT_STS_CMD_RDY RT_BIT_32(7)
134/** Writable mask. */
135# define TPM_FIFO_LOCALITY_REG_INT_STS_WR_MASK UINT32_C(0x87)
136
137/** Interfacce capabilities register. */
138#define TPM_FIFO_LOCALITY_REG_IF_CAP 0x14
139/** Flag whether the TPM supports the data avilable interrupt. */
140# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL RT_BIT(0)
141/** Flag whether the TPM supports the status valid interrupt. */
142# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_STS_VALID RT_BIT(1)
143/** Flag whether the TPM supports the data avilable interrupt. */
144# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE RT_BIT(2)
145/** Flag whether the TPM supports high level interrupts. */
146# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_HIGH RT_BIT(3)
147/** Flag whether the TPM supports low level interrupts. */
148# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_LOW RT_BIT(4)
149/** Flag whether the TPM supports rising edge interrupts. */
150# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_RISING_EDGE RT_BIT(5)
151/** Flag whether the TPM supports falling edge interrupts. */
152# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_FALLING_EDGE RT_BIT(6)
153/** Flag whether the TPM supports the command ready interrupt. */
154# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_CMD_RDY RT_BIT(7)
155/** Flag whether the busrt count field is static or dynamic. */
156# define TPM_FIFO_LOCALITY_REG_IF_CAP_BURST_CNT_STATIC RT_BIT(8)
157/** Maximum transfer size support. */
158# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_MASK 0x600
159# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT 9
160# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT)
161/** Only legacy transfers supported. */
162# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_LEGACY 0x0
163/** 8B maximum transfer size. */
164# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_8B 0x1
165/** 32B maximum transfer size. */
166# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_32B 0x2
167/** 64B maximum transfer size. */
168# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B 0x3
169/** Interface version. */
170# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_MASK UINT32_C(0x70000000)
171# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT 28
172# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT)
173/** Interface 1.21 or ealier. */
174# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_21 0
175/** Interface 1.3. */
176# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3 2
177/** Interface 1.3 for TPM 2.0. */
178# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3_TPM2 3
179
180/** TPM status register. */
181#define TPM_FIFO_LOCALITY_REG_STS 0x18
182/** Writing a 1 forces the TPM to re-send the response. */
183# define TPM_FIFO_LOCALITY_REG_STS_RESPONSE_RETRY RT_BIT_32(1)
184/** Indicating whether the TPM has finished a self test. */
185# define TPM_FIFO_LOCALITY_REG_STS_SELF_TEST_DONE RT_BIT_32(2)
186/** Flag indicating whether the TPM expects more data for the command. */
187# define TPM_FIFO_LOCALITY_REG_STS_EXPECT RT_BIT_32(3)
188/** Flag indicating whether the TPM has more response data available. */
189# define TPM_FIFO_LOCALITY_REG_STS_DATA_AVAIL RT_BIT_32(4)
190/** Written by software to cause the TPM to execute a previously transfered command. */
191# define TPM_FIFO_LOCALITY_REG_STS_TPM_GO RT_BIT_32(5)
192/** On reads indicates whether the TPM is ready to receive a new command (1) or not (0),
193 * a write of 1 causes the TPM to transition to this state. */
194# define TPM_FIFO_LOCALITY_REG_STS_CMD_RDY RT_BIT_32(6)
195/** Indicates whether the Expect and data available bits are valid. */
196# define TPM_FIFO_LOCALITY_REG_STS_VALID RT_BIT_32(7)
197/** Sets the burst count. */
198# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_MASK UINT32_C(0xffff00)
199# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SHIFT UINT32_C(8)
200# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SHIFT)
201/** Cancels the active command. */
202# define TPM_FIFO_LOCALITY_REG_STS_CMD_CANCEL RT_BIT_32(24)
203/** Reset establishment bit. */
204# define TPM_FIFO_LOCALITY_REG_STS_RST_ESTABLISHMENT RT_BIT_32(25)
205/** Sets the TPM family. */
206# define TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_MASK UINT32_C(0x0c000000)
207# define TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_SHIFT UINT32_C(26)
208# define TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_SHIFT)
209# define TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_1_2 UINT32_C(0)
210# define TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_2_0 UINT32_C(1)
211
212
213/** TPM end of HASH operation signal register for locality 4. */
214#define TPM_FIFO_LOCALITY_REG_HASH_END 0x20
215/** Data FIFO read/write register. */
216#define TPM_FIFO_LOCALITY_REG_DATA_FIFO 0x24
217/** TPM start of HASH operation signal register for locality 4. */
218#define TPM_FIFO_LOCALITY_REG_HASH_START 0x28
219
220/** Locality interface ID register. */
221#define TPM_FIFO_LOCALITY_REG_INTF_ID 0x30
222/** Interface type field. */
223# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_MASK UINT32_C(0xf)
224# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_SHIFT 0
225# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_SHIFT)
226/** FIFO interface as defined in PTP for TPM 2.0 is active. */
227# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_FIFO_TPM20 0x0
228/** CRB interface is active. */
229# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_CRB 0x1
230/** FIFO interface as defined in TIS 1.3 is active. */
231# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_TIS1_3 0xf
232/** Interface type field. */
233# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_MASK UINT32_C(0xf)
234# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_SHIFT 4
235# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_SHIFT)
236/** FIFO interface for TPM 2.0 */
237# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_FIFO 0
238/** CRB interface version 0. */
239# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_CRB 1
240/** Only locality 0 is supported when clear, set if 5 localities are supported. */
241# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_LOCALITY RT_BIT(8)
242/** Maximum transfer size support. */
243# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_MASK 0x1800
244# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SHIFT 11
245# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SHIFT)
246/** Only legacy transfers supported. */
247# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_LEGACY 0x0
248/** 8B maximum transfer size. */
249# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_8B 0x1
250/** 32B maximum transfer size. */
251# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_32B 0x2
252/** 64B maximum transfer size. */
253# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B 0x3
254/** FIFO interface is supported and may be selected. */
255# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_FIFO RT_BIT(13)
256/** CRB interface is supported and may be selected. */
257# define TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_CRB RT_BIT(14)
258/** Interrupt polarity configuration. */
259# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_MASK 0x60000
260# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT 17
261# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT)
262# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_GET(a) (((a) & TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_MASK) >> TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT)
263/** Selects the FIFO interface, takes effect on next _TPM_INIT. */
264# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_FIFO 0
265/** Selects the CRB interface, takes effect on next _TPM_INIT. */
266# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_CRB 1
267/** Locks the interface selector field and prevents further changes. */
268# define TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_LOCK RT_BIT(19)
269
270
271/** Extended data FIFO read/write register. */
272#define TPM_FIFO_LOCALITY_REG_XDATA_FIFO 0x80
273/** TPM device and vendor ID. */
274#define TPM_FIFO_LOCALITY_REG_DID_VID 0xf00
275/** TPM revision ID. */
276#define TPM_FIFO_LOCALITY_REG_RID 0xf04
277/** @} */
278
279
280/** @name TPM locality register related defines for the CRB interface.
281 * @{ */
282/** Locality state register. */
283#define TPM_CRB_LOCALITY_REG_STATE 0x00
284/** Indicates whether a dynamic OS has been established on this platform before.. */
285# define TPM_CRB_LOCALITY_REG_ESTABLISHMENT RT_BIT(0)
286/** Flag whether the host has a locality assigned (1) or not (0). */
287# define TPM_CRB_LOCALITY_REG_STATE_LOC_ASSIGNED RT_BIT(1)
288/** Indicates the currently active locality. */
289# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_MASK UINT32_C(0x1c)
290# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SHIFT 2
291# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(a) ((a) << TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SHIFT)
292/** Flag whether the register contains valid values. */
293# define TPM_CRB_LOCALITY_REG_STATE_VALID RT_BIT(7)
294
295/** Locality control register. */
296#define TPM_CRB_LOCALITY_REG_CTRL 0x08
297/** Request TPM access from this locality. */
298# define TPM_CRB_LOCALITY_REG_CTRL_REQ_ACCESS RT_BIT(0)
299/** Release TPM access from this locality. */
300# define TPM_CRB_LOCALITY_REG_CTRL_RELINQUISH RT_BIT(1)
301/** Seize TPM access in favor of this locality if it has a higher priority. */
302# define TPM_CRB_LOCALITY_REG_CTRL_SEIZE RT_BIT(2)
303/** Resets the established bit if written from locality 3 or 4. */
304# define TPM_CRB_LOCALITY_REG_CTRL_RST_ESTABLISHMENT RT_BIT(3)
305
306/** Locality status register. */
307#define TPM_CRB_LOCALITY_REG_STS 0x0c
308/** Locality has been granted access to the TPM. */
309# define TPM_CRB_LOCALITY_REG_STS_GRANTED RT_BIT(0)
310/** A higher locality has seized the TPM from this locality. */
311# define TPM_CRB_LOCALITY_REG_STS_SEIZED RT_BIT(1)
312
313/** Locality interface ID register. */
314#define TPM_CRB_LOCALITY_REG_INTF_ID 0x30
315/** Interface type field. */
316# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_MASK UINT32_C(0xf)
317# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SHIFT 0
318# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SET(a) ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SHIFT)
319/** FIFO interface as defined in PTP for TPM 2.0 is active. */
320# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_FIFO_TPM20 0x0
321/** CRB interface is active. */
322# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_CRB 0x1
323/** FIFO interface as defined in TIS 1.3 is active. */
324# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_TIS1_3 0xf
325/** Interface type field. */
326# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_MASK UINT32_C(0xf)
327# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SHIFT 4
328# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SET(a) ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SHIFT)
329/** FIFO interface for TPM 2.0 */
330# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_FIFO 0
331/** CRB interface version 0. */
332# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_CRB 1
333/** Only locality 0 is supported when clear, set if 5 localities are supported. */
334# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_LOCALITY RT_BIT(8)
335/** @todo TPM supports ... */
336# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB_IDLE_BYPASS RT_BIT(9)
337/** Maximum transfer size support. */
338# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_MASK 0x1800
339# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SHIFT 11
340# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(a) ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SHIFT)
341/** Only legacy transfers supported. */
342# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_LEGACY 0x0
343/** 8B maximum transfer size. */
344# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_8B 0x1
345/** 32B maximum transfer size. */
346# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_32B 0x2
347/** 64B maximum transfer size. */
348# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B 0x3
349/** FIFO interface is supported and may be selected. */
350# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_FIFO RT_BIT(13)
351/** CRB interface is supported and may be selected. */
352# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB RT_BIT(14)
353/** Interrupt polarity configuration. */
354# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_MASK 0x60000
355# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT 17
356# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SET(a) ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT)
357# 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)
358/** Selects the FIFO interface, takes effect on next _TPM_INIT. */
359# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_FIFO 0
360/** Selects the CRB interface, takes effect on next _TPM_INIT. */
361# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_CRB 1
362/** Locks the interface selector field and prevents further changes. */
363# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_LOCK RT_BIT(19)
364/** Revision ID field. */
365# define TPM_CRB_LOCALITY_REG_INTF_ID_RID_SHIFT 17
366# define TPM_CRB_LOCALITY_REG_INTF_ID_RID_SET(a) ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_RID_SHIFT)
367/** Vendor ID field. */
368# define TPM_CRB_LOCALITY_REG_INTF_ID_VID_SHIFT 32
369# define TPM_CRB_LOCALITY_REG_INTF_ID_VID_SET(a) ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_VID_SHIFT)
370/** Device ID field. */
371# define TPM_CRB_LOCALITY_REG_INTF_ID_DID_SHIFT 48
372# define TPM_CRB_LOCALITY_REG_INTF_ID_DID_SET(a) ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_DID_SHIFT)
373
374/** Locality CRB extension register (optional and locality 0 only). */
375#define TPM_CRB_LOCALITY_REG_CTRL_EXT 0x38
376
377/** Locality CRB request register. */
378#define TPM_CRB_LOCALITY_REG_CTRL_REQ 0x40
379/** The TPM should transition to the ready state to receive a new command. */
380# define TPM_CRB_LOCALITY_REG_CTRL_REQ_CMD_RDY RT_BIT(0)
381/** The TPM should transition to the idle state. */
382# define TPM_CRB_LOCALITY_REG_CTRL_REQ_IDLE RT_BIT(1)
383
384/** Locality CRB status register. */
385#define TPM_CRB_LOCALITY_REG_CTRL_STS 0x44
386/** This bit indicates that the TPM ran into a fatal error if set. */
387# define TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_FATAL_ERR RT_BIT(0)
388/** This bit indicates that the TPM is in the idle state. */
389# define TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_IDLE RT_BIT(1)
390
391/** Locality CRB cancel register. */
392#define TPM_CRB_LOCALITY_REG_CTRL_CANCEL 0x48
393/** Locality CRB start register. */
394#define TPM_CRB_LOCALITY_REG_CTRL_START 0x4c
395
396/** Locality interrupt enable register. */
397#define TPM_CRB_LOCALITY_REG_INT_ENABLE 0x50
398/** Enable the "TPM has executed a reqeust and response is available" interrupt. */
399# define TPM_CRB_LOCALITY_REG_INT_ENABLE_START RT_BIT(0)
400/** Enable the "TPM has transitioned to the command ready state" interrupt. */
401# define TPM_CRB_LOCALITY_REG_INT_CMD_RDY RT_BIT(1)
402/** Enable the "TPM has cleared the establishment flag" interrupt. */
403# define TPM_CRB_LOCALITY_REG_INT_ESTABLISHMENT_CLR RT_BIT(2)
404/** Enable the "active locality has changed" interrupt. */
405# define TPM_CRB_LOCALITY_REG_INT_LOC_CHANGED RT_BIT(3)
406/** Enables interrupts globally as defined by the individual bits in this register. */
407# define TPM_CRB_LOCALITY_REG_INT_GLOBAL_ENABLE RT_BIT(31)
408
409/** Locality interrupt status register. */
410#define TPM_CRB_LOCALITY_REG_INT_STS 0x54
411/** Indicates that the TPM as executed a command and the response is available for reading, writing a 1 clears the bit. */
412# define TPM_CRB_LOCALITY_REG_INT_STS_START RT_BIT(0)
413/** Indicates that the TPM has finished the transition to the ready state, writing a 1 clears this bit. */
414# define TPM_CRB_LOCALITY_REG_INT_STS_CMD_RDY RT_BIT(1)
415/** Indicates that the TPM has cleared the establishment flag, writing a 1 clears this bit. */
416# define TPM_CRB_LOCALITY_REG_INT_STS_ESTABLISHMENT_CLR RT_BIT(2)
417/** Indicates that a locality change has occurrec, writing a 1 clears this bit. */
418# define TPM_CRB_LOCALITY_REG_INT_STS_LOC_CHANGED RT_BIT(3)
419
420/** Locality command buffer size register. */
421#define TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ 0x58
422/** Locality command buffer low address register. */
423#define TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR 0x5c
424/** Locality command buffer low address register. */
425#define TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR 0x60
426/** Locality response buffer size register. */
427#define TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ 0x64
428/** Locality response buffer address register. */
429#define TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR 0x68
430/** Locality data buffer. */
431#define TPM_CRB_LOCALITY_REG_DATA_BUFFER 0x80
432/** @} */
433
434
435/*********************************************************************************************************************************
436* Structures and Typedefs *
437*********************************************************************************************************************************/
438
439/**
440 * Possible TPM states
441 * (see chapter 5.6.12.1 Figure 3 State Transition Diagram).
442 */
443typedef enum DEVTPMSTATE
444{
445 /** Invalid state, do not use. */
446 DEVTPMSTATE_INVALID = 0,
447 /** Idle state. */
448 DEVTPMSTATE_IDLE,
449 /** Ready to accept command data. */
450 DEVTPMSTATE_READY,
451 /** Command data being transfered. */
452 DEVTPMSTATE_CMD_RECEPTION,
453 /** Command is being executed by the TPM. */
454 DEVTPMSTATE_CMD_EXEC,
455 /** Command has completed and data can be read. */
456 DEVTPMSTATE_CMD_COMPLETION,
457 /** Command is being canceled. */
458 DEVTPMSTATE_CMD_CANCEL,
459 /** TPM ran into a fatal error and is not operational. */
460 DEVTPMSTATE_FATAL_ERROR,
461 /** Last valid state (used for saved state sanity check). */
462 DEVTPMSTATE_LAST_VALID = DEVTPMSTATE_FATAL_ERROR,
463 /** 32bit hack. */
464 DEVTPMSTATE_32BIT_HACK = 0x7fffffff
465} DEVTPMSTATE;
466
467
468/**
469 * Locality state.
470 */
471typedef struct DEVTPMLOCALITY
472{
473 /** The interrupt enable register. */
474 uint32_t uRegIntEn;
475 /** The interrupt status register. */
476 uint32_t uRegIntSts;
477} DEVTPMLOCALITY;
478/** Pointer to a locality state. */
479typedef DEVTPMLOCALITY *PDEVTPMLOCALITY;
480/** Pointer to a const locality state. */
481typedef const DEVTPMLOCALITY *PCDEVTPMLOCALITY;
482
483
484/**
485 * Shared TPM device state.
486 */
487typedef struct DEVTPM
488{
489 /** Base MMIO address of the TPM device. */
490 RTGCPHYS GCPhysMmio;
491 /** The handle of the MMIO region. */
492 IOMMMIOHANDLE hMmio;
493 /** The handle for the ring-3 task. */
494 PDMTASKHANDLE hTpmCmdTask;
495 /** The vendor ID configured. */
496 uint16_t uVenId;
497 /** The device ID configured. */
498 uint16_t uDevId;
499 /** The revision ID configured. */
500 uint8_t bRevId;
501 /** The IRQ value. */
502 uint8_t uIrq;
503 /** Flag whether CRB access mode is used. */
504 bool fCrb;
505 /** Flag whether the TPM driver below supportes other localities than 0. */
506 bool fLocChangeSup;
507 /** Flag whether the establishment bit is set. */
508 bool fEstablishmentSet;
509
510 /** Currently selected locality. */
511 uint8_t bLoc;
512 /** States of the implemented localities. */
513 DEVTPMLOCALITY aLoc[TPM_LOCALITY_COUNT];
514 /** Bitmask of localities having requested access to the TPM. */
515 uint32_t bmLocReqAcc;
516 /** Bitmask of localities having been seized access from the TPM. */
517 uint32_t bmLocSeizedAcc;
518 /** The current state of the TPM. */
519 DEVTPMSTATE enmState;
520 /** The TPM version being emulated. */
521 TPMVERSION enmTpmVers;
522
523 /** Size of the command/response buffer. */
524 uint32_t cbCmdResp;
525 /** Offset into the Command/Response buffer. */
526 uint32_t offCmdResp;
527 /** Command/Response buffer. */
528 uint8_t abCmdResp[TPM_DATA_BUFFER_SIZE_MAX];
529} DEVTPM;
530/** Pointer to the shared TPM device state. */
531typedef DEVTPM *PDEVTPM;
532
533/** The special no current locality selected value. */
534#define TPM_NO_LOCALITY_SELECTED 0xff
535
536
537/**
538 * TPM device state for ring-3.
539 */
540typedef struct DEVTPMR3
541{
542 /** Pointer to the device instance. */
543 PPDMDEVINS pDevIns;
544 /** The base interface for LUN\#0. */
545 PDMIBASE IBase;
546 /** The base interface below. */
547 R3PTRTYPE(PPDMIBASE) pDrvBase;
548 /** The TPM connector interface below. */
549 R3PTRTYPE(PPDMITPMCONNECTOR) pDrvTpm;
550} DEVTPMR3;
551/** Pointer to the TPM device state for ring-3. */
552typedef DEVTPMR3 *PDEVTPMR3;
553
554
555/**
556 * TPM device state for ring-0.
557 */
558typedef struct DEVTPMR0
559{
560 uint32_t u32Dummy;
561} DEVTPMR0;
562/** Pointer to the TPM device state for ring-0. */
563typedef DEVTPMR0 *PDEVTPMR0;
564
565
566/**
567 * TPM device state for raw-mode.
568 */
569typedef struct DEVTPMRC
570{
571 uint32_t u32Dummy;
572} DEVTPMRC;
573/** Pointer to the TPM device state for raw-mode. */
574typedef DEVTPMRC *PDEVTPMRC;
575
576/** The TPM device state for the current context. */
577typedef CTX_SUFF(DEVTPM) DEVTPMCC;
578/** Pointer to the TPM device state for the current context. */
579typedef CTX_SUFF(PDEVTPM) PDEVTPMCC;
580
581
582#ifndef VBOX_DEVICE_STRUCT_TESTCASE
583
584
585/*********************************************************************************************************************************
586* Global Variables *
587*********************************************************************************************************************************/
588#ifdef IN_RING3
589/**
590 * SSM descriptor table for the TPM structure.
591 */
592static SSMFIELD const g_aTpmFields[] =
593{
594 SSMFIELD_ENTRY(DEVTPM, fEstablishmentSet),
595 SSMFIELD_ENTRY(DEVTPM, bLoc),
596 SSMFIELD_ENTRY(DEVTPM, aLoc[0].uRegIntEn),
597 SSMFIELD_ENTRY(DEVTPM, aLoc[0].uRegIntSts),
598 SSMFIELD_ENTRY(DEVTPM, aLoc[1].uRegIntEn),
599 SSMFIELD_ENTRY(DEVTPM, aLoc[1].uRegIntSts),
600 SSMFIELD_ENTRY(DEVTPM, aLoc[2].uRegIntEn),
601 SSMFIELD_ENTRY(DEVTPM, aLoc[2].uRegIntSts),
602 SSMFIELD_ENTRY(DEVTPM, aLoc[3].uRegIntEn),
603 SSMFIELD_ENTRY(DEVTPM, aLoc[3].uRegIntSts),
604 SSMFIELD_ENTRY(DEVTPM, aLoc[4].uRegIntEn),
605 SSMFIELD_ENTRY(DEVTPM, aLoc[4].uRegIntSts),
606 SSMFIELD_ENTRY(DEVTPM, bmLocReqAcc),
607 SSMFIELD_ENTRY(DEVTPM, bmLocSeizedAcc),
608 SSMFIELD_ENTRY(DEVTPM, enmState),
609 SSMFIELD_ENTRY(DEVTPM, offCmdResp),
610 SSMFIELD_ENTRY(DEVTPM, abCmdResp),
611 SSMFIELD_ENTRY_TERM()
612};
613#endif
614
615
616/**
617 * Sets the IRQ line of the given device to the given state.
618 *
619 * @param pDevIns Pointer to the PDM device instance data.
620 * @param pThis Pointer to the shared TPM device.
621 * @param iLvl The interrupt level to set.
622 */
623DECLINLINE(void) tpmIrqReq(PPDMDEVINS pDevIns, PDEVTPM pThis, int iLvl)
624{
625 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl);
626}
627
628
629/**
630 * Updates the IRQ status of the given locality.
631 *
632 * @param pDevIns Pointer to the PDM device instance data.
633 * @param pThis Pointer to the shared TPM device.
634 * @param pLoc The locality state.
635 */
636static void tpmLocIrqUpdate(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc)
637{
638 if ( (pLoc->uRegIntEn & TPM_CRB_LOCALITY_REG_INT_GLOBAL_ENABLE) /* Aliases with TPM_FIFO_LOCALITY_REG_INT_ENABLE_GLOBAL */
639 && (pLoc->uRegIntEn & pLoc->uRegIntSts))
640 tpmIrqReq(pDevIns, pThis, 1);
641 else
642 tpmIrqReq(pDevIns, pThis, 0);
643}
644
645
646/**
647 * Sets the interrupt status for the given locality, firing an interrupt if necessary.
648 *
649 * @param pDevIns Pointer to the PDM device instance data.
650 * @param pThis Pointer to the shared TPM device.
651 * @param pLoc The locality state.
652 * @param uSts The interrupt status bit to set.
653 */
654static void tpmLocSetIntSts(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc, uint32_t uSts)
655{
656 pLoc->uRegIntSts |= uSts;
657 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
658}
659
660
661/**
662 * Selects the next locality which has requested access.
663 *
664 * @param pDevIns Pointer to the PDM device instance data.
665 * @param pThis Pointer to the shared TPM device.
666 */
667static void tpmLocSelectNext(PPDMDEVINS pDevIns, PDEVTPM pThis)
668{
669 Assert(pThis->bmLocReqAcc);
670 Assert(pThis->bLoc == TPM_NO_LOCALITY_SELECTED);
671 pThis->bLoc = (uint8_t)ASMBitLastSetU32(pThis->bmLocReqAcc) - 1; /* Select one with highest priority. */
672
673 tpmLocSetIntSts(pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_CRB_LOCALITY_REG_INT_STS_LOC_CHANGED);
674}
675
676
677/**
678 * Returns the given locality being accessed from the given TPM MMIO offset.
679 *
680 * @returns Locality number.
681 * @param off The offset into the TPM MMIO region.
682 */
683DECLINLINE(uint8_t) tpmGetLocalityFromOffset(RTGCPHYS off)
684{
685 return off / TPM_LOCALITY_MMIO_SIZE;
686}
687
688
689/**
690 * Returns the given register of a particular locality being accessed from the given TPM MMIO offset.
691 *
692 * @returns Register index being accessed.
693 * @param off The offset into the TPM MMIO region.
694 */
695DECLINLINE(uint32_t) tpmGetRegisterFromOffset(RTGCPHYS off)
696{
697 return off % TPM_LOCALITY_MMIO_SIZE;
698}
699
700
701/**
702 * Read from a FIFO interface register.
703 *
704 * @returns VBox strict status code.
705 * @param pDevIns Pointer to the PDM device instance data.
706 * @param pThis Pointer to the shared TPM device.
707 * @param pLoc The locality state being read from.
708 * @param bLoc The locality index.
709 * @param uReg The register offset being accessed.
710 * @param pu64 Where to store the read data.
711 * @param cb Number of bytes to read.
712 */
713static VBOXSTRICTRC tpmMmioFifoRead(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
714 uint8_t bLoc, uint32_t uReg, uint64_t *pu64, size_t cb)
715{
716 RT_NOREF(pDevIns);
717 VBOXSTRICTRC rc = VINF_SUCCESS;
718
719 /* Special path for the data buffer. */
720 if ( ( ( uReg >= TPM_FIFO_LOCALITY_REG_DATA_FIFO
721 && uReg < TPM_FIFO_LOCALITY_REG_DATA_FIFO + sizeof(uint32_t))
722 || ( uReg >= TPM_FIFO_LOCALITY_REG_XDATA_FIFO
723 && uReg < TPM_FIFO_LOCALITY_REG_XDATA_FIFO + sizeof(uint32_t)))
724 && bLoc == pThis->bLoc
725 && pThis->enmState == DEVTPMSTATE_CMD_COMPLETION)
726 {
727 if (pThis->offCmdResp <= pThis->cbCmdResp - cb)
728 {
729 memcpy(pu64, &pThis->abCmdResp[pThis->offCmdResp], cb);
730 pThis->offCmdResp += (uint32_t)cb;
731 }
732 else
733 memset(pu64, 0xff, cb);
734 return VINF_SUCCESS;
735 }
736
737 uint64_t u64;
738 switch (uReg)
739 {
740 case TPM_FIFO_LOCALITY_REG_ACCESS:
741 u64 = TPM_FIFO_LOCALITY_REG_ACCESS_VALID;
742 if (pThis->bLoc == bLoc)
743 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_ACTIVE;
744 if (pThis->bmLocSeizedAcc & RT_BIT_32(bLoc))
745 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_BEEN_SEIZED;
746 if (pThis->bmLocReqAcc & ~RT_BIT_32(bLoc))
747 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_PENDING_REQUEST;
748 if ( pThis->bLoc != bLoc
749 && pThis->bmLocReqAcc & RT_BIT_32(bLoc))
750 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_REQUEST_USE;
751 if (pThis->fEstablishmentSet)
752 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_ESTABLISHMENT;
753 break;
754 case TPM_FIFO_LOCALITY_REG_INT_ENABLE:
755 u64 = pLoc->uRegIntEn;
756 break;
757 case TPM_FIFO_LOCALITY_REG_INT_VEC:
758 u64 = pThis->uIrq;
759 break;
760 case TPM_FIFO_LOCALITY_REG_INT_STS:
761 u64 = pLoc->uRegIntSts;
762 break;
763 case TPM_FIFO_LOCALITY_REG_IF_CAP:
764 u64 = TPM_FIFO_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL
765 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_STS_VALID
766 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE
767 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_LOW
768 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_CMD_RDY
769 | TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B); /** @todo Make some of them configurable? */
770 if (pThis->enmTpmVers == TPMVERSION_1_2)
771 u64 |= TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3);
772 else
773 u64 |= TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3_TPM2);
774 break;
775 case TPM_FIFO_LOCALITY_REG_STS:
776 if (bLoc != pThis->bLoc)
777 {
778 u64 = UINT64_MAX;
779 break;
780 }
781
782 u64 = TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_SET( pThis->enmTpmVers == TPMVERSION_1_2
783 ? TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_1_2
784 : TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_2_0)
785 | TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SET(_1K)
786 | TPM_FIFO_LOCALITY_REG_STS_VALID;
787 if (pThis->enmState == DEVTPMSTATE_READY)
788 u64 |= TPM_FIFO_LOCALITY_REG_STS_CMD_RDY;
789 else if (pThis->enmState == DEVTPMSTATE_CMD_RECEPTION) /* When in the command reception state check whether all of the command data has been received. */
790 {
791 if ( pThis->offCmdResp < sizeof(TPMREQHDR)
792 || pThis->offCmdResp < RTTpmReqGetSz((PCTPMREQHDR)&pThis->abCmdResp[0]))
793 u64 |= TPM_FIFO_LOCALITY_REG_STS_EXPECT;
794 }
795 else if (pThis->enmState == DEVTPMSTATE_CMD_COMPLETION) /* Check whether there is more response data available. */
796 {
797 if (pThis->offCmdResp < RTTpmRespGetSz((PCTPMRESPHDR)&pThis->abCmdResp[0]))
798 u64 |= TPM_FIFO_LOCALITY_REG_STS_DATA_AVAIL;
799 }
800 break;
801 case TPM_FIFO_LOCALITY_REG_INTF_ID:
802 u64 = TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_SET(TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_FIFO)
803 | TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B)
804 | TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_GET(TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_FIFO)
805 | TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_LOCK
806 | TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_FIFO;
807 if (pThis->enmTpmVers == TPMVERSION_1_2)
808 u64 |= TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_SET(TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_TIS1_3);
809 else
810 u64 |= TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_SET(TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_FIFO_TPM20);
811
812 if (pThis->fLocChangeSup) /* Only advertise the locality capability if the driver below supports it. */
813 u64 |= TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_LOCALITY;
814 break;
815 case TPM_FIFO_LOCALITY_REG_DID_VID:
816 u64 = RT_H2BE_U32(RT_MAKE_U32(pThis->uVenId, pThis->uDevId));
817 break;
818 case TPM_FIFO_LOCALITY_REG_RID:
819 u64 = pThis->bRevId;
820 break;
821 default: /* Return ~0. */
822 u64 = UINT64_MAX;
823 break;
824 }
825
826 *pu64 = u64;
827
828 return rc;
829}
830
831
832/**
833 * Read to a FIFO interface register.
834 *
835 * @returns VBox strict status code.
836 * @param pDevIns Pointer to the PDM device instance data.
837 * @param pThis Pointer to the shared TPM device.
838 * @param pLoc The locality state being written to.
839 * @param bLoc The locality index.
840 * @param uReg The register offset being accessed.
841 * @param u64 The value to write.
842 * @param cb Number of bytes to write.
843 */
844static VBOXSTRICTRC tpmMmioFifoWrite(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
845 uint8_t bLoc, uint32_t uReg, uint64_t u64, size_t cb)
846{
847#ifdef IN_RING3
848 PDEVTPMR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMR3);
849#endif
850
851 /* Special path for the data buffer. */
852 if ( ( ( uReg >= TPM_FIFO_LOCALITY_REG_DATA_FIFO
853 && uReg < TPM_FIFO_LOCALITY_REG_DATA_FIFO + sizeof(uint32_t))
854 || ( uReg >= TPM_FIFO_LOCALITY_REG_XDATA_FIFO
855 && uReg < TPM_FIFO_LOCALITY_REG_XDATA_FIFO + sizeof(uint32_t)))
856 && bLoc == pThis->bLoc
857 && ( pThis->enmState == DEVTPMSTATE_READY
858 || pThis->enmState == DEVTPMSTATE_CMD_RECEPTION))
859 {
860 pThis->enmState = DEVTPMSTATE_CMD_RECEPTION;
861 if (pThis->offCmdResp <= pThis->cbCmdResp - cb)
862 {
863 memcpy(&pThis->abCmdResp[pThis->offCmdResp], &u64, cb);
864 pThis->offCmdResp += (uint32_t)cb;
865 }
866 return VINF_SUCCESS;
867 }
868
869 VBOXSTRICTRC rc = VINF_SUCCESS;
870 uint32_t u32 = (uint32_t)u64;
871
872 switch (uReg)
873 {
874 case TPM_FIFO_LOCALITY_REG_ACCESS:
875 u32 &= TPM_FIFO_LOCALITY_REG_ACCESS_WR_MASK;
876 /*
877 * Chapter 5.6.11, 2 states that writing to this register with more than one
878 * bit set to '1' is vendor specific, we decide to ignore such writes to make the logic
879 * below simpler.
880 */
881 if (!RT_IS_POWER_OF_TWO(u32))
882 break;
883
884 /* Seize access only if this locality has a higher priority than the currently selected one. */
885 if ( (u32 & TPM_FIFO_LOCALITY_REG_ACCESS_SEIZE)
886 && pThis->bLoc != TPM_NO_LOCALITY_SELECTED
887 && bLoc > pThis->bLoc)
888 {
889 pThis->bmLocSeizedAcc |= RT_BIT_32(pThis->bLoc);
890 /** @todo Abort command. */
891 pThis->bLoc = bLoc;
892 }
893
894 if ( (u64 & TPM_FIFO_LOCALITY_REG_ACCESS_REQUEST_USE)
895 && !(pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
896 {
897 pThis->bmLocReqAcc |= RT_BIT_32(bLoc);
898 if (pThis->bLoc == TPM_NO_LOCALITY_SELECTED)
899 {
900 pThis->bLoc = bLoc; /* Doesn't fire an interrupt. */
901 pThis->bmLocSeizedAcc &= ~RT_BIT_32(bLoc);
902 }
903 }
904
905 if ( (u64 & TPM_FIFO_LOCALITY_REG_ACCESS_ACTIVE)
906 && (pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
907 {
908 pThis->bmLocReqAcc &= ~RT_BIT_32(bLoc);
909 if (pThis->bLoc == bLoc)
910 {
911 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
912 if (pThis->bmLocReqAcc)
913 tpmLocSelectNext(pDevIns, pThis); /* Select the next locality. */
914 }
915 }
916 break;
917 case TPM_FIFO_LOCALITY_REG_INT_ENABLE:
918 if (bLoc != pThis->bLoc)
919 break;
920 pLoc->uRegIntEn = u32;
921 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
922 break;
923 case TPM_FIFO_LOCALITY_REG_INT_STS:
924 if (bLoc != pThis->bLoc)
925 break;
926 pLoc->uRegIntSts &= ~(u32 & TPM_FIFO_LOCALITY_REG_INT_STS_WR_MASK);
927 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
928 break;
929 case TPM_FIFO_LOCALITY_REG_STS:
930 /*
931 * Writes are ignored completely if the locality being accessed is not the
932 * current active one or if the value has multiple bits set (not a power of two),
933 * see chapter 5.6.12.1.
934 */
935 if ( bLoc != pThis->bLoc
936 || !RT_IS_POWER_OF_TWO(u64))
937 break;
938
939 if ( (u64 & TPM_FIFO_LOCALITY_REG_STS_CMD_RDY)
940 && ( pThis->enmState == DEVTPMSTATE_IDLE
941 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
942 {
943 pThis->enmState = DEVTPMSTATE_READY;
944 pThis->offCmdResp = 0;
945 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_FIFO_LOCALITY_REG_INT_STS_CMD_RDY);
946 }
947
948 if ( (u64 & TPM_FIFO_LOCALITY_REG_STS_TPM_GO)
949 && pThis->enmState == DEVTPMSTATE_CMD_RECEPTION)
950 {
951 pThis->enmState = DEVTPMSTATE_CMD_EXEC;
952 rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hTpmCmdTask);
953 }
954
955 if ( (u64 & TPM_FIFO_LOCALITY_REG_STS_RST_ESTABLISHMENT)
956 && pThis->bLoc >= 3
957 && ( pThis->enmState == DEVTPMSTATE_IDLE
958 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
959 {
960#ifndef IN_RING3
961 rc = VINF_IOM_R3_MMIO_WRITE;
962 break;
963#else
964 if (pThisCC->pDrvTpm)
965 {
966 int rc2 = pThisCC->pDrvTpm->pfnResetEstablishedFlag(pThisCC->pDrvTpm, pThis->bLoc);
967 if (RT_SUCCESS(rc2))
968 pThis->fEstablishmentSet = false;
969 else
970 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
971 }
972 else
973 pThis->fEstablishmentSet = false;
974#endif
975 }
976
977 if ( (u64 & TPM_FIFO_LOCALITY_REG_STS_CMD_CANCEL)
978 && pThis->enmState == DEVTPMSTATE_CMD_EXEC)
979 {
980#ifndef IN_RING3
981 rc = VINF_IOM_R3_MMIO_WRITE;
982 break;
983#else
984 if (pThisCC->pDrvTpm)
985 {
986 pThis->enmState = DEVTPMSTATE_CMD_CANCEL;
987 int rc2 = pThisCC->pDrvTpm->pfnCmdCancel(pThisCC->pDrvTpm);
988 if (RT_FAILURE(rc2))
989 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
990 }
991#endif
992 }
993
994 break;
995 case TPM_FIFO_LOCALITY_REG_INT_VEC:
996 case TPM_FIFO_LOCALITY_REG_IF_CAP:
997 case TPM_FIFO_LOCALITY_REG_DID_VID:
998 case TPM_FIFO_LOCALITY_REG_RID:
999 default: /* Ignore. */
1000 break;
1001 }
1002
1003 return rc;
1004}
1005
1006
1007/**
1008 * Read from a CRB interface register.
1009 *
1010 * @returns VBox strict status code.
1011 * @param pDevIns Pointer to the PDM device instance data.
1012 * @param pThis Pointer to the shared TPM device.
1013 * @param pLoc The locality state being read from.
1014 * @param bLoc The locality index.
1015 * @param uReg The register offset being accessed.
1016 * @param pu64 Where to store the read data.
1017 * @param cb Size of the read in bytes.
1018 */
1019static VBOXSTRICTRC tpmMmioCrbRead(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
1020 uint8_t bLoc, uint32_t uReg, uint64_t *pu64, size_t cb)
1021{
1022 RT_NOREF(pDevIns);
1023
1024 /* Special path for the data buffer. */
1025 if ( uReg >= TPM_CRB_LOCALITY_REG_DATA_BUFFER
1026 && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + pThis->cbCmdResp
1027 && bLoc == pThis->bLoc
1028 && pThis->enmState == DEVTPMSTATE_CMD_COMPLETION)
1029 {
1030 memcpy(pu64, &pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], cb);
1031 return VINF_SUCCESS;
1032 }
1033
1034 VBOXSTRICTRC rc = VINF_SUCCESS;
1035 uint64_t u64 = UINT64_MAX;
1036 switch (uReg)
1037 {
1038 case TPM_CRB_LOCALITY_REG_STATE:
1039 u64 = TPM_CRB_LOCALITY_REG_STATE_VALID
1040 | ( pThis->bLoc != TPM_NO_LOCALITY_SELECTED
1041 ? TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(pThis->bLoc) | TPM_CRB_LOCALITY_REG_STATE_LOC_ASSIGNED
1042 : TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(0));
1043 if (pThis->fEstablishmentSet)
1044 u64 |= TPM_CRB_LOCALITY_REG_ESTABLISHMENT;
1045 break;
1046 case TPM_CRB_LOCALITY_REG_STS:
1047 u64 = pThis->bLoc == bLoc
1048 ? TPM_CRB_LOCALITY_REG_STS_GRANTED
1049 : 0;
1050 u64 |= pThis->bmLocSeizedAcc & RT_BIT_32(bLoc)
1051 ? TPM_CRB_LOCALITY_REG_STS_SEIZED
1052 : 0;
1053 break;
1054 case TPM_CRB_LOCALITY_REG_INTF_ID:
1055 u64 = TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_CRB)
1056 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_CRB)
1057 | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B)
1058 | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB
1059 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_GET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_CRB)
1060 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_LOCK
1061 | TPM_CRB_LOCALITY_REG_INTF_ID_RID_SET(pThis->bRevId)
1062 | TPM_CRB_LOCALITY_REG_INTF_ID_VID_SET(pThis->uVenId)
1063 | TPM_CRB_LOCALITY_REG_INTF_ID_DID_SET(pThis->uDevId);
1064
1065 if (pThis->fLocChangeSup) /* Only advertise the locality capability if the driver below supports it. */
1066 u64 |= TPM_CRB_LOCALITY_REG_INTF_ID_CAP_LOCALITY;
1067
1068 break;
1069 case TPM_CRB_LOCALITY_REG_CTRL_REQ:
1070 if (bLoc != pThis->bLoc)
1071 break;
1072 /*
1073 * Command ready and go idle are always 0 upon read
1074 * as we don't need time to transition to this state
1075 * when written by the guest.
1076 */
1077 u64 = 0;
1078 break;
1079 case TPM_CRB_LOCALITY_REG_CTRL_STS:
1080 if (bLoc != pThis->bLoc)
1081 break;
1082 if (pThis->enmState == DEVTPMSTATE_FATAL_ERROR)
1083 u64 = TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_FATAL_ERR;
1084 else if (pThis->enmState == DEVTPMSTATE_IDLE)
1085 u64 = TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_IDLE;
1086 else
1087 u64 = 0;
1088 break;
1089 case TPM_CRB_LOCALITY_REG_CTRL_CANCEL:
1090 if (bLoc != pThis->bLoc)
1091 break;
1092 if (pThis->enmState == DEVTPMSTATE_CMD_CANCEL)
1093 u64 = 0x1;
1094 else
1095 u64 = 0;
1096 break;
1097 case TPM_CRB_LOCALITY_REG_CTRL_START:
1098 if (bLoc != pThis->bLoc)
1099 break;
1100 if (pThis->enmState == DEVTPMSTATE_CMD_EXEC)
1101 u64 = 0x1;
1102 else
1103 u64 = 0;
1104 break;
1105 case TPM_CRB_LOCALITY_REG_INT_ENABLE:
1106 u64 = pLoc->uRegIntEn;
1107 break;
1108 case TPM_CRB_LOCALITY_REG_INT_STS:
1109 u64 = pLoc->uRegIntSts;
1110 break;
1111 case TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR:
1112 u64 = pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER;
1113 break;
1114 case TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR:
1115 u64 = (pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER) >> 32;
1116 break;
1117 case TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ:
1118 case TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ:
1119 u64 = pThis->cbCmdResp;
1120 break;
1121 case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR:
1122 u64 = pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER;
1123 break;
1124 case TPM_CRB_LOCALITY_REG_CTRL: /* Writeonly */
1125 u64 = 0;
1126 break;
1127 case TPM_CRB_LOCALITY_REG_CTRL_EXT:
1128 default:
1129 break; /* Return ~0 */
1130 }
1131
1132 *pu64 = u64;
1133 return rc;
1134}
1135
1136
1137/**
1138 * Read to a CRB interface register.
1139 *
1140 * @returns VBox strict status code.
1141 * @param pDevIns Pointer to the PDM device instance data.
1142 * @param pThis Pointer to the shared TPM device.
1143 * @param pLoc The locality state being written to.
1144 * @param bLoc The locality index.
1145 * @param uReg The register offset being accessed.
1146 * @param u64 The value to write.
1147 * @param cb Size of the write in bytes.
1148 */
1149static VBOXSTRICTRC tpmMmioCrbWrite(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
1150 uint8_t bLoc, uint32_t uReg, uint64_t u64, size_t cb)
1151{
1152#ifdef IN_RING3
1153 PDEVTPMR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMR3);
1154#endif
1155
1156 VBOXSTRICTRC rc = VINF_SUCCESS;
1157 uint32_t u32 = (uint32_t)u64;
1158
1159 /* Special path for the data buffer. */
1160 if ( uReg >= TPM_CRB_LOCALITY_REG_DATA_BUFFER
1161 && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + pThis->cbCmdResp
1162 && bLoc == pThis->bLoc
1163 && ( pThis->enmState == DEVTPMSTATE_READY
1164 || pThis->enmState == DEVTPMSTATE_CMD_RECEPTION))
1165 {
1166 pThis->enmState = DEVTPMSTATE_CMD_RECEPTION;
1167 memcpy(&pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], &u64, cb);
1168 return VINF_SUCCESS;
1169 }
1170
1171 switch (uReg)
1172 {
1173 case TPM_CRB_LOCALITY_REG_CTRL:
1174 {
1175 /* See chapter 6.5.3.2.2.1. */
1176 if ( (u64 & TPM_CRB_LOCALITY_REG_CTRL_RST_ESTABLISHMENT)
1177 && pThis->bLoc >= 3
1178 && ( pThis->enmState == DEVTPMSTATE_IDLE
1179 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
1180 {
1181#ifndef IN_RING3
1182 rc = VINF_IOM_R3_MMIO_WRITE;
1183 break;
1184#else
1185 if (pThisCC->pDrvTpm)
1186 {
1187 int rc2 = pThisCC->pDrvTpm->pfnResetEstablishedFlag(pThisCC->pDrvTpm, pThis->bLoc);
1188 if (RT_SUCCESS(rc2))
1189 pThis->fEstablishmentSet = false;
1190 else
1191 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1192 }
1193 else
1194 pThis->fEstablishmentSet = false;
1195#endif
1196 }
1197
1198 /*
1199 * The following three checks should be mutually exclusive as the writer shouldn't
1200 * request, relinquish and seize access in the same write.
1201 */
1202 /* Seize access only if this locality has a higher priority than the currently selected one. */
1203 if ( (u64 & TPM_CRB_LOCALITY_REG_CTRL_SEIZE)
1204 && pThis->bLoc != TPM_NO_LOCALITY_SELECTED
1205 && bLoc > pThis->bLoc)
1206 {
1207 if (pThis->enmState == DEVTPMSTATE_CMD_EXEC)
1208 {
1209#ifndef IN_RING3
1210 rc = VINF_IOM_R3_MMIO_WRITE;
1211 break;
1212#else
1213 pThis->enmState = DEVTPMSTATE_CMD_CANCEL;
1214 if (pThisCC->pDrvTpm)
1215 {
1216 int rc2 = pThisCC->pDrvTpm->pfnCmdCancel(pThisCC->pDrvTpm);
1217 if (RT_FAILURE(rc2))
1218 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1219 else
1220 {
1221 pThis->enmState = DEVTPMSTATE_CMD_COMPLETION;
1222 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_START);
1223 }
1224 }
1225#endif
1226 }
1227
1228 pThis->bmLocSeizedAcc |= RT_BIT_32(pThis->bLoc);
1229 pThis->bLoc = bLoc;
1230 }
1231
1232 if ( (u64 & TPM_CRB_LOCALITY_REG_CTRL_REQ_ACCESS)
1233 && !(pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
1234 {
1235 pThis->bmLocReqAcc |= RT_BIT_32(bLoc);
1236 if (pThis->bLoc == TPM_NO_LOCALITY_SELECTED)
1237 {
1238 pThis->bLoc = bLoc; /* Doesn't fire an interrupt. */
1239 pThis->bmLocSeizedAcc &= ~RT_BIT_32(bLoc);
1240 }
1241 }
1242
1243 if ( (u64 & TPM_CRB_LOCALITY_REG_CTRL_RELINQUISH)
1244 && (pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
1245 {
1246 pThis->bmLocReqAcc &= ~RT_BIT_32(bLoc);
1247 if (pThis->bLoc == bLoc)
1248 {
1249 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
1250 if (pThis->bmLocReqAcc)
1251 tpmLocSelectNext(pDevIns, pThis); /* Select the next locality. */
1252 }
1253 }
1254 break;
1255 }
1256 case TPM_CRB_LOCALITY_REG_CTRL_REQ:
1257 if ( bLoc != pThis->bLoc
1258 || !RT_IS_POWER_OF_TWO(u32)) /* Ignore if multiple bits are set. */
1259 break;
1260 if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_CMD_RDY)
1261 && ( pThis->enmState == DEVTPMSTATE_IDLE
1262 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
1263 {
1264 pThis->enmState = DEVTPMSTATE_READY;
1265 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_CMD_RDY);
1266 }
1267 else if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_IDLE)
1268 && pThis->enmState != DEVTPMSTATE_CMD_EXEC)
1269 {
1270 /* Invalidate the command/response buffer. */
1271 RT_ZERO(pThis->abCmdResp);
1272 pThis->offCmdResp = 0;
1273 pThis->enmState = DEVTPMSTATE_IDLE;
1274 }
1275 break;
1276 case TPM_CRB_LOCALITY_REG_CTRL_CANCEL:
1277 if (bLoc != pThis->bLoc)
1278 break;
1279 if ( pThis->enmState == DEVTPMSTATE_CMD_EXEC
1280 && u32 == 0x1)
1281 {
1282#ifndef IN_RING3
1283 rc = VINF_IOM_R3_MMIO_WRITE;
1284 break;
1285#else
1286 pThis->enmState = DEVTPMSTATE_CMD_CANCEL;
1287 if (pThisCC->pDrvTpm)
1288 {
1289 int rc2 = pThisCC->pDrvTpm->pfnCmdCancel(pThisCC->pDrvTpm);
1290 if (RT_FAILURE(rc2))
1291 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1292 else
1293 {
1294 pThis->enmState = DEVTPMSTATE_CMD_COMPLETION;
1295 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_START);
1296 }
1297 }
1298#endif
1299 }
1300 break;
1301 case TPM_CRB_LOCALITY_REG_CTRL_START:
1302 if (bLoc != pThis->bLoc)
1303 break;
1304 if ( pThis->enmState == DEVTPMSTATE_CMD_RECEPTION
1305 && u32 == 0x1)
1306 {
1307 pThis->enmState = DEVTPMSTATE_CMD_EXEC;
1308 rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hTpmCmdTask);
1309 }
1310 break;
1311 case TPM_CRB_LOCALITY_REG_INT_ENABLE:
1312 pLoc->uRegIntEn = u32;
1313 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
1314 break;
1315 case TPM_CRB_LOCALITY_REG_INT_STS:
1316 pLoc->uRegIntSts &= ~u32;
1317 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
1318 break;
1319 case TPM_CRB_LOCALITY_REG_CTRL_EXT: /* Not implemented. */
1320 case TPM_CRB_LOCALITY_REG_STATE: /* Readonly */
1321 case TPM_CRB_LOCALITY_REG_INTF_ID:
1322 case TPM_CRB_LOCALITY_REG_CTRL_STS:
1323 case TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR:
1324 case TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR:
1325 case TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ:
1326 case TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ:
1327 case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR:
1328 default: /* Ignore. */
1329 break;
1330 }
1331
1332 return rc;
1333}
1334
1335
1336/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
1337
1338/**
1339 * @callback_method_impl{FNIOMMMIONEWREAD}
1340 */
1341static DECLCALLBACK(VBOXSTRICTRC) tpmMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1342{
1343 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1344 RT_NOREF(pvUser);
1345
1346 AssertReturn(cb <= sizeof(uint64_t), VERR_INTERNAL_ERROR);
1347
1348 RTGCPHYS offAligned = off & ~UINT64_C(0x3);
1349 uint8_t cBitsShift = (off & 0x3) * 8;
1350
1351 VBOXSTRICTRC rc = VINF_SUCCESS;
1352 uint32_t uReg = tpmGetRegisterFromOffset(offAligned);
1353 uint8_t bLoc = tpmGetLocalityFromOffset(offAligned);
1354 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
1355
1356 uint64_t u64;
1357 if (pThis->fCrb)
1358 rc = tpmMmioCrbRead(pDevIns, pThis, pLoc, bLoc, uReg, &u64, cb);
1359 else
1360 rc = tpmMmioFifoRead(pDevIns, pThis, pLoc, bLoc, uReg, &u64, cb);
1361
1362 LogFlowFunc((": %RGp %#x %#llx\n", off, cb, u64));
1363
1364 if (rc == VINF_SUCCESS)
1365 {
1366 switch (cb)
1367 {
1368 case 1: *(uint8_t *)pv = (uint8_t)(u64 >> cBitsShift); break;
1369 case 2: *(uint16_t *)pv = (uint16_t)(u64 >> cBitsShift); break;
1370 case 4: *(uint32_t *)pv = (uint32_t)(u64 >> cBitsShift); break;
1371 case 8: *(uint64_t *)pv = u64; break;
1372 default: AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR);
1373 }
1374 }
1375
1376 return rc;
1377}
1378
1379
1380/**
1381 * @callback_method_impl{FNIOMMMIONEWWRITE}
1382 */
1383static DECLCALLBACK(VBOXSTRICTRC) tpmMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1384{
1385 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1386 RT_NOREF(pvUser);
1387
1388 Assert(!(off & (cb - 1)));
1389
1390 uint64_t u64;
1391 switch (cb)
1392 {
1393 case 1: u64 = *(const uint8_t *)pv; break;
1394 case 2: u64 = *(const uint16_t *)pv; break;
1395 case 4: u64 = *(const uint32_t *)pv; break;
1396 case 8: u64 = *(const uint64_t *)pv; break;
1397 default: AssertFailedReturn(VERR_INTERNAL_ERROR);
1398 }
1399
1400 LogFlowFunc((": %RGp %#llx\n", off, u64));
1401
1402 VBOXSTRICTRC rc = VINF_SUCCESS;
1403 uint32_t uReg = tpmGetRegisterFromOffset(off);
1404 uint8_t bLoc = tpmGetLocalityFromOffset(off);
1405 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
1406
1407 if (pThis->fCrb)
1408 rc = tpmMmioCrbWrite(pDevIns, pThis, pLoc, bLoc, uReg, u64, cb);
1409 else
1410 rc = tpmMmioFifoWrite(pDevIns, pThis, pLoc, bLoc, uReg, u64, cb);
1411
1412 return rc;
1413}
1414
1415
1416#ifdef IN_RING3
1417
1418/**
1419 * @callback_method_impl{FNPDMTASKDEV, Execute a command in ring-3}
1420 */
1421static DECLCALLBACK(void) tpmR3CmdExecWorker(PPDMDEVINS pDevIns, void *pvUser)
1422{
1423 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1424 PDEVTPMR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMR3);
1425 RT_NOREF(pvUser);
1426 LogFlowFunc(("\n"));
1427
1428 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1429 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1430
1431 if (pThisCC->pDrvTpm)
1432 {
1433 size_t cbCmd = RTTpmReqGetSz((PCTPMREQHDR)&pThis->abCmdResp[0]);
1434 int rc = pThisCC->pDrvTpm->pfnCmdExec(pThisCC->pDrvTpm, pThis->bLoc, &pThis->abCmdResp[0], cbCmd,
1435 &pThis->abCmdResp[0], sizeof(pThis->abCmdResp));
1436 if (RT_SUCCESS(rc))
1437 {
1438 pThis->enmState = DEVTPMSTATE_CMD_COMPLETION;
1439 pThis->offCmdResp = 0;
1440 if (pThis->fCrb)
1441 tpmLocSetIntSts(pThisCC->pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_CRB_LOCALITY_REG_INT_STS_START);
1442 else
1443 tpmLocSetIntSts(pThisCC->pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_FIFO_LOCALITY_REG_INT_STS_DATA_AVAIL | TPM_FIFO_LOCALITY_REG_INT_STS_STS_VALID);
1444 }
1445 else
1446 {
1447 /* Set fatal error. */
1448 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1449 }
1450 }
1451
1452 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1453}
1454
1455
1456/**
1457 * Resets the shared hardware TPM state.
1458 *
1459 * @param pThis Pointer to the shared TPM device.
1460 */
1461static void tpmR3HwReset(PDEVTPM pThis)
1462{
1463 pThis->enmState = DEVTPMSTATE_IDLE;
1464 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
1465 pThis->bmLocReqAcc = 0;
1466 pThis->bmLocSeizedAcc = 0;
1467 pThis->offCmdResp = 0;
1468 RT_ZERO(pThis->abCmdResp);
1469
1470 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aLoc); i++)
1471 {
1472 PDEVTPMLOCALITY pLoc = &pThis->aLoc[i];
1473 pLoc->uRegIntEn = 0;
1474 pLoc->uRegIntSts = 0;
1475 }
1476}
1477
1478
1479/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
1480
1481/**
1482 * @callback_method_impl{FNSSMDEVLIVEEXEC}
1483 */
1484static DECLCALLBACK(int) tpmR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1485{
1486 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1487 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1488 RT_NOREF(uPass);
1489
1490 /* Save the part of the config used for verification purposes when restoring. */
1491 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmio);
1492 pHlp->pfnSSMPutU16( pSSM, pThis->uVenId);
1493 pHlp->pfnSSMPutU16( pSSM, pThis->uDevId);
1494 pHlp->pfnSSMPutU8( pSSM, pThis->bRevId);
1495 pHlp->pfnSSMPutU8( pSSM, pThis->uIrq);
1496 pHlp->pfnSSMPutBool( pSSM, pThis->fLocChangeSup);
1497 pHlp->pfnSSMPutU32( pSSM, (uint32_t)pThis->enmTpmVers);
1498 pHlp->pfnSSMPutU32( pSSM, pThis->cbCmdResp);
1499
1500 return VINF_SSM_DONT_CALL_AGAIN;
1501}
1502
1503
1504/**
1505 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1506 */
1507static DECLCALLBACK(int) tpmR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1508{
1509 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1510 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1511
1512 tpmR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
1513
1514 int rc = pHlp->pfnSSMPutStructEx(pSSM, pThis, sizeof(*pThis), 0 /*fFlags*/, &g_aTpmFields[0], NULL);
1515 AssertRCReturn(rc, rc);
1516
1517 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1518}
1519
1520
1521/**
1522 * @callback_method_impl{FNSSMDEVLOADEXEC}
1523 */
1524static DECLCALLBACK(int) tpmR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1525{
1526 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1527 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1528 uint8_t u8;
1529 uint16_t u16;
1530 uint32_t u32;
1531 bool f;
1532 RTGCPHYS GCPhysMmio;
1533 TPMVERSION enmTpmVers;
1534
1535 Assert(uPass == SSM_PASS_FINAL); RT_NOREF(uPass);
1536 AssertMsgReturn(uVersion == TPM_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1537
1538 /* Verify the config first. */
1539 int rc = pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysMmio);
1540 AssertRCReturn(rc, rc);
1541 if (GCPhysMmio != pThis->GCPhysMmio)
1542 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1543 N_("Config mismatch - saved GCPhysMmio=%#RGp; configured GCPhysMmio=%#RGp"),
1544 GCPhysMmio, pThis->GCPhysMmio);
1545
1546 rc = pHlp->pfnSSMGetU16(pSSM, &u16);
1547 AssertRCReturn(rc, rc);
1548 if (u16 != pThis->uVenId)
1549 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1550 N_("Config mismatch - saved uVenId=%#RX16; configured uVenId=%#RX16"),
1551 u16, pThis->uVenId);
1552
1553 rc = pHlp->pfnSSMGetU16(pSSM, &u16);
1554 AssertRCReturn(rc, rc);
1555 if (u16 != pThis->uDevId)
1556 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1557 N_("Config mismatch - saved uDevId=%#RX16; configured uDevId=%#RX16"),
1558 u16, pThis->uDevId);
1559
1560 rc = pHlp->pfnSSMGetU8(pSSM, &u8);
1561 AssertRCReturn(rc, rc);
1562 if (u8 != pThis->bRevId)
1563 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1564 N_("Config mismatch - saved bRevId=%#RX8; configured bDevId=%#RX8"),
1565 u8, pThis->bRevId);
1566
1567 rc = pHlp->pfnSSMGetU8(pSSM, &u8);
1568 AssertRCReturn(rc, rc);
1569 if (u8 != pThis->uIrq)
1570 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1571 N_("Config mismatch - saved uIrq=%#RX8; configured uIrq=%#RX8"),
1572 u8, pThis->uIrq);
1573
1574 rc = pHlp->pfnSSMGetBool(pSSM, &f);
1575 AssertRCReturn(rc, rc);
1576 if (f != pThis->fLocChangeSup)
1577 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1578 N_("Config mismatch - saved fLocChangeSup=%RTbool; configured fLocChangeSup=%RTbool"),
1579 f, pThis->fLocChangeSup);
1580
1581 rc = pHlp->pfnSSMGetU32(pSSM, (uint32_t *)&enmTpmVers);
1582 AssertRCReturn(rc, rc);
1583 if (enmTpmVers != pThis->enmTpmVers)
1584 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1585 N_("Config mismatch - saved enmTpmVers=%RU32; configured enmTpmVers=%RU32"),
1586 enmTpmVers, pThis->enmTpmVers);
1587
1588 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
1589 AssertRCReturn(rc, rc);
1590 if (u32 != pThis->cbCmdResp)
1591 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1592 N_("Config mismatch - saved cbCmdResp=%RU32; configured cbCmdResp=%RU32"),
1593 u32, pThis->cbCmdResp);
1594
1595 if (uPass == SSM_PASS_FINAL)
1596 {
1597 rc = pHlp->pfnSSMGetStructEx(pSSM, pThis, sizeof(*pThis), 0 /*fFlags*/, &g_aTpmFields[0], NULL);
1598
1599 /* The marker. */
1600 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
1601 AssertRCReturn(rc, rc);
1602 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1603
1604 /* Verify device state sanity. */
1605 AssertLogRelMsgReturn( pThis->enmState > DEVTPMSTATE_INVALID
1606 && pThis->enmState <= DEVTPMSTATE_LAST_VALID,
1607 ("Invalid TPM state loaded from saved state: %#x\n", pThis->enmState),
1608 VERR_SSM_UNEXPECTED_DATA);
1609
1610 AssertLogRelMsgReturn(pThis->offCmdResp <= pThis->cbCmdResp,
1611 ("Invalid TPM command/response buffer offset loaded from saved state: %#x\n", pThis->offCmdResp),
1612 VERR_SSM_UNEXPECTED_DATA);
1613 }
1614
1615 return VINF_SUCCESS;
1616}
1617
1618
1619/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
1620
1621/**
1622 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1623 */
1624static DECLCALLBACK(void *) tpmR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1625{
1626 PDEVTPMCC pThisCC = RT_FROM_MEMBER(pInterface, DEVTPMCC, IBase);
1627 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
1628 //PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMPORT, &pThisCC->ITpmPort);
1629 return NULL;
1630}
1631
1632
1633/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
1634
1635/**
1636 * @interface_method_impl{PDMDEVREG,pfnPowerOn}
1637 */
1638static DECLCALLBACK(void) tpmR3PowerOn(PPDMDEVINS pDevIns)
1639{
1640 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1641 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1642
1643 if (pThisCC->pDrvTpm)
1644 pThis->fEstablishmentSet = pThisCC->pDrvTpm->pfnGetEstablishedFlag(pThisCC->pDrvTpm);
1645}
1646
1647
1648/**
1649 * @interface_method_impl{PDMDEVREG,pfnReset}
1650 */
1651static DECLCALLBACK(void) tpmR3Reset(PPDMDEVINS pDevIns)
1652{
1653 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1654 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1655
1656 tpmR3HwReset(pThis);
1657 if (pThisCC->pDrvTpm)
1658 pThis->fEstablishmentSet = pThisCC->pDrvTpm->pfnGetEstablishedFlag(pThisCC->pDrvTpm);
1659}
1660
1661
1662/**
1663 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1664 */
1665static DECLCALLBACK(int) tpmR3Destruct(PPDMDEVINS pDevIns)
1666{
1667 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1668 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1669
1670 /** @todo */
1671 RT_NOREF(pThis);
1672 return VINF_SUCCESS;
1673}
1674
1675
1676/**
1677 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1678 */
1679static DECLCALLBACK(int) tpmR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1680{
1681 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1682 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1683 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1684 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1685 int rc;
1686
1687 RT_NOREF(iInstance);
1688
1689 pThis->hTpmCmdTask = NIL_PDMTASKHANDLE;
1690
1691 pThisCC->pDevIns = pDevIns;
1692
1693 /* IBase */
1694 pThisCC->IBase.pfnQueryInterface = tpmR3QueryInterface;
1695
1696 /*
1697 * Validate and read the configuration.
1698 */
1699 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq"
1700 "|MmioBase"
1701 "|VendorId"
1702 "|DeviceId"
1703 "|RevisionId"
1704 "|Crb",
1705 "");
1706
1707 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Irq", &pThis->uIrq, 10);
1708 if (RT_FAILURE(rc))
1709 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
1710
1711 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioBase", &pThis->GCPhysMmio, TPM_MMIO_BASE_DEFAULT);
1712 if (RT_FAILURE(rc))
1713 return PDMDEV_SET_ERROR(pDevIns, rc,
1714 N_("Configuration error: Failed to get the \"MmioBase\" value"));
1715
1716 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "VendorId", &pThis->uDevId, TPM_VID_DEFAULT);
1717 if (RT_FAILURE(rc))
1718 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"VendorId\" value"));
1719
1720 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "DeviceId", &pThis->uDevId, TPM_DID_DEFAULT);
1721 if (RT_FAILURE(rc))
1722 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"DeviceId\" value"));
1723
1724 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "RevisionId", &pThis->bRevId, TPM_RID_DEFAULT);
1725 if (RT_FAILURE(rc))
1726 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"RevisionId\" value"));
1727
1728 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Crb", &pThis->fCrb, false);
1729 if (RT_FAILURE(rc))
1730 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Crb\" value"));
1731
1732 /*
1733 * Register the MMIO range, PDM API requests page aligned
1734 * addresses and sizes.
1735 */
1736 rc = PDMDevHlpMmioCreateAndMap(pDevIns, pThis->GCPhysMmio, TPM_MMIO_SIZE, tpmMmioWrite, tpmMmioRead,
1737 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
1738 "TPM MMIO", &pThis->hMmio);
1739 AssertRCReturn(rc, rc);
1740
1741 /*
1742 * Attach any TPM driver below.
1743 */
1744 rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "TPM");
1745 if (RT_SUCCESS(rc))
1746 {
1747 pThisCC->pDrvTpm = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMITPMCONNECTOR);
1748 AssertLogRelMsgReturn(pThisCC->pDrvTpm, ("TPM#%d: Driver is missing the TPM interface.\n", iInstance), VERR_PDM_MISSING_INTERFACE);
1749
1750 pThis->cbCmdResp = RT_MIN(pThisCC->pDrvTpm->pfnGetBufferSize(pThisCC->pDrvTpm), TPM_DATA_BUFFER_SIZE_MAX);
1751 pThis->fLocChangeSup = pThisCC->pDrvTpm->pfnGetLocalityMax(pThisCC->pDrvTpm) > 0;
1752
1753 pThis->enmTpmVers = pThisCC->pDrvTpm->pfnGetVersion(pThisCC->pDrvTpm);
1754 if (pThis->enmTpmVers == TPMVERSION_UNKNOWN)
1755 return PDMDEV_SET_ERROR(pDevIns, VERR_NOT_SUPPORTED, N_("The emulated TPM version is not supported"));
1756 }
1757 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1758 {
1759 pThis->fLocChangeSup = false;
1760 pThis->fEstablishmentSet = false;
1761 pThis->cbCmdResp = TPM_DATA_BUFFER_SIZE_MAX;
1762
1763 pThisCC->pDrvBase = NULL;
1764 pThisCC->pDrvTpm = NULL;
1765 LogRel(("TPM#%d: no unit\n", iInstance));
1766 }
1767 else
1768 AssertLogRelMsgRCReturn(rc, ("TPM#%d: Failed to attach to TPM driver. rc=%Rrc\n", iInstance, rc), rc);
1769
1770 /* Create task for executing requests in ring-3. */
1771 rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "TPMCmdWrk",
1772 tpmR3CmdExecWorker, NULL /*pvUser*/, &pThis->hTpmCmdTask);
1773 AssertRCReturn(rc,rc);
1774
1775 /*
1776 * Saved state.
1777 */
1778 rc = PDMDevHlpSSMRegister3(pDevIns, TPM_SAVED_STATE_VERSION, sizeof(*pThis),
1779 tpmR3LiveExec, tpmR3SaveExec, tpmR3LoadExec);
1780 AssertRCReturn(rc, rc);
1781
1782 tpmR3HwReset(pThis);
1783 return VINF_SUCCESS;
1784}
1785
1786#else /* !IN_RING3 */
1787
1788/**
1789 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1790 */
1791static DECLCALLBACK(int) tpmRZConstruct(PPDMDEVINS pDevIns)
1792{
1793 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1794 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1795
1796 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, tpmMmioWrite, tpmMmioRead, NULL /*pvUser*/);
1797 AssertRCReturn(rc, rc);
1798
1799 return VINF_SUCCESS;
1800}
1801
1802#endif /* !IN_RING3 */
1803
1804/**
1805 * The device registration structure.
1806 */
1807const PDMDEVREG g_DeviceTpm =
1808{
1809 /* .u32Version = */ PDM_DEVREG_VERSION,
1810 /* .uReserved0 = */ 0,
1811 /* .szName = */ "tpm",
1812 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1813 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
1814 /* .cMaxInstances = */ 1,
1815 /* .uSharedVersion = */ 42,
1816 /* .cbInstanceShared = */ sizeof(DEVTPM),
1817 /* .cbInstanceCC = */ sizeof(DEVTPMCC),
1818 /* .cbInstanceRC = */ sizeof(DEVTPMRC),
1819 /* .cMaxPciDevices = */ 0,
1820 /* .cMaxMsixVectors = */ 0,
1821 /* .pszDescription = */ "Trusted Platform Module",
1822#if defined(IN_RING3)
1823 /* .pszRCMod = */ "VBoxDDRC.rc",
1824 /* .pszR0Mod = */ "VBoxDDR0.r0",
1825 /* .pfnConstruct = */ tpmR3Construct,
1826 /* .pfnDestruct = */ tpmR3Destruct,
1827 /* .pfnRelocate = */ NULL,
1828 /* .pfnMemSetup = */ NULL,
1829 /* .pfnPowerOn = */ tpmR3PowerOn,
1830 /* .pfnReset = */ tpmR3Reset,
1831 /* .pfnSuspend = */ NULL,
1832 /* .pfnResume = */ NULL,
1833 /* .pfnAttach = */ NULL,
1834 /* .pfnDetach = */ NULL,
1835 /* .pfnQueryInterface = */ NULL,
1836 /* .pfnInitComplete = */ NULL,
1837 /* .pfnPowerOff = */ NULL,
1838 /* .pfnSoftReset = */ NULL,
1839 /* .pfnReserved0 = */ NULL,
1840 /* .pfnReserved1 = */ NULL,
1841 /* .pfnReserved2 = */ NULL,
1842 /* .pfnReserved3 = */ NULL,
1843 /* .pfnReserved4 = */ NULL,
1844 /* .pfnReserved5 = */ NULL,
1845 /* .pfnReserved6 = */ NULL,
1846 /* .pfnReserved7 = */ NULL,
1847#elif defined(IN_RING0)
1848 /* .pfnEarlyConstruct = */ NULL,
1849 /* .pfnConstruct = */ tpmRZConstruct,
1850 /* .pfnDestruct = */ NULL,
1851 /* .pfnFinalDestruct = */ NULL,
1852 /* .pfnRequest = */ NULL,
1853 /* .pfnReserved0 = */ NULL,
1854 /* .pfnReserved1 = */ NULL,
1855 /* .pfnReserved2 = */ NULL,
1856 /* .pfnReserved3 = */ NULL,
1857 /* .pfnReserved4 = */ NULL,
1858 /* .pfnReserved5 = */ NULL,
1859 /* .pfnReserved6 = */ NULL,
1860 /* .pfnReserved7 = */ NULL,
1861#elif defined(IN_RC)
1862 /* .pfnConstruct = */ tpmRZConstruct,
1863 /* .pfnReserved0 = */ NULL,
1864 /* .pfnReserved1 = */ NULL,
1865 /* .pfnReserved2 = */ NULL,
1866 /* .pfnReserved3 = */ NULL,
1867 /* .pfnReserved4 = */ NULL,
1868 /* .pfnReserved5 = */ NULL,
1869 /* .pfnReserved6 = */ NULL,
1870 /* .pfnReserved7 = */ NULL,
1871#else
1872# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1873#endif
1874 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1875};
1876
1877#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1878
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use