VirtualBox

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

最後變更 在這個檔案是 107812,由 vboxsync 提交於 2 月 前

Devices/Security/DevTpm.cpp: Fix loading older saved states with an incorrect 0 vendor ID which was fixed in r165971, bugref:10777

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 81.7 KB
 
1/* $Id: DevTpm.cpp 107812 2025-01-16 12:33:14Z 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-2024 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.alldomusa.eu.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_LOW 0x68
430/** Locality response buffer address register. */
431#define TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR_HIGH 0x6c
432/** Locality data buffer. */
433#define TPM_CRB_LOCALITY_REG_DATA_BUFFER 0x80
434/** @} */
435
436
437/*********************************************************************************************************************************
438* Structures and Typedefs *
439*********************************************************************************************************************************/
440
441/**
442 * Possible TPM states
443 * (see chapter 5.6.12.1 Figure 3 State Transition Diagram).
444 */
445typedef enum DEVTPMSTATE
446{
447 /** Invalid state, do not use. */
448 DEVTPMSTATE_INVALID = 0,
449 /** Idle state. */
450 DEVTPMSTATE_IDLE,
451 /** Ready to accept command data. */
452 DEVTPMSTATE_READY,
453 /** Command data being transfered. */
454 DEVTPMSTATE_CMD_RECEPTION,
455 /** Command is being executed by the TPM. */
456 DEVTPMSTATE_CMD_EXEC,
457 /** Command has completed and data can be read. */
458 DEVTPMSTATE_CMD_COMPLETION,
459 /** Command is being canceled. */
460 DEVTPMSTATE_CMD_CANCEL,
461 /** TPM ran into a fatal error and is not operational. */
462 DEVTPMSTATE_FATAL_ERROR,
463 /** Last valid state (used for saved state sanity check). */
464 DEVTPMSTATE_LAST_VALID = DEVTPMSTATE_FATAL_ERROR,
465 /** 32bit hack. */
466 DEVTPMSTATE_32BIT_HACK = 0x7fffffff
467} DEVTPMSTATE;
468
469
470/**
471 * Locality state.
472 */
473typedef struct DEVTPMLOCALITY
474{
475 /** The interrupt enable register. */
476 uint32_t uRegIntEn;
477 /** The interrupt status register. */
478 uint32_t uRegIntSts;
479} DEVTPMLOCALITY;
480/** Pointer to a locality state. */
481typedef DEVTPMLOCALITY *PDEVTPMLOCALITY;
482/** Pointer to a const locality state. */
483typedef const DEVTPMLOCALITY *PCDEVTPMLOCALITY;
484
485
486/**
487 * Shared TPM device state.
488 */
489typedef struct DEVTPM
490{
491 /** Base MMIO address of the TPM device. */
492 RTGCPHYS GCPhysMmio;
493 /** The handle of the MMIO region. */
494 IOMMMIOHANDLE hMmio;
495 /** The handle for the ring-3 task. */
496 PDMTASKHANDLE hTpmCmdTask;
497 /** The vendor ID configured. */
498 uint16_t uVenId;
499 /** The device ID configured. */
500 uint16_t uDevId;
501 /** The revision ID configured. */
502 uint8_t bRevId;
503 /** The IRQ value. */
504 uint8_t uIrq;
505 /** Flag whether CRB access mode is used. */
506 bool fCrb;
507 /** Flag whether the TPM driver below supportes other localities than 0. */
508 bool fLocChangeSup;
509 /** Flag whether the establishment bit is set. */
510 bool fEstablishmentSet;
511
512 /** Currently selected locality. */
513 uint8_t bLoc;
514 /** States of the implemented localities. */
515 DEVTPMLOCALITY aLoc[TPM_LOCALITY_COUNT];
516 /** Bitmask of localities having requested access to the TPM. */
517 uint32_t bmLocReqAcc;
518 /** Bitmask of localities having been seized access from the TPM. */
519 uint32_t bmLocSeizedAcc;
520 /** The current state of the TPM. */
521 DEVTPMSTATE enmState;
522 /** The TPM version being emulated. */
523 TPMVERSION enmTpmVers;
524
525 /** Size of the command/response buffer. */
526 uint32_t cbCmdResp;
527 /** Offset into the Command/Response buffer. */
528 uint32_t offCmdResp;
529 /** Command/Response buffer. */
530 uint8_t abCmdResp[TPM_DATA_BUFFER_SIZE_MAX];
531} DEVTPM;
532/** Pointer to the shared TPM device state. */
533typedef DEVTPM *PDEVTPM;
534
535/** The special no current locality selected value. */
536#define TPM_NO_LOCALITY_SELECTED 0xff
537
538
539/**
540 * TPM device state for ring-3.
541 */
542typedef struct DEVTPMR3
543{
544 /** Pointer to the device instance. */
545 PPDMDEVINS pDevIns;
546 /** The base interface for LUN\#0. */
547 PDMIBASE IBase;
548 /** The base interface for LUN\#0. */
549 PDMITPMPORT ITpmPort;
550 /** The base interface below. */
551 R3PTRTYPE(PPDMIBASE) pDrvBase;
552 /** The TPM connector interface below. */
553 R3PTRTYPE(PPDMITPMCONNECTOR) pDrvTpm;
554} DEVTPMR3;
555/** Pointer to the TPM device state for ring-3. */
556typedef DEVTPMR3 *PDEVTPMR3;
557
558
559/**
560 * TPM device state for ring-0.
561 */
562typedef struct DEVTPMR0
563{
564 uint32_t u32Dummy;
565} DEVTPMR0;
566/** Pointer to the TPM device state for ring-0. */
567typedef DEVTPMR0 *PDEVTPMR0;
568
569
570/**
571 * TPM device state for raw-mode.
572 */
573typedef struct DEVTPMRC
574{
575 uint32_t u32Dummy;
576} DEVTPMRC;
577/** Pointer to the TPM device state for raw-mode. */
578typedef DEVTPMRC *PDEVTPMRC;
579
580/** The TPM device state for the current context. */
581typedef CTX_SUFF(DEVTPM) DEVTPMCC;
582/** Pointer to the TPM device state for the current context. */
583typedef CTX_SUFF(PDEVTPM) PDEVTPMCC;
584
585
586#ifndef VBOX_DEVICE_STRUCT_TESTCASE
587
588
589/*********************************************************************************************************************************
590* Global Variables *
591*********************************************************************************************************************************/
592#ifdef IN_RING3
593/**
594 * SSM descriptor table for the TPM structure.
595 */
596static SSMFIELD const g_aTpmFields[] =
597{
598 SSMFIELD_ENTRY(DEVTPM, fEstablishmentSet),
599 SSMFIELD_ENTRY(DEVTPM, bLoc),
600 SSMFIELD_ENTRY(DEVTPM, aLoc[0].uRegIntEn),
601 SSMFIELD_ENTRY(DEVTPM, aLoc[0].uRegIntSts),
602 SSMFIELD_ENTRY(DEVTPM, aLoc[1].uRegIntEn),
603 SSMFIELD_ENTRY(DEVTPM, aLoc[1].uRegIntSts),
604 SSMFIELD_ENTRY(DEVTPM, aLoc[2].uRegIntEn),
605 SSMFIELD_ENTRY(DEVTPM, aLoc[2].uRegIntSts),
606 SSMFIELD_ENTRY(DEVTPM, aLoc[3].uRegIntEn),
607 SSMFIELD_ENTRY(DEVTPM, aLoc[3].uRegIntSts),
608 SSMFIELD_ENTRY(DEVTPM, aLoc[4].uRegIntEn),
609 SSMFIELD_ENTRY(DEVTPM, aLoc[4].uRegIntSts),
610 SSMFIELD_ENTRY(DEVTPM, bmLocReqAcc),
611 SSMFIELD_ENTRY(DEVTPM, bmLocSeizedAcc),
612 SSMFIELD_ENTRY(DEVTPM, enmState),
613 SSMFIELD_ENTRY(DEVTPM, offCmdResp),
614 SSMFIELD_ENTRY(DEVTPM, abCmdResp),
615 SSMFIELD_ENTRY_TERM()
616};
617#endif
618
619
620/**
621 * Sets the IRQ line of the given device to the given state.
622 *
623 * @param pDevIns Pointer to the PDM device instance data.
624 * @param pThis Pointer to the shared TPM device.
625 * @param iLvl The interrupt level to set.
626 */
627DECLINLINE(void) tpmIrqReq(PPDMDEVINS pDevIns, PDEVTPM pThis, int iLvl)
628{
629 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl);
630}
631
632
633/**
634 * Updates the IRQ status of the given locality.
635 *
636 * @param pDevIns Pointer to the PDM device instance data.
637 * @param pThis Pointer to the shared TPM device.
638 * @param pLoc The locality state.
639 */
640static void tpmLocIrqUpdate(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc)
641{
642 if ( (pLoc->uRegIntEn & TPM_CRB_LOCALITY_REG_INT_GLOBAL_ENABLE) /* Aliases with TPM_FIFO_LOCALITY_REG_INT_ENABLE_GLOBAL */
643 && (pLoc->uRegIntEn & pLoc->uRegIntSts))
644 tpmIrqReq(pDevIns, pThis, 1);
645 else
646 tpmIrqReq(pDevIns, pThis, 0);
647}
648
649
650/**
651 * Sets the interrupt status for the given locality, firing an interrupt if necessary.
652 *
653 * @param pDevIns Pointer to the PDM device instance data.
654 * @param pThis Pointer to the shared TPM device.
655 * @param pLoc The locality state.
656 * @param uSts The interrupt status bit to set.
657 */
658static void tpmLocSetIntSts(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc, uint32_t uSts)
659{
660 pLoc->uRegIntSts |= uSts;
661 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
662}
663
664
665/**
666 * Selects the next locality which has requested access.
667 *
668 * @param pDevIns Pointer to the PDM device instance data.
669 * @param pThis Pointer to the shared TPM device.
670 */
671static void tpmLocSelectNext(PPDMDEVINS pDevIns, PDEVTPM pThis)
672{
673 Assert(pThis->bmLocReqAcc);
674 Assert(pThis->bLoc == TPM_NO_LOCALITY_SELECTED);
675 pThis->bLoc = (uint8_t)ASMBitLastSetU32(pThis->bmLocReqAcc) - 1; /* Select one with highest priority. */
676
677 tpmLocSetIntSts(pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_CRB_LOCALITY_REG_INT_STS_LOC_CHANGED);
678}
679
680
681/**
682 * Returns the given locality being accessed from the given TPM MMIO offset.
683 *
684 * @returns Locality number.
685 * @param off The offset into the TPM MMIO region.
686 */
687DECLINLINE(uint8_t) tpmGetLocalityFromOffset(RTGCPHYS off)
688{
689 return off / TPM_LOCALITY_MMIO_SIZE;
690}
691
692
693/**
694 * Returns the given register of a particular locality being accessed from the given TPM MMIO offset.
695 *
696 * @returns Register index being accessed.
697 * @param off The offset into the TPM MMIO region.
698 */
699DECLINLINE(uint32_t) tpmGetRegisterFromOffset(RTGCPHYS off)
700{
701 return off % TPM_LOCALITY_MMIO_SIZE;
702}
703
704
705/**
706 * Read from a FIFO interface register.
707 *
708 * @returns VBox strict status code.
709 * @param pDevIns Pointer to the PDM device instance data.
710 * @param pThis Pointer to the shared TPM device.
711 * @param pLoc The locality state being read from.
712 * @param bLoc The locality index.
713 * @param uReg The register offset being accessed.
714 * @param pu64 Where to store the read data.
715 * @param cb Number of bytes to read.
716 */
717static VBOXSTRICTRC tpmMmioFifoRead(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
718 uint8_t bLoc, uint32_t uReg, uint64_t *pu64, size_t cb)
719{
720 RT_NOREF(pDevIns);
721 VBOXSTRICTRC rc = VINF_SUCCESS;
722
723 /* Special path for the data buffer. */
724 if ( ( ( uReg >= TPM_FIFO_LOCALITY_REG_DATA_FIFO
725 && uReg < TPM_FIFO_LOCALITY_REG_DATA_FIFO + sizeof(uint32_t))
726 || ( uReg >= TPM_FIFO_LOCALITY_REG_XDATA_FIFO
727 && uReg < TPM_FIFO_LOCALITY_REG_XDATA_FIFO + sizeof(uint32_t)))
728 && bLoc == pThis->bLoc
729 && pThis->enmState == DEVTPMSTATE_CMD_COMPLETION)
730 {
731 if (pThis->offCmdResp <= pThis->cbCmdResp - cb)
732 {
733 memcpy(pu64, &pThis->abCmdResp[pThis->offCmdResp], cb);
734 pThis->offCmdResp += (uint32_t)cb;
735 }
736 else
737 memset(pu64, 0xff, cb);
738 return VINF_SUCCESS;
739 }
740
741 uint64_t u64;
742 switch (uReg)
743 {
744 case TPM_FIFO_LOCALITY_REG_ACCESS:
745 u64 = TPM_FIFO_LOCALITY_REG_ACCESS_VALID;
746 if (pThis->bLoc == bLoc)
747 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_ACTIVE;
748 if (pThis->bmLocSeizedAcc & RT_BIT_32(bLoc))
749 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_BEEN_SEIZED;
750 if (pThis->bmLocReqAcc & ~RT_BIT_32(bLoc))
751 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_PENDING_REQUEST;
752 if ( pThis->bLoc != bLoc
753 && pThis->bmLocReqAcc & RT_BIT_32(bLoc))
754 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_REQUEST_USE;
755 if (pThis->fEstablishmentSet)
756 u64 |= TPM_FIFO_LOCALITY_REG_ACCESS_ESTABLISHMENT;
757 break;
758 case TPM_FIFO_LOCALITY_REG_INT_ENABLE:
759 u64 = pLoc->uRegIntEn;
760 break;
761 case TPM_FIFO_LOCALITY_REG_INT_VEC:
762 u64 = pThis->uIrq;
763 break;
764 case TPM_FIFO_LOCALITY_REG_INT_STS:
765 u64 = pLoc->uRegIntSts;
766 break;
767 case TPM_FIFO_LOCALITY_REG_IF_CAP:
768 u64 = TPM_FIFO_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL
769 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_STS_VALID
770 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE
771 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_LOW
772 | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_CMD_RDY
773 | 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? */
774 if (pThis->enmTpmVers == TPMVERSION_1_2)
775 u64 |= TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3);
776 else
777 u64 |= TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3_TPM2);
778 break;
779 case TPM_FIFO_LOCALITY_REG_STS:
780 if (bLoc != pThis->bLoc)
781 {
782 u64 = UINT64_MAX;
783 break;
784 }
785
786 u64 = TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_SET( pThis->enmTpmVers == TPMVERSION_1_2
787 ? TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_1_2
788 : TPM_FIFO_LOCALITY_REG_STS_TPM_FAMILY_2_0)
789 | TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SET(_1K)
790 | TPM_FIFO_LOCALITY_REG_STS_VALID;
791 if (pThis->enmState == DEVTPMSTATE_READY)
792 u64 |= TPM_FIFO_LOCALITY_REG_STS_CMD_RDY;
793 else if (pThis->enmState == DEVTPMSTATE_CMD_RECEPTION) /* When in the command reception state check whether all of the command data has been received. */
794 {
795 if ( pThis->offCmdResp < sizeof(TPMREQHDR)
796 || pThis->offCmdResp < RTTpmReqGetSz((PCTPMREQHDR)&pThis->abCmdResp[0]))
797 u64 |= TPM_FIFO_LOCALITY_REG_STS_EXPECT;
798 }
799 else if (pThis->enmState == DEVTPMSTATE_CMD_COMPLETION) /* Check whether there is more response data available. */
800 {
801 if (pThis->offCmdResp < RTTpmRespGetSz((PCTPMRESPHDR)&pThis->abCmdResp[0]))
802 u64 |= TPM_FIFO_LOCALITY_REG_STS_DATA_AVAIL;
803 }
804 break;
805 case TPM_FIFO_LOCALITY_REG_INTF_ID:
806 u64 = TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_SET(TPM_FIFO_LOCALITY_REG_INTF_ID_IF_VERS_FIFO)
807 | TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B)
808 | TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_GET(TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_FIFO)
809 | TPM_FIFO_LOCALITY_REG_INTF_ID_IF_SEL_LOCK
810 | TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_FIFO;
811 if (pThis->enmTpmVers == TPMVERSION_1_2)
812 u64 |= TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_SET(TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_TIS1_3);
813 else
814 u64 |= TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_SET(TPM_FIFO_LOCALITY_REG_INTF_ID_IF_TYPE_FIFO_TPM20);
815
816 if (pThis->fLocChangeSup) /* Only advertise the locality capability if the driver below supports it. */
817 u64 |= TPM_FIFO_LOCALITY_REG_INTF_ID_CAP_LOCALITY;
818 break;
819 case TPM_FIFO_LOCALITY_REG_DID_VID:
820 u64 = RT_H2BE_U32(RT_MAKE_U32(pThis->uVenId, pThis->uDevId));
821 break;
822 case TPM_FIFO_LOCALITY_REG_RID:
823 u64 = pThis->bRevId;
824 break;
825 default: /* Return ~0. */
826 u64 = UINT64_MAX;
827 break;
828 }
829
830 *pu64 = u64;
831
832 return rc;
833}
834
835
836/**
837 * Read to a FIFO interface register.
838 *
839 * @returns VBox strict status code.
840 * @param pDevIns Pointer to the PDM device instance data.
841 * @param pThis Pointer to the shared TPM device.
842 * @param pLoc The locality state being written to.
843 * @param bLoc The locality index.
844 * @param uReg The register offset being accessed.
845 * @param u64 The value to write.
846 * @param cb Number of bytes to write.
847 */
848static VBOXSTRICTRC tpmMmioFifoWrite(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
849 uint8_t bLoc, uint32_t uReg, uint64_t u64, size_t cb)
850{
851#ifdef IN_RING3
852 PDEVTPMR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMR3);
853#endif
854
855 /* Special path for the data buffer. */
856 if ( ( ( uReg >= TPM_FIFO_LOCALITY_REG_DATA_FIFO
857 && uReg < TPM_FIFO_LOCALITY_REG_DATA_FIFO + sizeof(uint32_t))
858 || ( uReg >= TPM_FIFO_LOCALITY_REG_XDATA_FIFO
859 && uReg < TPM_FIFO_LOCALITY_REG_XDATA_FIFO + sizeof(uint32_t)))
860 && bLoc == pThis->bLoc
861 && ( pThis->enmState == DEVTPMSTATE_READY
862 || pThis->enmState == DEVTPMSTATE_CMD_RECEPTION))
863 {
864 pThis->enmState = DEVTPMSTATE_CMD_RECEPTION;
865 if (pThis->offCmdResp <= pThis->cbCmdResp - cb)
866 {
867 memcpy(&pThis->abCmdResp[pThis->offCmdResp], &u64, cb);
868 pThis->offCmdResp += (uint32_t)cb;
869 }
870 return VINF_SUCCESS;
871 }
872
873 VBOXSTRICTRC rc = VINF_SUCCESS;
874 uint32_t u32 = (uint32_t)u64;
875
876 switch (uReg)
877 {
878 case TPM_FIFO_LOCALITY_REG_ACCESS:
879 u32 &= TPM_FIFO_LOCALITY_REG_ACCESS_WR_MASK;
880 /*
881 * Chapter 5.6.11, 2 states that writing to this register with more than one
882 * bit set to '1' is vendor specific, we decide to ignore such writes to make the logic
883 * below simpler.
884 */
885 if (!RT_IS_POWER_OF_TWO(u32))
886 break;
887
888 /* Seize access only if this locality has a higher priority than the currently selected one. */
889 if ( (u32 & TPM_FIFO_LOCALITY_REG_ACCESS_SEIZE)
890 && pThis->bLoc != TPM_NO_LOCALITY_SELECTED
891 && bLoc > pThis->bLoc)
892 {
893 pThis->bmLocSeizedAcc |= RT_BIT_32(pThis->bLoc);
894 /** @todo Abort command. */
895 pThis->bLoc = bLoc;
896 }
897
898 if ( (u64 & TPM_FIFO_LOCALITY_REG_ACCESS_REQUEST_USE)
899 && !(pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
900 {
901 pThis->bmLocReqAcc |= RT_BIT_32(bLoc);
902 if (pThis->bLoc == TPM_NO_LOCALITY_SELECTED)
903 {
904 pThis->bLoc = bLoc; /* Doesn't fire an interrupt. */
905 pThis->bmLocSeizedAcc &= ~RT_BIT_32(bLoc);
906 }
907 }
908
909 if ( (u64 & TPM_FIFO_LOCALITY_REG_ACCESS_ACTIVE)
910 && (pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
911 {
912 pThis->bmLocReqAcc &= ~RT_BIT_32(bLoc);
913 if (pThis->bLoc == bLoc)
914 {
915 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
916 if (pThis->bmLocReqAcc)
917 tpmLocSelectNext(pDevIns, pThis); /* Select the next locality. */
918 }
919 }
920 break;
921 case TPM_FIFO_LOCALITY_REG_INT_ENABLE:
922 if (bLoc != pThis->bLoc)
923 break;
924 pLoc->uRegIntEn = u32;
925 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
926 break;
927 case TPM_FIFO_LOCALITY_REG_INT_STS:
928 if (bLoc != pThis->bLoc)
929 break;
930 pLoc->uRegIntSts &= ~(u32 & TPM_FIFO_LOCALITY_REG_INT_STS_WR_MASK);
931 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
932 break;
933 case TPM_FIFO_LOCALITY_REG_STS:
934 /*
935 * Writes are ignored completely if the locality being accessed is not the
936 * current active one or if the value has multiple bits set (not a power of two),
937 * see chapter 5.6.12.1.
938 */
939 if ( bLoc != pThis->bLoc
940 || !RT_IS_POWER_OF_TWO(u64))
941 break;
942
943 if ( (u64 & TPM_FIFO_LOCALITY_REG_STS_CMD_RDY)
944 && ( pThis->enmState == DEVTPMSTATE_IDLE
945 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
946 {
947 pThis->enmState = DEVTPMSTATE_READY;
948 pThis->offCmdResp = 0;
949 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_FIFO_LOCALITY_REG_INT_STS_CMD_RDY);
950 }
951
952 if ( (u64 & TPM_FIFO_LOCALITY_REG_STS_TPM_GO)
953 && pThis->enmState == DEVTPMSTATE_CMD_RECEPTION)
954 {
955 pThis->enmState = DEVTPMSTATE_CMD_EXEC;
956 rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hTpmCmdTask);
957 }
958
959 if ( (u64 & TPM_FIFO_LOCALITY_REG_STS_RST_ESTABLISHMENT)
960 && pThis->bLoc >= 3
961 && ( pThis->enmState == DEVTPMSTATE_IDLE
962 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
963 {
964#ifndef IN_RING3
965 rc = VINF_IOM_R3_MMIO_WRITE;
966 break;
967#else
968 if (pThisCC->pDrvTpm)
969 {
970 int rc2 = pThisCC->pDrvTpm->pfnResetEstablishedFlag(pThisCC->pDrvTpm, pThis->bLoc);
971 if (RT_SUCCESS(rc2))
972 pThis->fEstablishmentSet = false;
973 else
974 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
975 }
976 else
977 pThis->fEstablishmentSet = false;
978#endif
979 }
980
981 if ( (u64 & TPM_FIFO_LOCALITY_REG_STS_CMD_CANCEL)
982 && pThis->enmState == DEVTPMSTATE_CMD_EXEC)
983 {
984#ifndef IN_RING3
985 rc = VINF_IOM_R3_MMIO_WRITE;
986 break;
987#else
988 if (pThisCC->pDrvTpm)
989 {
990 pThis->enmState = DEVTPMSTATE_CMD_CANCEL;
991 int rc2 = pThisCC->pDrvTpm->pfnCmdCancel(pThisCC->pDrvTpm);
992 if (RT_FAILURE(rc2))
993 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
994 }
995#endif
996 }
997
998 break;
999 case TPM_FIFO_LOCALITY_REG_INT_VEC:
1000 case TPM_FIFO_LOCALITY_REG_IF_CAP:
1001 case TPM_FIFO_LOCALITY_REG_DID_VID:
1002 case TPM_FIFO_LOCALITY_REG_RID:
1003 default: /* Ignore. */
1004 break;
1005 }
1006
1007 return rc;
1008}
1009
1010
1011/**
1012 * Read from a CRB interface register.
1013 *
1014 * @returns VBox strict status code.
1015 * @param pDevIns Pointer to the PDM device instance data.
1016 * @param pThis Pointer to the shared TPM device.
1017 * @param pLoc The locality state being read from.
1018 * @param bLoc The locality index.
1019 * @param uReg The register offset being accessed.
1020 * @param pu32 Where to store the read data.
1021 */
1022static VBOXSTRICTRC tpmMmioCrbRead(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
1023 uint8_t bLoc, uint32_t uReg, uint32_t *pu32)
1024{
1025 RT_NOREF(pDevIns);
1026
1027 VBOXSTRICTRC rc = VINF_SUCCESS;
1028 uint32_t u32 = UINT32_MAX;
1029 switch (uReg)
1030 {
1031 case TPM_CRB_LOCALITY_REG_STATE:
1032 u32 = TPM_CRB_LOCALITY_REG_STATE_VALID
1033 | ( pThis->bLoc != TPM_NO_LOCALITY_SELECTED
1034 ? TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(pThis->bLoc) | TPM_CRB_LOCALITY_REG_STATE_LOC_ASSIGNED
1035 : TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(0));
1036 if (pThis->fEstablishmentSet)
1037 u32 |= TPM_CRB_LOCALITY_REG_ESTABLISHMENT;
1038 break;
1039 case TPM_CRB_LOCALITY_REG_STS:
1040 u32 = pThis->bLoc == bLoc
1041 ? TPM_CRB_LOCALITY_REG_STS_GRANTED
1042 : 0;
1043 u32 |= pThis->bmLocSeizedAcc & RT_BIT_32(bLoc)
1044 ? TPM_CRB_LOCALITY_REG_STS_SEIZED
1045 : 0;
1046 break;
1047 case TPM_CRB_LOCALITY_REG_INTF_ID:
1048 u32 = TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_CRB)
1049 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_CRB)
1050 | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B)
1051 | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB
1052 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_GET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_CRB)
1053 | TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_LOCK
1054 | TPM_CRB_LOCALITY_REG_INTF_ID_RID_SET(pThis->bRevId);
1055
1056 if (pThis->fLocChangeSup) /* Only advertise the locality capability if the driver below supports it. */
1057 u32 |= TPM_CRB_LOCALITY_REG_INTF_ID_CAP_LOCALITY;
1058
1059 break;
1060 case TPM_CRB_LOCALITY_REG_INTF_ID + 4:
1061 u32 = (uint32_t)pThis->uVenId | ((uint32_t)pThis->uDevId) << 16;
1062 break;
1063 case TPM_CRB_LOCALITY_REG_CTRL_REQ:
1064 if (bLoc != pThis->bLoc)
1065 break;
1066 /*
1067 * Command ready and go idle are always 0 upon read
1068 * as we don't need time to transition to this state
1069 * when written by the guest.
1070 */
1071 u32 = 0;
1072 break;
1073 case TPM_CRB_LOCALITY_REG_CTRL_STS:
1074 if (bLoc != pThis->bLoc)
1075 break;
1076 if (pThis->enmState == DEVTPMSTATE_FATAL_ERROR)
1077 u32 = TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_FATAL_ERR;
1078 else if (pThis->enmState == DEVTPMSTATE_IDLE)
1079 u32 = TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_IDLE;
1080 else
1081 u32 = 0;
1082 break;
1083 case TPM_CRB_LOCALITY_REG_CTRL_CANCEL:
1084 if (bLoc != pThis->bLoc)
1085 break;
1086 if (pThis->enmState == DEVTPMSTATE_CMD_CANCEL)
1087 u32 = 0x1;
1088 else
1089 u32 = 0;
1090 break;
1091 case TPM_CRB_LOCALITY_REG_CTRL_START:
1092 if (bLoc != pThis->bLoc)
1093 break;
1094 if (pThis->enmState == DEVTPMSTATE_CMD_EXEC)
1095 u32 = 0x1;
1096 else
1097 u32 = 0;
1098 break;
1099 case TPM_CRB_LOCALITY_REG_INT_ENABLE:
1100 u32 = pLoc->uRegIntEn;
1101 break;
1102 case TPM_CRB_LOCALITY_REG_INT_STS:
1103 u32 = pLoc->uRegIntSts;
1104 break;
1105 case TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR:
1106 u32 = pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER;
1107 break;
1108 case TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR:
1109 u32 = (pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER) >> 32;
1110 break;
1111 case TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ:
1112 case TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ:
1113 u32 = pThis->cbCmdResp;
1114 break;
1115 case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR_LOW:
1116 u32 = pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER;
1117 break;
1118 case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR_HIGH:
1119 u32 = (pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER) >> 32;
1120 break;
1121 case TPM_CRB_LOCALITY_REG_CTRL: /* Writeonly */
1122 u32 = 0;
1123 break;
1124 case TPM_CRB_LOCALITY_REG_CTRL_EXT:
1125 default:
1126 break; /* Return ~0 */
1127 }
1128
1129 *pu32 = u32;
1130 return rc;
1131}
1132
1133
1134/**
1135 * Write to a CRB interface register.
1136 *
1137 * @returns VBox strict status code.
1138 * @param pDevIns Pointer to the PDM device instance data.
1139 * @param pThis Pointer to the shared TPM device.
1140 * @param pLoc The locality state being written to.
1141 * @param bLoc The locality index.
1142 * @param uReg The register offset being accessed.
1143 * @param u32 The value to write.
1144 */
1145static VBOXSTRICTRC tpmMmioCrbWrite(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
1146 uint8_t bLoc, uint32_t uReg, uint32_t u32)
1147{
1148#ifdef IN_RING3
1149 PDEVTPMR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMR3);
1150#endif
1151
1152 VBOXSTRICTRC rc = VINF_SUCCESS;
1153 switch (uReg)
1154 {
1155 case TPM_CRB_LOCALITY_REG_CTRL:
1156 {
1157 /* See chapter 6.5.3.2.2.1. */
1158 if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_RST_ESTABLISHMENT)
1159 && pThis->bLoc >= 3
1160 && ( pThis->enmState == DEVTPMSTATE_IDLE
1161 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
1162 {
1163#ifndef IN_RING3
1164 rc = VINF_IOM_R3_MMIO_WRITE;
1165 break;
1166#else
1167 if (pThisCC->pDrvTpm)
1168 {
1169 int rc2 = pThisCC->pDrvTpm->pfnResetEstablishedFlag(pThisCC->pDrvTpm, pThis->bLoc);
1170 if (RT_SUCCESS(rc2))
1171 pThis->fEstablishmentSet = false;
1172 else
1173 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1174 }
1175 else
1176 pThis->fEstablishmentSet = false;
1177#endif
1178 }
1179
1180 /*
1181 * The following three checks should be mutually exclusive as the writer shouldn't
1182 * request, relinquish and seize access in the same write.
1183 */
1184 /* Seize access only if this locality has a higher priority than the currently selected one. */
1185 if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_SEIZE)
1186 && pThis->bLoc != TPM_NO_LOCALITY_SELECTED
1187 && bLoc > pThis->bLoc)
1188 {
1189 if (pThis->enmState == DEVTPMSTATE_CMD_EXEC)
1190 {
1191#ifndef IN_RING3
1192 rc = VINF_IOM_R3_MMIO_WRITE;
1193 break;
1194#else
1195 pThis->enmState = DEVTPMSTATE_CMD_CANCEL;
1196 if (pThisCC->pDrvTpm)
1197 {
1198 int rc2 = pThisCC->pDrvTpm->pfnCmdCancel(pThisCC->pDrvTpm);
1199 if (RT_FAILURE(rc2))
1200 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1201 else
1202 {
1203 pThis->enmState = DEVTPMSTATE_CMD_COMPLETION;
1204 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_START);
1205 }
1206 }
1207#endif
1208 }
1209
1210 pThis->bmLocSeizedAcc |= RT_BIT_32(pThis->bLoc);
1211 pThis->bLoc = bLoc;
1212 }
1213
1214 if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_ACCESS)
1215 && !(pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
1216 {
1217 pThis->bmLocReqAcc |= RT_BIT_32(bLoc);
1218 if (pThis->bLoc == TPM_NO_LOCALITY_SELECTED)
1219 {
1220 pThis->bLoc = bLoc; /* Doesn't fire an interrupt. */
1221 pThis->bmLocSeizedAcc &= ~RT_BIT_32(bLoc);
1222 }
1223 }
1224
1225 if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_RELINQUISH)
1226 && (pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
1227 {
1228 pThis->bmLocReqAcc &= ~RT_BIT_32(bLoc);
1229 if (pThis->bLoc == bLoc)
1230 {
1231 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
1232 if (pThis->bmLocReqAcc)
1233 tpmLocSelectNext(pDevIns, pThis); /* Select the next locality. */
1234 }
1235 }
1236 break;
1237 }
1238 case TPM_CRB_LOCALITY_REG_CTRL_REQ:
1239 if ( bLoc != pThis->bLoc
1240 || !RT_IS_POWER_OF_TWO(u32)) /* Ignore if multiple bits are set. */
1241 break;
1242 if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_CMD_RDY)
1243 && ( pThis->enmState == DEVTPMSTATE_IDLE
1244 || pThis->enmState == DEVTPMSTATE_CMD_COMPLETION))
1245 {
1246 pThis->enmState = DEVTPMSTATE_READY;
1247 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_CMD_RDY);
1248 }
1249 else if ( (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_IDLE)
1250 && pThis->enmState != DEVTPMSTATE_CMD_EXEC)
1251 {
1252 /* Invalidate the command/response buffer. */
1253 RT_ZERO(pThis->abCmdResp);
1254 pThis->offCmdResp = 0;
1255 pThis->enmState = DEVTPMSTATE_IDLE;
1256 }
1257 break;
1258 case TPM_CRB_LOCALITY_REG_CTRL_CANCEL:
1259 if (bLoc != pThis->bLoc)
1260 break;
1261 if ( pThis->enmState == DEVTPMSTATE_CMD_EXEC
1262 && u32 == 0x1)
1263 {
1264#ifndef IN_RING3
1265 rc = VINF_IOM_R3_MMIO_WRITE;
1266 break;
1267#else
1268 pThis->enmState = DEVTPMSTATE_CMD_CANCEL;
1269 if (pThisCC->pDrvTpm)
1270 {
1271 int rc2 = pThisCC->pDrvTpm->pfnCmdCancel(pThisCC->pDrvTpm);
1272 if (RT_FAILURE(rc2))
1273 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1274 else
1275 {
1276 pThis->enmState = DEVTPMSTATE_CMD_COMPLETION;
1277 tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_START);
1278 }
1279 }
1280#endif
1281 }
1282 break;
1283 case TPM_CRB_LOCALITY_REG_CTRL_START:
1284 if (bLoc != pThis->bLoc)
1285 break;
1286 if ( pThis->enmState == DEVTPMSTATE_CMD_RECEPTION
1287 && u32 == 0x1)
1288 {
1289 pThis->enmState = DEVTPMSTATE_CMD_EXEC;
1290 rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hTpmCmdTask);
1291 }
1292 break;
1293 case TPM_CRB_LOCALITY_REG_INT_ENABLE:
1294 pLoc->uRegIntEn = u32;
1295 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
1296 break;
1297 case TPM_CRB_LOCALITY_REG_INT_STS:
1298 pLoc->uRegIntSts &= ~u32;
1299 tpmLocIrqUpdate(pDevIns, pThis, pLoc);
1300 break;
1301 case TPM_CRB_LOCALITY_REG_CTRL_EXT: /* Not implemented. */
1302 case TPM_CRB_LOCALITY_REG_STATE: /* Readonly */
1303 case TPM_CRB_LOCALITY_REG_INTF_ID:
1304 case TPM_CRB_LOCALITY_REG_CTRL_STS:
1305 case TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR:
1306 case TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR:
1307 case TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ:
1308 case TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ:
1309 case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR_LOW:
1310 case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR_HIGH:
1311 default: /* Ignore. */
1312 break;
1313 }
1314
1315 return rc;
1316}
1317
1318
1319/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
1320
1321/**
1322 * @callback_method_impl{FNIOMMMIONEWREAD}
1323 */
1324static DECLCALLBACK(VBOXSTRICTRC) tpmMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1325{
1326 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1327 RT_NOREF(pvUser);
1328
1329 AssertReturn(cb <= sizeof(uint64_t), VERR_INTERNAL_ERROR);
1330
1331 VBOXSTRICTRC rc = VINF_SUCCESS;
1332
1333 if (pThis->fCrb)
1334 {
1335 Assert(!(off & (cb - 1)));
1336
1337 uint32_t uReg = tpmGetRegisterFromOffset(off);
1338 uint8_t bLoc = tpmGetLocalityFromOffset(off);
1339 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
1340
1341 /* Special path for the data buffer. */
1342 if ( uReg >= TPM_CRB_LOCALITY_REG_DATA_BUFFER
1343 && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + pThis->cbCmdResp
1344 && bLoc == pThis->bLoc
1345 && pThis->enmState == DEVTPMSTATE_CMD_COMPLETION)
1346 {
1347 memcpy(pv, &pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], cb);
1348 return VINF_SUCCESS;
1349 }
1350
1351 /* The register space is divided into 32-bit parts. */
1352 Assert(cb <= sizeof(uint64_t));
1353 uint32_t uRegAligned = uReg & ~UINT32_C(0x3);
1354 uint32_t cBitsShift = uReg & UINT32_C(0x3);
1355 uint32_t u32;
1356 rc = tpmMmioCrbRead(pDevIns, pThis, pLoc, bLoc, uRegAligned, &u32);
1357 if (rc == VINF_SUCCESS)
1358 {
1359 switch (cb)
1360 {
1361 case 1: *(uint8_t *)pv = (uint8_t)(u32 >> cBitsShift); break;
1362 case 2: *(uint16_t *)pv = (uint16_t)(u32 >> cBitsShift); break;
1363 case 4:
1364 case 8: *(uint32_t *)pv = u32; break;
1365 default: AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR);
1366 }
1367
1368 LogFlowFunc((": %RGp %#x %.*Rhxs (uRegAligned=%#x cBitsShift=%#x u32=%#RX32)\n", off, cb, cb, pv, uRegAligned, cBitsShift, u32));
1369
1370 if (cb == sizeof(uint64_t))
1371 {
1372 rc = tpmMmioCrbRead(pDevIns, pThis, pLoc, bLoc, uRegAligned + 4, &((uint32_t *)pv)[1]);
1373 LogFlowFunc((": %RGp %#x %.*Rhxs (uRegAligned=%#x u32=%#RX32)\n",
1374 off, cb, cb, pv, uRegAligned + 4, *((const uint32_t *)pv + 1)));
1375 }
1376 }
1377 }
1378 else
1379 {
1380 uint64_t u64;
1381
1382 RTGCPHYS offAligned = off & ~UINT64_C(0x3);
1383 uint8_t cBitsShift = (off & 0x3) * 8;
1384
1385 uint32_t uReg = tpmGetRegisterFromOffset(offAligned);
1386 uint8_t bLoc = tpmGetLocalityFromOffset(offAligned);
1387 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
1388
1389 rc = tpmMmioFifoRead(pDevIns, pThis, pLoc, bLoc, uReg, &u64, cb);
1390 LogFlowFunc((": %RGp %#x %#llx\n", off, cb, u64));
1391
1392 if (rc == VINF_SUCCESS)
1393 {
1394 switch (cb)
1395 {
1396 case 1: *(uint8_t *)pv = (uint8_t)(u64 >> cBitsShift); break;
1397 case 2: *(uint16_t *)pv = (uint16_t)(u64 >> cBitsShift); break;
1398 case 4: *(uint32_t *)pv = (uint32_t)(u64 >> cBitsShift); break;
1399 case 8: *(uint64_t *)pv = u64; break;
1400 default: AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR);
1401 }
1402 }
1403 }
1404
1405 return rc;
1406}
1407
1408
1409/**
1410 * @callback_method_impl{FNIOMMMIONEWWRITE}
1411 */
1412static DECLCALLBACK(VBOXSTRICTRC) tpmMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1413{
1414 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1415 RT_NOREF(pvUser);
1416
1417 Assert(!(off & (cb - 1)));
1418
1419 VBOXSTRICTRC rc = VINF_SUCCESS;
1420 uint32_t uReg = tpmGetRegisterFromOffset(off);
1421 uint8_t bLoc = tpmGetLocalityFromOffset(off);
1422 PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
1423
1424 if (pThis->fCrb)
1425 {
1426 /* Special path for the data buffer. */
1427 if ( uReg >= TPM_CRB_LOCALITY_REG_DATA_BUFFER
1428 && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + pThis->cbCmdResp
1429 && bLoc == pThis->bLoc
1430 && ( pThis->enmState == DEVTPMSTATE_READY
1431 || pThis->enmState == DEVTPMSTATE_CMD_RECEPTION))
1432 {
1433 pThis->enmState = DEVTPMSTATE_CMD_RECEPTION;
1434 memcpy(&pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], pv, cb);
1435 return VINF_SUCCESS;
1436 }
1437
1438 /* The register space is divided into 32-bit parts. */
1439 Assert(cb <= sizeof(uint64_t));
1440 uint32_t uRegAligned = uReg & ~UINT32_C(0x3);
1441 uint32_t cBitsShift = uReg & UINT32_C(0x3);
1442 uint32_t u32;
1443
1444 LogFlowFunc((": %RGp %#x %.*Rhxs (uRegAligned=%#x cBitsShift=%#x)\n", off, cb, cb, pv, uRegAligned, cBitsShift));
1445
1446 switch (cb)
1447 {
1448 case 1:
1449 {
1450 /* Read current content and merge with the written data. */
1451 uint32_t u32Read;
1452 rc = tpmMmioCrbRead(pDevIns, pThis, pLoc, bLoc, uRegAligned, &u32Read);
1453 if (rc != VINF_SUCCESS)
1454 return rc;
1455 u32 = u32Read & ~((uint32_t)UINT8_MAX << cBitsShift);
1456 u32 |= ((uint32_t)*(const uint8_t *)pv) << cBitsShift;
1457 break;
1458 }
1459 case 2:
1460 {
1461 /* Read current content and merge with the written data. */
1462 uint32_t u32Read;
1463 rc = tpmMmioCrbRead(pDevIns, pThis, pLoc, bLoc, uRegAligned, &u32Read);
1464 if (rc != VINF_SUCCESS)
1465 return rc;
1466 u32 = u32Read & ~((uint32_t)UINT16_MAX << cBitsShift);
1467 u32 |= ((uint32_t)*(const uint16_t *)pv) << cBitsShift;
1468 break;
1469 }
1470 case 4:
1471 case 8:
1472 u32 = *(const uint32_t *)pv;
1473 break;
1474 default: AssertFailedReturn(VERR_INTERNAL_ERROR);
1475 }
1476
1477 rc = tpmMmioCrbWrite(pDevIns, pThis, pLoc, bLoc, uRegAligned, u32);
1478 if ( rc == VINF_SUCCESS
1479 && cb == sizeof(uint64_t))
1480 rc = tpmMmioCrbWrite(pDevIns, pThis, pLoc, bLoc, uRegAligned + 4, *((uint32_t *)pv + 1));
1481 }
1482 else
1483 {
1484 uint64_t u64;
1485 switch (cb)
1486 {
1487 case 1: u64 = *(const uint8_t *)pv; break;
1488 case 2: u64 = *(const uint16_t *)pv; break;
1489 case 4: u64 = *(const uint32_t *)pv; break;
1490 case 8: u64 = *(const uint64_t *)pv; break;
1491 default: AssertFailedReturn(VERR_INTERNAL_ERROR);
1492 }
1493
1494 LogFlowFunc((": %RGp %#llx\n", off, u64));
1495 rc = tpmMmioFifoWrite(pDevIns, pThis, pLoc, bLoc, uReg, u64, cb);
1496 }
1497
1498 return rc;
1499}
1500
1501
1502#ifdef IN_RING3
1503
1504/**
1505 * @callback_method_impl{FNPDMTASKDEV, Execute a command in ring-3}
1506 */
1507static DECLCALLBACK(void) tpmR3CmdExecWorker(PPDMDEVINS pDevIns, void *pvUser)
1508{
1509 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1510 PDEVTPMR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMR3);
1511 RT_NOREF(pvUser);
1512 LogFlowFunc(("\n"));
1513
1514 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1515 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1516
1517 if (pThisCC->pDrvTpm)
1518 {
1519 size_t cbCmd = RTTpmReqGetSz((PCTPMREQHDR)&pThis->abCmdResp[0]);
1520 int rc = pThisCC->pDrvTpm->pfnCmdExec(pThisCC->pDrvTpm, pThis->bLoc, &pThis->abCmdResp[0], cbCmd,
1521 &pThis->abCmdResp[0], sizeof(pThis->abCmdResp));
1522 if (RT_SUCCESS(rc))
1523 {
1524 pThis->enmState = DEVTPMSTATE_CMD_COMPLETION;
1525 pThis->offCmdResp = 0;
1526 if (pThis->fCrb)
1527 tpmLocSetIntSts(pThisCC->pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_CRB_LOCALITY_REG_INT_STS_START);
1528 else
1529 tpmLocSetIntSts(pThisCC->pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_FIFO_LOCALITY_REG_INT_STS_DATA_AVAIL | TPM_FIFO_LOCALITY_REG_INT_STS_STS_VALID);
1530 }
1531 else
1532 {
1533 /* Set fatal error. */
1534 pThis->enmState = DEVTPMSTATE_FATAL_ERROR;
1535 }
1536 }
1537
1538 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1539}
1540
1541
1542/**
1543 * Resets the shared hardware TPM state.
1544 *
1545 * @param pThis Pointer to the shared TPM device.
1546 */
1547static void tpmR3HwReset(PDEVTPM pThis)
1548{
1549 pThis->enmState = DEVTPMSTATE_IDLE;
1550 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
1551 pThis->bmLocReqAcc = 0;
1552 pThis->bmLocSeizedAcc = 0;
1553 pThis->offCmdResp = 0;
1554 RT_ZERO(pThis->abCmdResp);
1555
1556 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aLoc); i++)
1557 {
1558 PDEVTPMLOCALITY pLoc = &pThis->aLoc[i];
1559 pLoc->uRegIntEn = 0;
1560 pLoc->uRegIntSts = 0;
1561 }
1562}
1563
1564
1565/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
1566
1567/**
1568 * @callback_method_impl{FNSSMDEVLIVEEXEC}
1569 */
1570static DECLCALLBACK(int) tpmR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1571{
1572 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1573 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1574 RT_NOREF(uPass);
1575
1576 /* Save the part of the config used for verification purposes when restoring. */
1577 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmio);
1578 pHlp->pfnSSMPutU16( pSSM, pThis->uVenId);
1579 pHlp->pfnSSMPutU16( pSSM, pThis->uDevId);
1580 pHlp->pfnSSMPutU8( pSSM, pThis->bRevId);
1581 pHlp->pfnSSMPutU8( pSSM, pThis->uIrq);
1582 pHlp->pfnSSMPutBool( pSSM, pThis->fLocChangeSup);
1583 pHlp->pfnSSMPutU32( pSSM, (uint32_t)pThis->enmTpmVers);
1584 pHlp->pfnSSMPutU32( pSSM, pThis->cbCmdResp);
1585
1586 return VINF_SSM_DONT_CALL_AGAIN;
1587}
1588
1589
1590/**
1591 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1592 */
1593static DECLCALLBACK(int) tpmR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1594{
1595 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1596 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1597
1598 tpmR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
1599
1600 int rc = pHlp->pfnSSMPutStructEx(pSSM, pThis, sizeof(*pThis), 0 /*fFlags*/, &g_aTpmFields[0], NULL);
1601 AssertRCReturn(rc, rc);
1602
1603 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1604}
1605
1606
1607/**
1608 * @callback_method_impl{FNSSMDEVLOADEXEC}
1609 */
1610static DECLCALLBACK(int) tpmR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1611{
1612 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1613 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1614 uint8_t u8;
1615 uint16_t u16;
1616 uint32_t u32;
1617 bool f;
1618 RTGCPHYS GCPhysMmio;
1619 TPMVERSION enmTpmVers;
1620
1621 Assert(uPass == SSM_PASS_FINAL); RT_NOREF(uPass);
1622 AssertMsgReturn(uVersion == TPM_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1623
1624 /* Verify the config first. */
1625 int rc = pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysMmio);
1626 AssertRCReturn(rc, rc);
1627 if (GCPhysMmio != pThis->GCPhysMmio)
1628 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1629 N_("Config mismatch - saved GCPhysMmio=%#RGp; configured GCPhysMmio=%#RGp"),
1630 GCPhysMmio, pThis->GCPhysMmio);
1631
1632 rc = pHlp->pfnSSMGetU16(pSSM, &u16);
1633 AssertRCReturn(rc, rc);
1634 /*
1635 * r165971 fixes setting the proper vendor ID in the constructor.
1636 * In older saved states it was always 0 which would made this check fail.
1637 * So just ignore any mismatches if the loaded vendor ID is 0.
1638 */
1639 if ( u16 != pThis->uVenId
1640 && u16 != 0)
1641 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1642 N_("Config mismatch - saved uVenId=%#RX16; configured uVenId=%#RX16"),
1643 u16, pThis->uVenId);
1644
1645 rc = pHlp->pfnSSMGetU16(pSSM, &u16);
1646 AssertRCReturn(rc, rc);
1647 if (u16 != pThis->uDevId)
1648 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1649 N_("Config mismatch - saved uDevId=%#RX16; configured uDevId=%#RX16"),
1650 u16, pThis->uDevId);
1651
1652 rc = pHlp->pfnSSMGetU8(pSSM, &u8);
1653 AssertRCReturn(rc, rc);
1654 if (u8 != pThis->bRevId)
1655 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1656 N_("Config mismatch - saved bRevId=%#RX8; configured bDevId=%#RX8"),
1657 u8, pThis->bRevId);
1658
1659 rc = pHlp->pfnSSMGetU8(pSSM, &u8);
1660 AssertRCReturn(rc, rc);
1661 if (u8 != pThis->uIrq)
1662 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1663 N_("Config mismatch - saved uIrq=%#RX8; configured uIrq=%#RX8"),
1664 u8, pThis->uIrq);
1665
1666 rc = pHlp->pfnSSMGetBool(pSSM, &f);
1667 AssertRCReturn(rc, rc);
1668 if (f != pThis->fLocChangeSup)
1669 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1670 N_("Config mismatch - saved fLocChangeSup=%RTbool; configured fLocChangeSup=%RTbool"),
1671 f, pThis->fLocChangeSup);
1672
1673 rc = pHlp->pfnSSMGetU32(pSSM, (uint32_t *)&enmTpmVers);
1674 AssertRCReturn(rc, rc);
1675 if (enmTpmVers != pThis->enmTpmVers)
1676 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1677 N_("Config mismatch - saved enmTpmVers=%RU32; configured enmTpmVers=%RU32"),
1678 enmTpmVers, pThis->enmTpmVers);
1679
1680 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
1681 AssertRCReturn(rc, rc);
1682 if (u32 != pThis->cbCmdResp)
1683 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
1684 N_("Config mismatch - saved cbCmdResp=%RU32; configured cbCmdResp=%RU32"),
1685 u32, pThis->cbCmdResp);
1686
1687 if (uPass == SSM_PASS_FINAL)
1688 {
1689 rc = pHlp->pfnSSMGetStructEx(pSSM, pThis, sizeof(*pThis), 0 /*fFlags*/, &g_aTpmFields[0], NULL);
1690 AssertRCReturn(rc, rc);
1691
1692 /* The marker. */
1693 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
1694 AssertRCReturn(rc, rc);
1695 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1696
1697 /* Verify device state sanity. */
1698 AssertLogRelMsgReturn( pThis->enmState > DEVTPMSTATE_INVALID
1699 && pThis->enmState <= DEVTPMSTATE_LAST_VALID,
1700 ("Invalid TPM state loaded from saved state: %#x\n", pThis->enmState),
1701 VERR_SSM_UNEXPECTED_DATA);
1702
1703 AssertLogRelMsgReturn(pThis->offCmdResp <= pThis->cbCmdResp,
1704 ("Invalid TPM command/response buffer offset loaded from saved state: %#x\n", pThis->offCmdResp),
1705 VERR_SSM_UNEXPECTED_DATA);
1706 }
1707
1708 return VINF_SUCCESS;
1709}
1710
1711
1712/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
1713
1714/**
1715 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1716 */
1717static DECLCALLBACK(void *) tpmR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1718{
1719 PDEVTPMCC pThisCC = RT_FROM_MEMBER(pInterface, DEVTPMCC, IBase);
1720 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
1721 PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMPORT, &pThisCC->ITpmPort);
1722 return NULL;
1723}
1724
1725
1726/* -=-=-=-=-=-=-=-=- PDMITPMPORT -=-=-=-=-=-=-=-=- */
1727
1728/**
1729 * @interface_method_impl{PDMITPMPORT,pfnGetMaxBufferSize}
1730 */
1731static DECLCALLBACK(uint32_t) tpmR3TpmPortGetMaxBufferSize(PPDMITPMPORT pInterface)
1732{
1733 RT_NOREF(pInterface);
1734 return TPM_DATA_BUFFER_SIZE_MAX;
1735}
1736
1737
1738/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
1739
1740/**
1741 * @interface_method_impl{PDMDEVREG,pfnPowerOn}
1742 */
1743static DECLCALLBACK(void) tpmR3PowerOn(PPDMDEVINS pDevIns)
1744{
1745 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1746 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1747
1748 if (pThisCC->pDrvTpm)
1749 pThis->fEstablishmentSet = pThisCC->pDrvTpm->pfnGetEstablishedFlag(pThisCC->pDrvTpm);
1750}
1751
1752
1753/**
1754 * @interface_method_impl{PDMDEVREG,pfnReset}
1755 */
1756static DECLCALLBACK(void) tpmR3Reset(PPDMDEVINS pDevIns)
1757{
1758 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1759 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1760
1761 tpmR3HwReset(pThis);
1762 if (pThisCC->pDrvTpm)
1763 pThis->fEstablishmentSet = pThisCC->pDrvTpm->pfnGetEstablishedFlag(pThisCC->pDrvTpm);
1764}
1765
1766
1767/**
1768 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1769 */
1770static DECLCALLBACK(int) tpmR3Destruct(PPDMDEVINS pDevIns)
1771{
1772 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1773 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1774
1775 /** @todo */
1776 RT_NOREF(pThis);
1777 return VINF_SUCCESS;
1778}
1779
1780
1781/**
1782 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1783 */
1784static DECLCALLBACK(int) tpmR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1785{
1786 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1787 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1788 PDEVTPMCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
1789 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1790 int rc;
1791
1792 RT_NOREF(iInstance);
1793
1794 pThis->hTpmCmdTask = NIL_PDMTASKHANDLE;
1795
1796 pThisCC->pDevIns = pDevIns;
1797
1798 /* IBase */
1799 pThisCC->IBase.pfnQueryInterface = tpmR3QueryInterface;
1800
1801 /* ITpmPort */
1802 pThisCC->ITpmPort.pfnGetMaxBufferSize = tpmR3TpmPortGetMaxBufferSize;
1803
1804
1805 /*
1806 * Validate and read the configuration.
1807 */
1808 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq"
1809 "|MmioBase"
1810 "|VendorId"
1811 "|DeviceId"
1812 "|RevisionId"
1813 "|Crb",
1814 "");
1815
1816 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Irq", &pThis->uIrq, 10);
1817 if (RT_FAILURE(rc))
1818 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
1819
1820 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioBase", &pThis->GCPhysMmio, TPM_MMIO_BASE_DEFAULT);
1821 if (RT_FAILURE(rc))
1822 return PDMDEV_SET_ERROR(pDevIns, rc,
1823 N_("Configuration error: Failed to get the \"MmioBase\" value"));
1824
1825 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "VendorId", &pThis->uVenId, TPM_VID_DEFAULT);
1826 if (RT_FAILURE(rc))
1827 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"VendorId\" value"));
1828
1829 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "DeviceId", &pThis->uDevId, TPM_DID_DEFAULT);
1830 if (RT_FAILURE(rc))
1831 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"DeviceId\" value"));
1832
1833 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "RevisionId", &pThis->bRevId, TPM_RID_DEFAULT);
1834 if (RT_FAILURE(rc))
1835 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"RevisionId\" value"));
1836
1837 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Crb", &pThis->fCrb, false);
1838 if (RT_FAILURE(rc))
1839 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Crb\" value"));
1840
1841 /*
1842 * Register the MMIO range, PDM API requests page aligned
1843 * addresses and sizes.
1844 */
1845 rc = PDMDevHlpMmioCreateAndMap(pDevIns, pThis->GCPhysMmio, TPM_MMIO_SIZE, tpmMmioWrite, tpmMmioRead,
1846 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
1847 "TPM MMIO", &pThis->hMmio);
1848 AssertRCReturn(rc, rc);
1849
1850 /*
1851 * Attach any TPM driver below.
1852 */
1853 rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "TPM");
1854 if (RT_SUCCESS(rc))
1855 {
1856 pThisCC->pDrvTpm = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMITPMCONNECTOR);
1857 AssertLogRelMsgReturn(pThisCC->pDrvTpm, ("TPM#%d: Driver is missing the TPM interface.\n", iInstance), VERR_PDM_MISSING_INTERFACE);
1858
1859 uint32_t cbBufDrv = pThisCC->pDrvTpm->pfnGetBufferSize(pThisCC->pDrvTpm);
1860 pThis->cbCmdResp = RT_MIN(cbBufDrv, TPM_DATA_BUFFER_SIZE_MAX);
1861 pThis->fLocChangeSup = pThisCC->pDrvTpm->pfnGetLocalityMax(pThisCC->pDrvTpm) > 0;
1862
1863 pThis->enmTpmVers = pThisCC->pDrvTpm->pfnGetVersion(pThisCC->pDrvTpm);
1864 if (pThis->enmTpmVers == TPMVERSION_UNKNOWN)
1865 return PDMDEV_SET_ERROR(pDevIns, VERR_NOT_SUPPORTED, N_("The emulated TPM version is not supported"));
1866 }
1867 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1868 {
1869 pThis->fLocChangeSup = false;
1870 pThis->fEstablishmentSet = false;
1871 pThis->cbCmdResp = TPM_DATA_BUFFER_SIZE_MAX;
1872
1873 pThisCC->pDrvBase = NULL;
1874 pThisCC->pDrvTpm = NULL;
1875 LogRel(("TPM#%d: no unit\n", iInstance));
1876 }
1877 else
1878 AssertLogRelMsgRCReturn(rc, ("TPM#%d: Failed to attach to TPM driver. rc=%Rrc\n", iInstance, rc), rc);
1879
1880 /* Create task for executing requests in ring-3. */
1881 rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "TPMCmdWrk",
1882 tpmR3CmdExecWorker, NULL /*pvUser*/, &pThis->hTpmCmdTask);
1883 AssertRCReturn(rc,rc);
1884
1885 /*
1886 * Saved state.
1887 */
1888 rc = PDMDevHlpSSMRegister3(pDevIns, TPM_SAVED_STATE_VERSION, sizeof(*pThis),
1889 tpmR3LiveExec, tpmR3SaveExec, tpmR3LoadExec);
1890 AssertRCReturn(rc, rc);
1891
1892 tpmR3HwReset(pThis);
1893 return VINF_SUCCESS;
1894}
1895
1896#else /* !IN_RING3 */
1897
1898/**
1899 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1900 */
1901static DECLCALLBACK(int) tpmRZConstruct(PPDMDEVINS pDevIns)
1902{
1903 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1904 PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
1905
1906 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, tpmMmioWrite, tpmMmioRead, NULL /*pvUser*/);
1907 AssertRCReturn(rc, rc);
1908
1909 return VINF_SUCCESS;
1910}
1911
1912#endif /* !IN_RING3 */
1913
1914/**
1915 * The device registration structure.
1916 */
1917const PDMDEVREG g_DeviceTpm =
1918{
1919 /* .u32Version = */ PDM_DEVREG_VERSION,
1920 /* .uReserved0 = */ 0,
1921 /* .szName = */ "tpm",
1922 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1923 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
1924 /* .cMaxInstances = */ 1,
1925 /* .uSharedVersion = */ 42,
1926 /* .cbInstanceShared = */ sizeof(DEVTPM),
1927 /* .cbInstanceCC = */ sizeof(DEVTPMCC),
1928 /* .cbInstanceRC = */ sizeof(DEVTPMRC),
1929 /* .cMaxPciDevices = */ 0,
1930 /* .cMaxMsixVectors = */ 0,
1931 /* .pszDescription = */ "Trusted Platform Module",
1932#if defined(IN_RING3)
1933 /* .pszRCMod = */ "VBoxDDRC.rc",
1934 /* .pszR0Mod = */ "VBoxDDR0.r0",
1935 /* .pfnConstruct = */ tpmR3Construct,
1936 /* .pfnDestruct = */ tpmR3Destruct,
1937 /* .pfnRelocate = */ NULL,
1938 /* .pfnMemSetup = */ NULL,
1939 /* .pfnPowerOn = */ tpmR3PowerOn,
1940 /* .pfnReset = */ tpmR3Reset,
1941 /* .pfnSuspend = */ NULL,
1942 /* .pfnResume = */ NULL,
1943 /* .pfnAttach = */ NULL,
1944 /* .pfnDetach = */ NULL,
1945 /* .pfnQueryInterface = */ NULL,
1946 /* .pfnInitComplete = */ NULL,
1947 /* .pfnPowerOff = */ NULL,
1948 /* .pfnSoftReset = */ NULL,
1949 /* .pfnReserved0 = */ NULL,
1950 /* .pfnReserved1 = */ NULL,
1951 /* .pfnReserved2 = */ NULL,
1952 /* .pfnReserved3 = */ NULL,
1953 /* .pfnReserved4 = */ NULL,
1954 /* .pfnReserved5 = */ NULL,
1955 /* .pfnReserved6 = */ NULL,
1956 /* .pfnReserved7 = */ NULL,
1957#elif defined(IN_RING0)
1958 /* .pfnEarlyConstruct = */ NULL,
1959 /* .pfnConstruct = */ tpmRZConstruct,
1960 /* .pfnDestruct = */ NULL,
1961 /* .pfnFinalDestruct = */ NULL,
1962 /* .pfnRequest = */ NULL,
1963 /* .pfnReserved0 = */ NULL,
1964 /* .pfnReserved1 = */ NULL,
1965 /* .pfnReserved2 = */ NULL,
1966 /* .pfnReserved3 = */ NULL,
1967 /* .pfnReserved4 = */ NULL,
1968 /* .pfnReserved5 = */ NULL,
1969 /* .pfnReserved6 = */ NULL,
1970 /* .pfnReserved7 = */ NULL,
1971#elif defined(IN_RC)
1972 /* .pfnConstruct = */ tpmRZConstruct,
1973 /* .pfnReserved0 = */ NULL,
1974 /* .pfnReserved1 = */ NULL,
1975 /* .pfnReserved2 = */ NULL,
1976 /* .pfnReserved3 = */ NULL,
1977 /* .pfnReserved4 = */ NULL,
1978 /* .pfnReserved5 = */ NULL,
1979 /* .pfnReserved6 = */ NULL,
1980 /* .pfnReserved7 = */ NULL,
1981#else
1982# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1983#endif
1984 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1985};
1986
1987#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1988
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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