Skip to content

Commit 490df43

Browse files
accekaccek-itl
authored andcommitted
xen/arch/x86/tpm.c: add CRB interface support
Assisted-by: Claude:claude-opus-4-6
1 parent 0e6d731 commit 490df43

3 files changed

Lines changed: 208 additions & 51 deletions

File tree

xen/arch/x86/include/asm/tpm.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
#include <xen/types.h>
1111

12-
#define TPM_TIS_BASE 0xfed40000U
13-
#define TPM_TIS_SIZE 0x00010000U
12+
#define TPM_BASE 0xfed40000U
13+
#define TPM_SIZE 0x00010000U
1414

1515
/* All fields of the following structs are big endian. */
1616

xen/arch/x86/slaunch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ void __init slaunch_map_mem_regions(void)
104104
paddr_t evt_log_addr;
105105
uint32_t evt_log_size;
106106

107-
rc = slaunch_map_l2(TPM_TIS_BASE, TPM_TIS_SIZE);
107+
rc = slaunch_map_l2(TPM_BASE, TPM_SIZE);
108108
BUG_ON(rc != 0);
109109

110110
/* Vendor-specific part. */

xen/arch/x86/tpm.c

Lines changed: 205 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -85,63 +85,115 @@ static bool is_amd_cpu(void)
8585

8686
#define TPM_LOC_REG(loc, reg) (0x1000 * (loc) + (reg))
8787

88-
#define TPM_ACCESS_(x) TPM_LOC_REG(x, 0x00)
89-
#define ACCESS_REQUEST_USE (1 << 1)
90-
#define ACCESS_ACTIVE_LOCALITY (1 << 5)
91-
#define TPM_INTF_CAPABILITY_(x) TPM_LOC_REG(x, 0x14)
92-
#define INTF_VERSION_MASK 0x70000000
93-
#define TPM_STS_(x) TPM_LOC_REG(x, 0x18)
94-
#define TPM_FAMILY_MASK 0x0C000000
95-
#define STS_EXPECT_DATA (1 << 3)
96-
#define STS_DATA_AVAIL (1 << 4)
97-
#define STS_TPM_GO (1 << 5)
98-
#define STS_COMMAND_READY (1 << 6)
99-
#define STS_VALID (1 << 7)
100-
#define TPM_BURST_COUNT_(x) TPM_LOC_REG(x, 0x19)
101-
#define TPM_DATA_FIFO_(x) TPM_LOC_REG(x, 0x24)
102-
10388
#define swap16(x) __builtin_bswap16(x)
10489
#define swap32(x) __builtin_bswap32(x)
10590

106-
static inline volatile uint32_t tis_read32(unsigned reg)
91+
/******************************** MMIO helpers ********************************/
92+
93+
static inline uint32_t tpm_read32(unsigned reg)
10794
{
108-
return *(volatile uint32_t *)__va(TPM_TIS_BASE + reg);
95+
return *(volatile uint32_t *)__va(TPM_BASE + reg);
10996
}
11097

111-
static inline volatile uint16_t tis_read16(unsigned reg)
98+
static inline uint16_t tpm_read16(unsigned reg)
11299
{
113-
return *(volatile uint16_t *)__va(TPM_TIS_BASE + reg);
100+
return *(volatile uint16_t *)__va(TPM_BASE + reg);
114101
}
115102

116-
static inline volatile uint8_t tis_read8(unsigned reg)
103+
static inline uint8_t tpm_read8(unsigned reg)
117104
{
118-
return *(volatile uint8_t *)__va(TPM_TIS_BASE + reg);
105+
return *(volatile uint8_t *)__va(TPM_BASE + reg);
119106
}
120107

121-
static inline void tis_write8(unsigned reg, uint8_t val)
108+
static inline void tpm_write32(unsigned reg, uint32_t val)
122109
{
123-
*(volatile uint8_t *)__va(TPM_TIS_BASE + reg) = val;
110+
*(volatile uint32_t *)__va(TPM_BASE + reg) = val;
124111
}
125112

