VirtualBox

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

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

Devices/Security: Only advertise the multiple localities supported capability if the driver below supports it, bugref:10075

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