VirtualBox

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

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

Devices/Security/DevTpm: Implement some todos, bugref:10075

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