VirtualBox

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

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

Devices/Security/DevTpm: Fix declaration, bugref:10075

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

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