VirtualBox

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

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

Devices/Security/DevTpm: Saved state support, untested, bugref:10075

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

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