Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/tpm/tpm_ppi.c
26292 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2012-2014 Intel Corporation
4
*
5
* Authors:
6
* Xiaoyan Zhang <[email protected]>
7
* Jiang Liu <[email protected]>
8
* Jarkko Sakkinen <[email protected]>
9
*
10
* Maintained by: <[email protected]>
11
*
12
* This file contains implementation of the sysfs interface for PPI.
13
*/
14
15
16
#include <linux/acpi.h>
17
#include "tpm.h"
18
19
#define TPM_PPI_REVISION_ID_1 1
20
#define TPM_PPI_REVISION_ID_2 2
21
#define TPM_PPI_FN_VERSION 1
22
#define TPM_PPI_FN_SUBREQ 2
23
#define TPM_PPI_FN_GETREQ 3
24
#define TPM_PPI_FN_GETACT 4
25
#define TPM_PPI_FN_GETRSP 5
26
#define TPM_PPI_FN_SUBREQ2 7
27
#define TPM_PPI_FN_GETOPR 8
28
#define PPI_TPM_REQ_MAX 101 /* PPI 1.3 for TPM 2 */
29
#define PPI_VS_REQ_START 128
30
#define PPI_VS_REQ_END 255
31
32
static const guid_t tpm_ppi_guid =
33
GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
34
0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
35
36
static bool tpm_ppi_req_has_parameter(u64 req)
37
{
38
return req == 23;
39
}
40
41
static inline union acpi_object *
42
tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
43
union acpi_object *argv4, u64 rev)
44
{
45
BUG_ON(!ppi_handle);
46
return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid,
47
rev, func, argv4, type);
48
}
49
50
static ssize_t tpm_show_ppi_version(struct device *dev,
51
struct device_attribute *attr, char *buf)
52
{
53
struct tpm_chip *chip = to_tpm_chip(dev);
54
55
return sysfs_emit(buf, "%s\n", chip->ppi_version);
56
}
57
58
static ssize_t tpm_show_ppi_request(struct device *dev,
59
struct device_attribute *attr, char *buf)
60
{
61
ssize_t size = -EINVAL;
62
union acpi_object *obj;
63
struct tpm_chip *chip = to_tpm_chip(dev);
64
u64 rev = TPM_PPI_REVISION_ID_2;
65
u64 req;
66
67
if (strcmp(chip->ppi_version, "1.2") < 0)
68
rev = TPM_PPI_REVISION_ID_1;
69
70
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
71
ACPI_TYPE_PACKAGE, NULL, rev);
72
if (!obj)
73
return -ENXIO;
74
75
/*
76
* output.pointer should be of package type, including two integers.
77
* The first is function return code, 0 means success and 1 means
78
* error. The second is pending TPM operation requested by the OS, 0
79
* means none and >0 means operation value.
80
*/
81
if (obj->package.count == 3 &&
82
obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
83
obj->package.elements[1].type == ACPI_TYPE_INTEGER &&
84
obj->package.elements[2].type == ACPI_TYPE_INTEGER) {
85
if (obj->package.elements[0].integer.value)
86
size = -EFAULT;
87
else {
88
req = obj->package.elements[1].integer.value;
89
if (tpm_ppi_req_has_parameter(req))
90
size = sysfs_emit(buf, "%llu %llu\n", req,
91
obj->package.elements[2].integer.value);
92
else
93
size = sysfs_emit(buf, "%llu\n", req);
94
}
95
} else if (obj->package.count == 2 &&
96
obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
97
obj->package.elements[1].type == ACPI_TYPE_INTEGER) {
98
if (obj->package.elements[0].integer.value)
99
size = -EFAULT;
100
else
101
size = sysfs_emit(buf, "%llu\n",
102
obj->package.elements[1].integer.value);
103
}
104
105
ACPI_FREE(obj);
106
107
return size;
108
}
109
110
static ssize_t tpm_store_ppi_request(struct device *dev,
111
struct device_attribute *attr,
112
const char *buf, size_t count)
113
{
114
u32 req;
115
u64 ret;
116
int func = TPM_PPI_FN_SUBREQ;
117
union acpi_object *obj, tmp[2];
118
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(2, tmp);
119
struct tpm_chip *chip = to_tpm_chip(dev);
120
u64 rev = TPM_PPI_REVISION_ID_1;
121
122
/*
123
* the function to submit TPM operation request to pre-os environment
124
* is updated with function index from SUBREQ to SUBREQ2 since PPI
125
* version 1.1
126
*/
127
if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
128
TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_SUBREQ2))
129
func = TPM_PPI_FN_SUBREQ2;
130
131
/*
132
* PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS
133
* accept buffer/string/integer type, but some BIOS accept buffer/
134
* string/package type. For PPI version 1.0 and 1.1, use buffer type
135
* for compatibility, and use package type since 1.2 according to spec.
136
*/
137
if (strcmp(chip->ppi_version, "1.3") == 0) {
138
if (sscanf(buf, "%llu %llu", &tmp[0].integer.value,
139
&tmp[1].integer.value) != 2)
140
goto ppi12;
141
rev = TPM_PPI_REVISION_ID_2;
142
tmp[0].type = ACPI_TYPE_INTEGER;
143
tmp[1].type = ACPI_TYPE_INTEGER;
144
} else if (strcmp(chip->ppi_version, "1.2") < 0) {
145
if (sscanf(buf, "%d", &req) != 1)
146
return -EINVAL;
147
argv4.type = ACPI_TYPE_BUFFER;
148
argv4.buffer.length = sizeof(req);
149
argv4.buffer.pointer = (u8 *)&req;
150
} else {
151
ppi12:
152
argv4.package.count = 1;
153
tmp[0].type = ACPI_TYPE_INTEGER;
154
if (sscanf(buf, "%llu", &tmp[0].integer.value) != 1)
155
return -EINVAL;
156
}
157
158
obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
159
&argv4, rev);
160
if (!obj) {
161
return -ENXIO;
162
} else {
163
ret = obj->integer.value;
164
ACPI_FREE(obj);
165
}
166
167
if (ret == 0)
168
return (acpi_status)count;
169
170
return (ret == 1) ? -EPERM : -EFAULT;
171
}
172
173
static ssize_t tpm_show_ppi_transition_action(struct device *dev,
174
struct device_attribute *attr,
175
char *buf)
176
{
177
u32 ret;
178
acpi_status status;
179
union acpi_object *obj = NULL;
180
union acpi_object tmp = {
181
.buffer.type = ACPI_TYPE_BUFFER,
182
.buffer.length = 0,
183
.buffer.pointer = NULL
184
};
185
struct tpm_chip *chip = to_tpm_chip(dev);
186
187
static char *info[] = {
188
"None",
189
"Shutdown",
190
"Reboot",
191
"OS Vendor-specific",
192
"Error",
193
};
194
195
/*
196
* PPI spec defines params[3].type as empty package, but some platforms
197
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
198
* compatibility, define params[3].type as buffer, if PPI version < 1.2
199
*/
200
if (strcmp(chip->ppi_version, "1.2") < 0)
201
obj = &tmp;
202
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
203
ACPI_TYPE_INTEGER, obj, TPM_PPI_REVISION_ID_1);
204
if (!obj) {
205
return -ENXIO;
206
} else {
207
ret = obj->integer.value;
208
ACPI_FREE(obj);
209
}
210
211
if (ret < ARRAY_SIZE(info) - 1)
212
status = sysfs_emit(buf, "%d: %s\n", ret, info[ret]);
213
else
214
status = sysfs_emit(buf, "%d: %s\n", ret,
215
info[ARRAY_SIZE(info) - 1]);
216
return status;
217
}
218
219
static ssize_t tpm_show_ppi_response(struct device *dev,
220
struct device_attribute *attr,
221
char *buf)
222
{
223
acpi_status status = -EINVAL;
224
union acpi_object *obj, *ret_obj;
225
u64 req, res;
226
struct tpm_chip *chip = to_tpm_chip(dev);
227
228
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
229
ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1);
230
if (!obj)
231
return -ENXIO;
232
233
/*
234
* parameter output.pointer should be of package type, including
235
* 3 integers. The first means function return code, the second means
236
* most recent TPM operation request, and the last means response to
237
* the most recent TPM operation request. Only if the first is 0, and
238
* the second integer is not 0, the response makes sense.
239
*/
240
ret_obj = obj->package.elements;
241
if (obj->package.count < 3 ||
242
ret_obj[0].type != ACPI_TYPE_INTEGER ||
243
ret_obj[1].type != ACPI_TYPE_INTEGER ||
244
ret_obj[2].type != ACPI_TYPE_INTEGER)
245
goto cleanup;
246
247
if (ret_obj[0].integer.value) {
248
status = -EFAULT;
249
goto cleanup;
250
}
251
252
req = ret_obj[1].integer.value;
253
res = ret_obj[2].integer.value;
254
if (req) {
255
if (res == 0)
256
status = sysfs_emit(buf, "%llu %s\n", req,
257
"0: Success");
258
else if (res == 0xFFFFFFF0)
259
status = sysfs_emit(buf, "%llu %s\n", req,
260
"0xFFFFFFF0: User Abort");
261
else if (res == 0xFFFFFFF1)
262
status = sysfs_emit(buf, "%llu %s\n", req,
263
"0xFFFFFFF1: BIOS Failure");
264
else if (res >= 1 && res <= 0x00000FFF)
265
status = sysfs_emit(buf, "%llu %llu: %s\n",
266
req, res, "Corresponding TPM error");
267
else
268
status = sysfs_emit(buf, "%llu %llu: %s\n",
269
req, res, "Error");
270
} else {
271
status = sysfs_emit(buf, "%llu: %s\n",
272
req, "No Recent Request");
273
}
274
275
cleanup:
276
ACPI_FREE(obj);
277
return status;
278
}
279
280
static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
281
u32 end)
282
{
283
int i;
284
u32 ret;
285
int len = 0;
286
union acpi_object *obj, tmp;
287
union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp);
288
289
static char *info[] = {
290
"Not implemented",
291
"BIOS only",
292
"Blocked for OS by BIOS",
293
"User required",
294
"User not required",
295
};
296
297
if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1,
298
1 << TPM_PPI_FN_GETOPR))
299
return -EPERM;
300
301
tmp.integer.type = ACPI_TYPE_INTEGER;
302
for (i = start; i <= end; i++) {
303
tmp.integer.value = i;
304
obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
305
ACPI_TYPE_INTEGER, &argv,
306
TPM_PPI_REVISION_ID_1);
307
if (!obj) {
308
return -ENOMEM;
309
} else {
310
ret = obj->integer.value;
311
ACPI_FREE(obj);
312
}
313
314
if (ret > 0 && ret < ARRAY_SIZE(info))
315
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
316
i, ret, info[ret]);
317
}
318
319
return len;
320
}
321
322
static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
323
struct device_attribute *attr,
324
char *buf)
325
{
326
struct tpm_chip *chip = to_tpm_chip(dev);
327
328
return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
329
PPI_TPM_REQ_MAX);
330
}
331
332
static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
333
struct device_attribute *attr,
334
char *buf)
335
{
336
struct tpm_chip *chip = to_tpm_chip(dev);
337
338
return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
339
PPI_VS_REQ_END);
340
}
341
342
static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
343
static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP,
344
tpm_show_ppi_request, tpm_store_ppi_request);
345
static DEVICE_ATTR(transition_action, S_IRUGO,
346
tpm_show_ppi_transition_action, NULL);
347
static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL);
348
static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL);
349
static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL);
350
351
static struct attribute *ppi_attrs[] = {
352
&dev_attr_version.attr,
353
&dev_attr_request.attr,
354
&dev_attr_transition_action.attr,
355
&dev_attr_response.attr,
356
&dev_attr_tcg_operations.attr,
357
&dev_attr_vs_operations.attr, NULL,
358
};
359
static const struct attribute_group ppi_attr_grp = {
360
.name = "ppi",
361
.attrs = ppi_attrs
362
};
363
364
void tpm_add_ppi(struct tpm_chip *chip)
365
{
366
union acpi_object *obj;
367
368
if (!chip->acpi_dev_handle)
369
return;
370
371
if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
372
TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_VERSION))
373
return;
374
375
/* Cache PPI version string. */
376
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid,
377
TPM_PPI_REVISION_ID_1,
378
TPM_PPI_FN_VERSION,
379
NULL, ACPI_TYPE_STRING);
380
if (obj) {
381
strscpy(chip->ppi_version, obj->string.pointer,
382
sizeof(chip->ppi_version));
383
ACPI_FREE(obj);
384
}
385
386
chip->groups[chip->groups_cnt++] = &ppi_attr_grp;
387
}
388
389