126-
static inline void request_locality(unsigned loc)
113+
static inline void tpm_write8(unsigned reg, uint8_t val)
114+
{
115+
*(volatile uint8_t *)__va(TPM_BASE + reg) = val;
116+
}
117+
118+
/************************** Interface detection *******************************/
119+
120+
#define TPM_INTF_ID_(x) TPM_LOC_REG(x, 0x30)
121+
#define INTF_TYPE_MASK 0x0000000fU
122+
#define INTF_TYPE_TIS 0x00
123+
#define INTF_TYPE_CRB 0x01
124+
125+
/*
126+
* No static caching: the early 32-bit binary (tpm_early.bin) is built with
127+
* "objcopy -j .text", which omits .bss/.data.
128+
*/
129+
static inline bool tpm_is_crb(void)
130+
{
131+
return (tpm_read32(TPM_INTF_ID_(0)) & INTF_TYPE_MASK) == INTF_TYPE_CRB;
132+
}
133+
134+
/************************** TIS register definitions **************************/
135+
136+
#define TIS_ACCESS_(x) TPM_LOC_REG(x, 0x00)
137+
#define ACCESS_REQUEST_USE (1 << 1)
138+
#define ACCESS_ACTIVE_LOCALITY (1 << 5)
139+
#define TIS_INTF_CAPABILITY_(x) TPM_LOC_REG(x, 0x14)
140+
#define INTF_VERSION_MASK 0x70000000
141+
#define TIS_STS_(x) TPM_LOC_REG(x, 0x18)
142+
#define STS_FAMILY_MASK 0x0C000000
143+
#define STS_EXPECT_DATA (1 << 3)
144+
#define STS_DATA_AVAIL (1 << 4)
145+
#define STS_TPM_GO (1 << 5)
146+
#define STS_COMMAND_READY (1 << 6)
147+
#define STS_VALID (1 << 7)
148+
#define TIS_BURST_COUNT_(x) TPM_LOC_REG(x, 0x19)
149+
#define TIS_DATA_FIFO_(x) TPM_LOC_REG(x, 0x24)
150+
151+
/************************** CRB register definitions **************************/
152+
153+
#define CRB_LOC_STATE_(x) TPM_LOC_REG(x, 0x00)
154+
#define CRB_LOC_STATE_LOC_ASSIGNED (1 << 1)
155+
#define CRB_LOC_STATE_REG_VALID_STS (1 << 7)
156+
#define CRB_LOC_CTRL_(x) TPM_LOC_REG(x, 0x08)
157+
#define CRB_LOC_CTRL_REQUEST_ACCESS (1 << 0)
158+
#define CRB_LOC_CTRL_RELINQUISH (1 << 1)
159+
#define CRB_CTRL_REQ_(x) TPM_LOC_REG(x, 0x40)
160+
#define CRB_CTRL_REQ_CMD_READY (1 << 0)
161+
#define CRB_CTRL_REQ_GO_IDLE (1 << 1)
162+
#define CRB_CTRL_STS_(x) TPM_LOC_REG(x, 0x44)
163+
#define CRB_CTRL_STS_ERROR (1 << 0)
164+
#define CRB_CTRL_CANCEL_(x) TPM_LOC_REG(x, 0x48)
165+
#define CRB_CTRL_CANCEL_INVOKE (1 << 0)
166+
#define CRB_CTRL_START_(x) TPM_LOC_REG(x, 0x4C)
167+
#define CRB_CTRL_START_INVOKE (1 << 0)
168+
#define CRB_CTRL_CMD_SIZE_(x) TPM_LOC_REG(x, 0x58)
169+
#define CRB_CTRL_CMD_LADDR_(x) TPM_LOC_REG(x, 0x5C)
170+
#define CRB_CTRL_CMD_HADDR_(x) TPM_LOC_REG(x, 0x60)
171+
#define CRB_CTRL_RSP_SIZE_(x) TPM_LOC_REG(x, 0x64)
172+
#define CRB_CTRL_RSP_ADDR_(x) TPM_LOC_REG(x, 0x68)
173+
#define CRB_DATA_BUFFER_(x) TPM_LOC_REG(x, 0x80)
174+
#define CRB_DATA_BUFFER_SIZE 0x0F80
175+
176+
/************************** TIS locality & command ****************************/
177+
178+
static inline void tis_request_locality(unsigned loc)
127179
{
128-
tis_write8(TPM_ACCESS_(loc), ACCESS_REQUEST_USE);
180+
tpm_write8(TIS_ACCESS_(loc), ACCESS_REQUEST_USE);
129181
/* Check that locality was actually activated. */
130-
while ( (tis_read8(TPM_ACCESS_(loc)) & ACCESS_ACTIVE_LOCALITY) == 0 );
182+
while ( (tpm_read8(TIS_ACCESS_(loc)) & ACCESS_ACTIVE_LOCALITY) == 0 );
131183
}
132184

133-
static inline void relinquish_locality(unsigned loc)
185+
static inline void tis_relinquish_locality(unsigned loc)
134186
{
135-
tis_write8(TPM_ACCESS_(loc), ACCESS_ACTIVE_LOCALITY);
187+
tpm_write8(TIS_ACCESS_(loc), ACCESS_ACTIVE_LOCALITY);
136188
}
137189

138-
static inline uint16_t get_burst_count(unsigned loc)
190+
static inline uint16_t tis_get_burst_count(unsigned loc)
139191
{
140-
return tis_read16(TPM_BURST_COUNT_(loc));
192+
return tpm_read16(TIS_BURST_COUNT_(loc));
141193
}
142194

