Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/tpm/tpm_crb_ffa.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2024 Arm Ltd.
4
*
5
* This device driver implements the TPM CRB start method
6
* as defined in the TPM Service Command Response Buffer
7
* Interface Over FF-A (DEN0138).
8
*/
9
10
#define pr_fmt(fmt) "CRB_FFA: " fmt
11
12
#include <linux/arm_ffa.h>
13
#include <linux/delay.h>
14
#include <linux/moduleparam.h>
15
#include "tpm_crb_ffa.h"
16
17
static unsigned int busy_timeout_ms = 2000;
18
19
module_param(busy_timeout_ms, uint, 0644);
20
MODULE_PARM_DESC(busy_timeout_ms,
21
"Maximum time in ms to retry before giving up on busy");
22
23
/* TPM service function status codes */
24
#define CRB_FFA_OK 0x05000001
25
#define CRB_FFA_OK_RESULTS_RETURNED 0x05000002
26
#define CRB_FFA_NOFUNC 0x8e000001
27
#define CRB_FFA_NOTSUP 0x8e000002
28
#define CRB_FFA_INVARG 0x8e000005
29
#define CRB_FFA_INV_CRB_CTRL_DATA 0x8e000006
30
#define CRB_FFA_ALREADY 0x8e000009
31
#define CRB_FFA_DENIED 0x8e00000a
32
#define CRB_FFA_NOMEM 0x8e00000b
33
34
#define CRB_FFA_VERSION_MAJOR 1
35
#define CRB_FFA_VERSION_MINOR 0
36
37
/* version encoding */
38
#define CRB_FFA_MAJOR_VERSION_MASK GENMASK(30, 16)
39
#define CRB_FFA_MINOR_VERSION_MASK GENMASK(15, 0)
40
#define CRB_FFA_MAJOR_VERSION(x) ((u16)(FIELD_GET(CRB_FFA_MAJOR_VERSION_MASK, (x))))
41
#define CRB_FFA_MINOR_VERSION(x) ((u16)(FIELD_GET(CRB_FFA_MINOR_VERSION_MASK, (x))))
42
43
/*
44
* Normal world sends requests with FFA_MSG_SEND_DIRECT_REQ and
45
* responses are returned with FFA_MSG_SEND_DIRECT_RESP for normal
46
* messages.
47
*
48
* All requests with FFA_MSG_SEND_DIRECT_REQ and FFA_MSG_SEND_DIRECT_RESP
49
* are using the AArch32 or AArch64 SMC calling convention with register usage
50
* as defined in FF-A specification:
51
* w0: Function ID
52
* -for 32-bit: 0x8400006F or 0x84000070
53
* -for 64-bit: 0xC400006F or 0xC4000070
54
* w1: Source/Destination IDs
55
* w2: Reserved (MBZ)
56
* w3-w7: Implementation defined, free to be used below
57
*/
58
59
/*
60
* Returns the version of the interface that is available
61
* Call register usage:
62
* w3: Not used (MBZ)
63
* w4: TPM service function ID, CRB_FFA_GET_INTERFACE_VERSION
64
* w5-w7: Reserved (MBZ)
65
*
66
* Return register usage:
67
* w3: Not used (MBZ)
68
* w4: TPM service function status
69
* w5: TPM service interface version
70
* Bits[31:16]: major version
71
* Bits[15:0]: minor version
72
* w6-w7: Reserved (MBZ)
73
*
74
* Possible function status codes in register w4:
75
* CRB_FFA_OK_RESULTS_RETURNED: The version of the interface has been
76
* returned.
77
*/
78
#define CRB_FFA_GET_INTERFACE_VERSION 0x0f000001
79
80
/*
81
* Notifies the TPM service that a TPM command or TPM locality request is
82
* ready to be processed, and allows the TPM service to process it.
83
* Call register usage:
84
* w3: Not used (MBZ)
85
* w4: TPM service function ID, CRB_FFA_START
86
* w5: Start function qualifier
87
* Bits[31:8] (MBZ)
88
* Bits[7:0]
89
* 0: Notifies TPM that a command is ready to be processed
90
* 1: Notifies TPM that a locality request is ready to be processed
91
* w6: TPM locality, one of 0..4
92
* -If the start function qualifier is 0, identifies the locality
93
* from where the command originated.
94
* -If the start function qualifier is 1, identifies the locality
95
* of the locality request
96
* w6-w7: Reserved (MBZ)
97
*
98
* Return register usage:
99
* w3: Not used (MBZ)
100
* w4: TPM service function status
101
* w5-w7: Reserved (MBZ)
102
*
103
* Possible function status codes in register w4:
104
* CRB_FFA_OK: the TPM service has been notified successfully
105
* CRB_FFA_INVARG: one or more arguments are not valid
106
* CRB_FFA_INV_CRB_CTRL_DATA: CRB control data or locality control
107
* data at the given TPM locality is not valid
108
* CRB_FFA_DENIED: the TPM has previously disabled locality requests and
109
* command processing at the given locality
110
*/
111
#define CRB_FFA_START 0x0f000201
112
113
struct tpm_crb_ffa {
114
struct ffa_device *ffa_dev;
115
u16 major_version;
116
u16 minor_version;
117
/* lock to protect sending of FF-A messages: */
118
struct mutex msg_data_lock;
119
union {
120
struct ffa_send_direct_data direct_msg_data;
121
struct ffa_send_direct_data2 direct_msg_data2;
122
};
123
};
124
125
static struct tpm_crb_ffa *tpm_crb_ffa;
126
static struct ffa_driver tpm_crb_ffa_driver;
127
128
static int tpm_crb_ffa_to_linux_errno(int errno)
129
{
130
int rc;
131
132
switch (errno) {
133
case CRB_FFA_OK:
134
rc = 0;
135
break;
136
case CRB_FFA_OK_RESULTS_RETURNED:
137
rc = 0;
138
break;
139
case CRB_FFA_NOFUNC:
140
rc = -ENOENT;
141
break;
142
case CRB_FFA_NOTSUP:
143
rc = -EPERM;
144
break;
145
case CRB_FFA_INVARG:
146
rc = -EINVAL;
147
break;
148
case CRB_FFA_INV_CRB_CTRL_DATA:
149
rc = -ENOEXEC;
150
break;
151
case CRB_FFA_ALREADY:
152
rc = -EEXIST;
153
break;
154
case CRB_FFA_DENIED:
155
rc = -EACCES;
156
break;
157
case CRB_FFA_NOMEM:
158
rc = -ENOMEM;
159
break;
160
default:
161
rc = -EINVAL;
162
}
163
164
return rc;
165
}
166
167
/**
168
* tpm_crb_ffa_init - called by the CRB driver to do any needed initialization
169
*
170
* This function is called by the tpm_crb driver during the tpm_crb
171
* driver's initialization. If the tpm_crb_ffa has not been probed
172
* yet, returns -ENOENT in order to force a retry. If th ffa_crb
173
* driver had been probed but failed with an error, returns -ENODEV
174
* in order to prevent further retries.
175
*
176
* Return: 0 on success, negative error code on failure.
177
*/
178
int tpm_crb_ffa_init(void)
179
{
180
int ret = 0;
181
182
if (!IS_MODULE(CONFIG_TCG_ARM_CRB_FFA)) {
183
ret = ffa_register(&tpm_crb_ffa_driver);
184
if (ret) {
185
tpm_crb_ffa = ERR_PTR(-ENODEV);
186
return ret;
187
}
188
}
189
190
if (!tpm_crb_ffa)
191
ret = -ENOENT;
192
193
if (IS_ERR_VALUE(tpm_crb_ffa))
194
ret = -ENODEV;
195
196
return ret;
197
}
198
EXPORT_SYMBOL_GPL(tpm_crb_ffa_init);
199
200
static int __tpm_crb_ffa_try_send_receive(unsigned long func_id,
201
unsigned long a0, unsigned long a1,
202
unsigned long a2)
203
{
204
const struct ffa_msg_ops *msg_ops;
205
int ret;
206
207
msg_ops = tpm_crb_ffa->ffa_dev->ops->msg_ops;
208
209
if (ffa_partition_supports_direct_req2_recv(tpm_crb_ffa->ffa_dev)) {
210
tpm_crb_ffa->direct_msg_data2 = (struct ffa_send_direct_data2){
211
.data = { func_id, a0, a1, a2 },
212
};
213
214
ret = msg_ops->sync_send_receive2(tpm_crb_ffa->ffa_dev,
215
&tpm_crb_ffa->direct_msg_data2);
216
if (!ret)
217
ret = tpm_crb_ffa_to_linux_errno(tpm_crb_ffa->direct_msg_data2.data[0]);
218
} else {
219
tpm_crb_ffa->direct_msg_data = (struct ffa_send_direct_data){
220
.data1 = func_id,
221
.data2 = a0,
222
.data3 = a1,
223
.data4 = a2,
224
};
225
226
ret = msg_ops->sync_send_receive(tpm_crb_ffa->ffa_dev,
227
&tpm_crb_ffa->direct_msg_data);
228
if (!ret)
229
ret = tpm_crb_ffa_to_linux_errno(tpm_crb_ffa->direct_msg_data.data1);
230
}
231
232
return ret;
233
}
234
235
static int __tpm_crb_ffa_send_receive(unsigned long func_id, unsigned long a0,
236
unsigned long a1, unsigned long a2)
237
{
238
ktime_t start, stop;
239
int ret;
240
241
if (!tpm_crb_ffa)
242
return -ENOENT;
243
244
start = ktime_get();
245
stop = ktime_add(start, ms_to_ktime(busy_timeout_ms));
246
247
for (;;) {
248
ret = __tpm_crb_ffa_try_send_receive(func_id, a0, a1, a2);
249
if (ret != -EBUSY)
250
break;
251
252
usleep_range(50, 100);
253
if (ktime_after(ktime_get(), stop)) {
254
dev_warn(&tpm_crb_ffa->ffa_dev->dev,
255
"Busy retry timed out\n");
256
break;
257
}
258
}
259
260
return ret;
261
}
262
263
/**
264
* tpm_crb_ffa_get_interface_version() - gets the ABI version of the TPM service
265
* @major: Pointer to caller-allocated buffer to hold the major version
266
* number the ABI
267
* @minor: Pointer to caller-allocated buffer to hold the minor version
268
* number the ABI
269
*
270
* Returns the major and minor version of the ABI of the FF-A based TPM.
271
* Allows the caller to evaluate its compatibility with the version of
272
* the ABI.
273
*
274
* Return: 0 on success, negative error code on failure.
275
*/
276
static int tpm_crb_ffa_get_interface_version(u16 *major, u16 *minor)
277
{
278
int rc;
279
280
if (!tpm_crb_ffa)
281
return -ENOENT;
282
283
if (IS_ERR_VALUE(tpm_crb_ffa))
284
return -ENODEV;
285
286
if (!major || !minor)
287
return -EINVAL;
288
289
guard(mutex)(&tpm_crb_ffa->msg_data_lock);
290
291
rc = __tpm_crb_ffa_send_receive(CRB_FFA_GET_INTERFACE_VERSION, 0x00, 0x00, 0x00);
292
if (!rc) {
293
if (ffa_partition_supports_direct_req2_recv(tpm_crb_ffa->ffa_dev)) {
294
*major = CRB_FFA_MAJOR_VERSION(tpm_crb_ffa->direct_msg_data2.data[1]);
295
*minor = CRB_FFA_MINOR_VERSION(tpm_crb_ffa->direct_msg_data2.data[1]);
296
} else {
297
*major = CRB_FFA_MAJOR_VERSION(tpm_crb_ffa->direct_msg_data.data2);
298
*minor = CRB_FFA_MINOR_VERSION(tpm_crb_ffa->direct_msg_data.data2);
299
}
300
}
301
302
return rc;
303
}
304
305
/**
306
* tpm_crb_ffa_start() - signals the TPM that a field has changed in the CRB
307
* @request_type: Identifies whether the change to the CRB is in the command
308
* fields or locality fields.
309
* @locality: Specifies the locality number.
310
*
311
* Used by the CRB driver
312
* that might be useful to those using or modifying it. Begins with
313
* empty comment line, and may include additional embedded empty
314
* comment lines.
315
*
316
* Return: 0 on success, negative error code on failure.
317
*/
318
int tpm_crb_ffa_start(int request_type, int locality)
319
{
320
if (!tpm_crb_ffa)
321
return -ENOENT;
322
323
if (IS_ERR_VALUE(tpm_crb_ffa))
324
return -ENODEV;
325
326
guard(mutex)(&tpm_crb_ffa->msg_data_lock);
327
328
return __tpm_crb_ffa_send_receive(CRB_FFA_START, request_type, locality, 0x00);
329
}
330
EXPORT_SYMBOL_GPL(tpm_crb_ffa_start);
331
332
static int tpm_crb_ffa_probe(struct ffa_device *ffa_dev)
333
{
334
struct tpm_crb_ffa *p;
335
int rc;
336
337
/* only one instance of a TPM partition is supported */
338
if (tpm_crb_ffa && !IS_ERR_VALUE(tpm_crb_ffa))
339
return -EEXIST;
340
341
tpm_crb_ffa = ERR_PTR(-ENODEV); // set tpm_crb_ffa so we can detect probe failure
342
343
if (!ffa_partition_supports_direct_recv(ffa_dev) &&
344
!ffa_partition_supports_direct_req2_recv(ffa_dev)) {
345
dev_warn(&ffa_dev->dev, "partition doesn't support direct message receive.\n");
346
return -EINVAL;
347
}
348
349
p = kzalloc(sizeof(*tpm_crb_ffa), GFP_KERNEL);
350
if (!p)
351
return -ENOMEM;
352
tpm_crb_ffa = p;
353
354
mutex_init(&tpm_crb_ffa->msg_data_lock);
355
tpm_crb_ffa->ffa_dev = ffa_dev;
356
ffa_dev_set_drvdata(ffa_dev, tpm_crb_ffa);
357
358
/* if TPM is aarch32 use 32-bit SMCs */
359
if (!ffa_partition_check_property(ffa_dev, FFA_PARTITION_AARCH64_EXEC))
360
ffa_dev->ops->msg_ops->mode_32bit_set(ffa_dev);
361
362
/* verify compatibility of TPM service version number */
363
rc = tpm_crb_ffa_get_interface_version(&tpm_crb_ffa->major_version,
364
&tpm_crb_ffa->minor_version);
365
if (rc) {
366
dev_err(&ffa_dev->dev, "failed to get crb interface version. rc:%d\n", rc);
367
goto out;
368
}
369
370
dev_info(&ffa_dev->dev, "ABI version %u.%u\n", tpm_crb_ffa->major_version,
371
tpm_crb_ffa->minor_version);
372
373
if (tpm_crb_ffa->major_version != CRB_FFA_VERSION_MAJOR ||
374
(tpm_crb_ffa->minor_version > 0 &&
375
tpm_crb_ffa->minor_version < CRB_FFA_VERSION_MINOR)) {
376
dev_warn(&ffa_dev->dev, "Incompatible ABI version\n");
377
goto out;
378
}
379
380
return 0;
381
382
out:
383
kfree(tpm_crb_ffa);
384
tpm_crb_ffa = ERR_PTR(-ENODEV);
385
return -EINVAL;
386
}
387
388
static void tpm_crb_ffa_remove(struct ffa_device *ffa_dev)
389
{
390
kfree(tpm_crb_ffa);
391
tpm_crb_ffa = NULL;
392
}
393
394
static const struct ffa_device_id tpm_crb_ffa_device_id[] = {
395
/* 17b862a4-1806-4faf-86b3-089a58353861 */
396
{ UUID_INIT(0x17b862a4, 0x1806, 0x4faf,
397
0x86, 0xb3, 0x08, 0x9a, 0x58, 0x35, 0x38, 0x61) },
398
{}
399
};
400
401
static struct ffa_driver tpm_crb_ffa_driver = {
402
.name = "ffa-crb",
403
.probe = tpm_crb_ffa_probe,
404
.remove = tpm_crb_ffa_remove,
405
.id_table = tpm_crb_ffa_device_id,
406
};
407
408
#ifdef MODULE
409
module_ffa_driver(tpm_crb_ffa_driver);
410
#endif
411
412
MODULE_AUTHOR("Arm");
413
MODULE_DESCRIPTION("TPM CRB FFA driver");
414
MODULE_LICENSE("GPL");
415
416