VirtualBox

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

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

Security: The underlying driver specifies the input buffer size of the TPM for the device emulation to use and not the other way around, bugref:10075

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