143-
static void send_cmd(unsigned loc, uint8_t *buf, unsigned i_size,
144-
unsigned *o_size)
195+
static void tis_send_cmd(unsigned loc, uint8_t *buf, unsigned i_size,
196+
unsigned *o_size)
145197
{
146198
/*
147199
* Values of "expect data" and "data available" bits counts only when
@@ -154,65 +206,170 @@ static void send_cmd(unsigned loc, uint8_t *buf, unsigned i_size,
154206
unsigned burst_count;
155207

156208
/* Make sure TPM can accept a command. */
157-
if ( (tis_read8(TPM_STS_(loc)) & STS_COMMAND_READY) == 0 )
209+
if ( (tpm_read8(TIS_STS_(loc)) & STS_COMMAND_READY) == 0 )
158210
{
159211
/* Abort current command. */
160-
tis_write8(TPM_STS_(loc), STS_COMMAND_READY);
212+
tpm_write8(TIS_STS_(loc), STS_COMMAND_READY);
161213
/* Wait until TPM is ready for a new one. */
162-
while ( (tis_read8(TPM_STS_(loc)) & STS_COMMAND_READY) == 0 );
214+
while ( (tpm_read8(TIS_STS_(loc)) & STS_COMMAND_READY) == 0 );
163215
}
164216

165217
i = 0;
166218
while ( i < i_size )
167219
{
168220
do
169-
burst_count = get_burst_count(loc);
221+
burst_count = tis_get_burst_count(loc);
170222
while ( burst_count == 0 );
171223

172224
while ( burst_count-- > 0 && i < i_size )
173-
tis_write8(TPM_DATA_FIFO_(loc), buf[i++]);
225+
tpm_write8(TIS_DATA_FIFO_(loc), buf[i++]);
174226

175227
if ( i < i_size )
176-
while ( (tis_read8(TPM_STS_(loc)) & expect_data) != expect_data );
228+
while ( (tpm_read8(TIS_STS_(loc)) & expect_data) != expect_data );
177229
}
178230

179-
tis_write8(TPM_STS_(loc), STS_TPM_GO);
231+
tpm_write8(TIS_STS_(loc), STS_TPM_GO);
180232

181233
/* Wait for the first byte of response. */
182-
while ( (tis_read8(TPM_STS_(loc)) & data_avail) != data_avail );
234+
while ( (tpm_read8(TIS_STS_(loc)) & data_avail) != data_avail );
183235

184236
i = 0;
185237
do {
186238
do
187-
burst_count = get_burst_count(loc);
239+
burst_count = tis_get_burst_count(loc);
188240
while ( burst_count == 0 );
189241

190242
while ( burst_count-- > 0 && i < *o_size)
191-
buf[i++] = tis_read8(TPM_DATA_FIFO_(loc));
243+
buf[i++] = tpm_read8(TIS_DATA_FIFO_(loc));
192244

193-
while ( (tis_read8(TPM_STS_(loc)) & STS_VALID) == 0 );
245+
while ( (tpm_read8(TIS_STS_(loc)) & STS_VALID) == 0 );
194246
} while ( i < *o_size &&
195-
(tis_read8(TPM_STS_(loc)) & data_avail) == data_avail );
247+
(tpm_read8(TIS_STS_(loc)) & data_avail) == data_avail );
196248

197249
if ( i < *o_size )
198250
*o_size = i;
199251

200-
tis_write8(TPM_STS_(loc), STS_COMMAND_READY);
252+
tpm_write8(TIS_STS_(loc), STS_COMMAND_READY);
253+
}
254+
255+
/************************** CRB locality & command ****************************/
256+
257+
static void crb_request_locality(unsigned loc)
258+
{
259+
const uint32_t mask = CRB_LOC_STATE_LOC_ASSIGNED |
260+
CRB_LOC_STATE_REG_VALID_STS;
261+
262+
tpm_write32(CRB_LOC_CTRL_(loc), CRB_LOC_CTRL_REQUEST_ACCESS);
263+
while ( (tpm_read32(CRB_LOC_STATE_(loc)) & mask) != mask );
264+
}
265+
266+
static void crb_relinquish_locality(unsigned loc)
267+
{
268+
tpm_write32(CRB_LOC_CTRL_(loc), CRB_LOC_CTRL_RELINQUISH);
269+
while ( tpm_read32(CRB_LOC_STATE_(loc)) & CRB_LOC_STATE_LOC_ASSIGNED );
270+
}
271+
272+
static void crb_cmd_ready(unsigned loc)
273+
{
274+
tpm_write32(CRB_CTRL_REQ_(loc), CRB_CTRL_REQ_CMD_READY);
275+
while ( tpm_read32(CRB_CTRL_REQ_(loc)) & CRB_CTRL_REQ_CMD_READY );
276+
}
277+
278+
static void crb_go_idle(unsigned loc)
279+
{
280+
tpm_write32(CRB_CTRL_REQ_(loc), CRB_CTRL_REQ_GO_IDLE);
281+
while ( tpm_read32(CRB_CTRL_REQ_(loc)) & CRB_CTRL_REQ_GO_IDLE );
282+
}
283+
284+
static void crb_send_cmd(unsigned loc, uint8_t *buf, unsigned i_size,
285+
unsigned *o_size)
286+
{
287+
uint32_t data_buf_pa = TPM_BASE + CRB_DATA_BUFFER_(loc);
288+
unsigned expected;
289+
290+
crb_cmd_ready(loc);
291+
292+
tpm_write32(CRB_CTRL_CANCEL_(loc), 0);
293+
294+
tpm_write32(CRB_CTRL_CMD_LADDR_(loc), data_buf_pa);
295+
tpm_write32(CRB_CTRL_CMD_HADDR_(loc), 0);
296+
tpm_write32(CRB_CTRL_CMD_SIZE_(loc), CRB_DATA_BUFFER_SIZE);
297+
tpm_write32(CRB_CTRL_RSP_SIZE_(loc), CRB_DATA_BUFFER_SIZE);
298+
/* RSP_ADDR is 64-bit. */
299+
tpm_write32(CRB_CTRL_RSP_ADDR_(loc), data_buf_pa);
300+
tpm_write32(CRB_CTRL_RSP_ADDR_(loc) + 4, 0);
301+
302+
memcpy(__va(data_buf_pa), buf, i_size);
303+
304+
tpm_write32(CRB_CTRL_START_(loc), CRB_CTRL_START_INVOKE);
305+
while ( tpm_read32(CRB_CTRL_START_(loc)) & CRB_CTRL_START_INVOKE );
306+
307+
if ( tpm_read32(CRB_CTRL_STS_(loc)) & CRB_CTRL_STS_ERROR )
308+
{
309+
*o_size = 0;
310+
crb_go_idle(loc);
311+
return;
312+
}
313+
314+
/* Read header to learn the response length. */
315+
memcpy(buf, __va(data_buf_pa), sizeof(struct tpm_rsp_hdr));
316+
expected = swap32(((struct tpm_rsp_hdr *)buf)->paramSize);
317+
if ( expected > *o_size )
318+
expected = *o_size;
319+
if ( expected > CRB_DATA_BUFFER_SIZE )
320+
expected = CRB_DATA_BUFFER_SIZE;
321+
322+
memcpy(buf, __va(data_buf_pa), expected);
323+
324+
*o_size = expected;
325+
crb_go_idle(loc);
326+
}
327+
328+
/************************** Interface dispatch ********************************/
329+
330+
static inline void request_locality(unsigned loc)
331+
{
332+
if ( tpm_is_crb() )
333+
crb_request_locality(loc);
334+
else
335+
tis_request_locality(loc);
336+
}
337+
338+
static inline void relinquish_locality(unsigned loc)
339+
{
340+
if ( tpm_is_crb() )
341+
crb_relinquish_locality(loc);
342+
else
343+
tis_relinquish_locality(loc);
344+
}
345+
346+
static void send_cmd(unsigned loc, uint8_t *buf, unsigned i_size,
347+
unsigned *o_size)
348+
{
349+
if ( tpm_is_crb() )
350+
crb_send_cmd(loc, buf, i_size, o_size);
351+
else
352+
tis_send_cmd(loc, buf, i_size, o_size);
201353
}
202354

203355
static inline bool is_tpm12(void)
204356
{
357+
uint32_t intf_version;
358+
359+
/* CRB interface is always TPM 2.0. */
360+
if ( tpm_is_crb() )
361+
return false;
362+
205363
/*
206364
* If one of these conditions is true:
207365
* - INTF_CAPABILITY_x.interfaceVersion is 0 (TIS <= 1.21)
208366
* - INTF_CAPABILITY_x.interfaceVersion is 2 (TIS == 1.3)
209367
* - STS_x.tpmFamily is 0
210368
* we're dealing with TPM1.2.
211369
*/
212-
uint32_t intf_version = tis_read32(TPM_INTF_CAPABILITY_(0))
213-
& INTF_VERSION_MASK;
370+
intf_version = tpm_read32(TIS_INTF_CAPABILITY_(0)) & INTF_VERSION_MASK;
214371
return (intf_version == 0x00000000 || intf_version == 0x20000000 ||
215-
(tis_read32(TPM_STS_(0)) & TPM_FAMILY_MASK) == 0);
372+
(tpm_read32(TIS_STS_(0)) & STS_FAMILY_MASK) == 0);
216373
}
217374

218375
/****************************** TPM1.2 & TPM2.0 *******************************/

0 commit comments

Comments
 (0)