1 #include <linux/acpi.h>
2 #include <acpi/acpi_drivers.h>
5 static const u8 tpm_ppi_uuid
[] = {
6 0xA6, 0xFA, 0xDD, 0x3D,
10 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
12 static char *tpm_device_name
= "TPM";
14 #define TPM_PPI_REVISION_ID 1
15 #define TPM_PPI_FN_VERSION 1
16 #define TPM_PPI_FN_SUBREQ 2
17 #define TPM_PPI_FN_GETREQ 3
18 #define TPM_PPI_FN_GETACT 4
19 #define TPM_PPI_FN_GETRSP 5
20 #define TPM_PPI_FN_SUBREQ2 7
21 #define TPM_PPI_FN_GETOPR 8
22 #define PPI_TPM_REQ_MAX 22
23 #define PPI_VS_REQ_START 128
24 #define PPI_VS_REQ_END 255
25 #define PPI_VERSION_LEN 3
27 static acpi_status
ppi_callback(acpi_handle handle
, u32 level
, void *context
,
30 acpi_status status
= AE_OK
;
31 struct acpi_buffer buffer
= { ACPI_ALLOCATE_BUFFER
, NULL
};
33 if (ACPI_SUCCESS(acpi_get_name(handle
, ACPI_FULL_PATHNAME
, &buffer
))) {
34 if (strstr(buffer
.pointer
, context
) != NULL
) {
35 *return_value
= handle
;
36 status
= AE_CTRL_TERMINATE
;
38 kfree(buffer
.pointer
);
44 static inline void ppi_assign_params(union acpi_object params
[4],
47 params
[0].type
= ACPI_TYPE_BUFFER
;
48 params
[0].buffer
.length
= sizeof(tpm_ppi_uuid
);
49 params
[0].buffer
.pointer
= (char *)tpm_ppi_uuid
;
50 params
[1].type
= ACPI_TYPE_INTEGER
;
51 params
[1].integer
.value
= TPM_PPI_REVISION_ID
;
52 params
[2].type
= ACPI_TYPE_INTEGER
;
53 params
[2].integer
.value
= function_num
;
54 params
[3].type
= ACPI_TYPE_PACKAGE
;
55 params
[3].package
.count
= 0;
56 params
[3].package
.elements
= NULL
;
59 static ssize_t
tpm_show_ppi_version(struct device
*dev
,
60 struct device_attribute
*attr
, char *buf
)
64 struct acpi_object_list input
;
65 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
66 union acpi_object params
[4];
67 union acpi_object
*obj
;
70 ppi_assign_params(params
, TPM_PPI_FN_VERSION
);
71 input
.pointer
= params
;
72 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
, ACPI_ROOT_OBJECT
,
73 ACPI_UINT32_MAX
, ppi_callback
, NULL
,
74 tpm_device_name
, &handle
);
75 if (ACPI_FAILURE(status
))
78 status
= acpi_evaluate_object_typed(handle
, "_DSM", &input
, &output
,
80 if (ACPI_FAILURE(status
))
82 obj
= (union acpi_object
*)output
.pointer
;
83 status
= scnprintf(buf
, PAGE_SIZE
, "%s\n", obj
->string
.pointer
);
84 kfree(output
.pointer
);
88 static ssize_t
tpm_show_ppi_request(struct device
*dev
,
89 struct device_attribute
*attr
, char *buf
)
93 struct acpi_object_list input
;
94 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
95 union acpi_object params
[4];
96 union acpi_object
*ret_obj
;
99 ppi_assign_params(params
, TPM_PPI_FN_GETREQ
);
100 input
.pointer
= params
;
101 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
, ACPI_ROOT_OBJECT
,
102 ACPI_UINT32_MAX
, ppi_callback
, NULL
,
103 tpm_device_name
, &handle
);
104 if (ACPI_FAILURE(status
))
107 status
= acpi_evaluate_object_typed(handle
, "_DSM", &input
, &output
,
109 if (ACPI_FAILURE(status
))
112 * output.pointer should be of package type, including two integers.
113 * The first is function return code, 0 means success and 1 means
114 * error. The second is pending TPM operation requested by the OS, 0
115 * means none and >0 means operation value.
117 ret_obj
= ((union acpi_object
*)output
.pointer
)->package
.elements
;
118 if (ret_obj
->type
== ACPI_TYPE_INTEGER
) {
119 if (ret_obj
->integer
.value
) {
124 if (ret_obj
->type
== ACPI_TYPE_INTEGER
)
125 status
= scnprintf(buf
, PAGE_SIZE
, "%llu\n",
126 ret_obj
->integer
.value
);
133 kfree(output
.pointer
);
137 static ssize_t
tpm_store_ppi_request(struct device
*dev
,
138 struct device_attribute
*attr
,
139 const char *buf
, size_t count
)
141 char version
[PPI_VERSION_LEN
+ 1];
144 struct acpi_object_list input
;
145 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
146 union acpi_object params
[4];
147 union acpi_object obj
;
152 ppi_assign_params(params
, TPM_PPI_FN_VERSION
);
153 input
.pointer
= params
;
154 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
, ACPI_ROOT_OBJECT
,
155 ACPI_UINT32_MAX
, ppi_callback
, NULL
,
156 tpm_device_name
, &handle
);
157 if (ACPI_FAILURE(status
))
160 status
= acpi_evaluate_object_typed(handle
, "_DSM", &input
, &output
,
162 if (ACPI_FAILURE(status
))
165 ((union acpi_object
*)output
.pointer
)->string
.pointer
,
166 PPI_VERSION_LEN
+ 1);
167 kfree(output
.pointer
);
168 output
.length
= ACPI_ALLOCATE_BUFFER
;
169 output
.pointer
= NULL
;
171 * the function to submit TPM operation request to pre-os environment
172 * is updated with function index from SUBREQ to SUBREQ2 since PPI
175 if (strcmp(version
, "1.1") < 0)
176 params
[2].integer
.value
= TPM_PPI_FN_SUBREQ
;
178 params
[2].integer
.value
= TPM_PPI_FN_SUBREQ2
;
180 * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS
181 * accept buffer/string/integer type, but some BIOS accept buffer/
182 * string/package type. For PPI version 1.0 and 1.1, use buffer type
183 * for compatibility, and use package type since 1.2 according to spec.
185 if (strcmp(version
, "1.2") < 0) {
186 params
[3].type
= ACPI_TYPE_BUFFER
;
187 params
[3].buffer
.length
= sizeof(req
);
188 sscanf(buf
, "%d", &req
);
189 params
[3].buffer
.pointer
= (char *)&req
;
191 params
[3].package
.count
= 1;
192 obj
.type
= ACPI_TYPE_INTEGER
;
193 sscanf(buf
, "%llu", &obj
.integer
.value
);
194 params
[3].package
.elements
= &obj
;
197 status
= acpi_evaluate_object_typed(handle
, "_DSM", &input
, &output
,
199 if (ACPI_FAILURE(status
))
201 ret
= ((union acpi_object
*)output
.pointer
)->integer
.value
;
203 status
= (acpi_status
)count
;
208 kfree(output
.pointer
);
212 static ssize_t
tpm_show_ppi_transition_action(struct device
*dev
,
213 struct device_attribute
*attr
,
216 char version
[PPI_VERSION_LEN
+ 1];
219 struct acpi_object_list input
;
220 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
221 union acpi_object params
[4];
227 "OS Vendor-specific",
231 ppi_assign_params(params
, TPM_PPI_FN_VERSION
);
232 input
.pointer
= params
;
233 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
, ACPI_ROOT_OBJECT
,
234 ACPI_UINT32_MAX
, ppi_callback
, NULL
,
235 tpm_device_name
, &handle
);
236 if (ACPI_FAILURE(status
))
239 status
= acpi_evaluate_object_typed(handle
, "_DSM", &input
, &output
,
241 if (ACPI_FAILURE(status
))
244 ((union acpi_object
*)output
.pointer
)->string
.pointer
,
245 PPI_VERSION_LEN
+ 1);
247 * PPI spec defines params[3].type as empty package, but some platforms
248 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
249 * compatibility, define params[3].type as buffer, if PPI version < 1.2
251 if (strcmp(version
, "1.2") < 0) {
252 params
[3].type
= ACPI_TYPE_BUFFER
;
253 params
[3].buffer
.length
= 0;
254 params
[3].buffer
.pointer
= NULL
;
256 params
[2].integer
.value
= TPM_PPI_FN_GETACT
;
257 kfree(output
.pointer
);
258 output
.length
= ACPI_ALLOCATE_BUFFER
;
259 output
.pointer
= NULL
;
260 status
= acpi_evaluate_object_typed(handle
, "_DSM", &input
, &output
,
262 if (ACPI_FAILURE(status
))
264 ret
= ((union acpi_object
*)output
.pointer
)->integer
.value
;
265 if (ret
< ARRAY_SIZE(info
) - 1)
266 status
= scnprintf(buf
, PAGE_SIZE
, "%d: %s\n", ret
, info
[ret
]);
268 status
= scnprintf(buf
, PAGE_SIZE
, "%d: %s\n", ret
,
269 info
[ARRAY_SIZE(info
)-1]);
270 kfree(output
.pointer
);
274 static ssize_t
tpm_show_ppi_response(struct device
*dev
,
275 struct device_attribute
*attr
,
280 struct acpi_object_list input
;
281 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
282 union acpi_object params
[4];
283 union acpi_object
*ret_obj
;
287 ppi_assign_params(params
, TPM_PPI_FN_GETRSP
);
288 input
.pointer
= params
;
289 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
, ACPI_ROOT_OBJECT
,
290 ACPI_UINT32_MAX
, ppi_callback
, NULL
,
291 tpm_device_name
, &handle
);
292 if (ACPI_FAILURE(status
))
295 status
= acpi_evaluate_object_typed(handle
, "_DSM", &input
, &output
,
297 if (ACPI_FAILURE(status
))
300 * parameter output.pointer should be of package type, including
301 * 3 integers. The first means function return code, the second means
302 * most recent TPM operation request, and the last means response to
303 * the most recent TPM operation request. Only if the first is 0, and
304 * the second integer is not 0, the response makes sense.
306 ret_obj
= ((union acpi_object
*)output
.pointer
)->package
.elements
;
307 if (ret_obj
->type
!= ACPI_TYPE_INTEGER
) {
311 if (ret_obj
->integer
.value
) {
316 if (ret_obj
->type
!= ACPI_TYPE_INTEGER
) {
320 if (ret_obj
->integer
.value
) {
321 req
= ret_obj
->integer
.value
;
323 if (ret_obj
->type
!= ACPI_TYPE_INTEGER
) {
327 if (ret_obj
->integer
.value
== 0)
328 status
= scnprintf(buf
, PAGE_SIZE
, "%llu %s\n", req
,
330 else if (ret_obj
->integer
.value
== 0xFFFFFFF0)
331 status
= scnprintf(buf
, PAGE_SIZE
, "%llu %s\n", req
,
332 "0xFFFFFFF0: User Abort");
333 else if (ret_obj
->integer
.value
== 0xFFFFFFF1)
334 status
= scnprintf(buf
, PAGE_SIZE
, "%llu %s\n", req
,
335 "0xFFFFFFF1: BIOS Failure");
336 else if (ret_obj
->integer
.value
>= 1 &&
337 ret_obj
->integer
.value
<= 0x00000FFF)
338 status
= scnprintf(buf
, PAGE_SIZE
, "%llu %llu: %s\n",
339 req
, ret_obj
->integer
.value
,
340 "Corresponding TPM error");
342 status
= scnprintf(buf
, PAGE_SIZE
, "%llu %llu: %s\n",
343 req
, ret_obj
->integer
.value
,
346 status
= scnprintf(buf
, PAGE_SIZE
, "%llu: %s\n",
347 ret_obj
->integer
.value
, "No Recent Request");
350 kfree(output
.pointer
);
354 static ssize_t
show_ppi_operations(char *buf
, u32 start
, u32 end
)
357 char version
[PPI_VERSION_LEN
+ 1];
360 struct acpi_object_list input
;
361 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
362 union acpi_object params
[4];
363 union acpi_object obj
;
369 "Blocked for OS by BIOS",
374 ppi_assign_params(params
, TPM_PPI_FN_VERSION
);
375 input
.pointer
= params
;
376 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
, ACPI_ROOT_OBJECT
,
377 ACPI_UINT32_MAX
, ppi_callback
, NULL
,
378 tpm_device_name
, &handle
);
379 if (ACPI_FAILURE(status
))
382 status
= acpi_evaluate_object_typed(handle
, "_DSM", &input
, &output
,
384 if (ACPI_FAILURE(status
))
388 ((union acpi_object
*)output
.pointer
)->string
.pointer
,
389 PPI_VERSION_LEN
+ 1);
390 kfree(output
.pointer
);
391 output
.length
= ACPI_ALLOCATE_BUFFER
;
392 output
.pointer
= NULL
;
393 if (strcmp(version
, "1.2") < 0)
396 params
[2].integer
.value
= TPM_PPI_FN_GETOPR
;
397 params
[3].package
.count
= 1;
398 obj
.type
= ACPI_TYPE_INTEGER
;
399 params
[3].package
.elements
= &obj
;
400 for (i
= start
; i
<= end
; i
++) {
401 obj
.integer
.value
= i
;
402 status
= acpi_evaluate_object_typed(handle
, "_DSM",
403 &input
, &output
, ACPI_TYPE_INTEGER
);
404 if (ACPI_FAILURE(status
))
407 ret
= ((union acpi_object
*)output
.pointer
)->integer
.value
;
408 if (ret
> 0 && ret
< ARRAY_SIZE(info
))
409 str
+= scnprintf(str
, PAGE_SIZE
, "%d %d: %s\n",
411 kfree(output
.pointer
);
412 output
.length
= ACPI_ALLOCATE_BUFFER
;
413 output
.pointer
= NULL
;
418 static ssize_t
tpm_show_ppi_tcg_operations(struct device
*dev
,
419 struct device_attribute
*attr
,
422 return show_ppi_operations(buf
, 0, PPI_TPM_REQ_MAX
);
425 static ssize_t
tpm_show_ppi_vs_operations(struct device
*dev
,
426 struct device_attribute
*attr
,
429 return show_ppi_operations(buf
, PPI_VS_REQ_START
, PPI_VS_REQ_END
);
432 static DEVICE_ATTR(version
, S_IRUGO
, tpm_show_ppi_version
, NULL
);
433 static DEVICE_ATTR(request
, S_IRUGO
| S_IWUSR
| S_IWGRP
,
434 tpm_show_ppi_request
, tpm_store_ppi_request
);
435 static DEVICE_ATTR(transition_action
, S_IRUGO
,
436 tpm_show_ppi_transition_action
, NULL
);
437 static DEVICE_ATTR(response
, S_IRUGO
, tpm_show_ppi_response
, NULL
);
438 static DEVICE_ATTR(tcg_operations
, S_IRUGO
, tpm_show_ppi_tcg_operations
, NULL
);
439 static DEVICE_ATTR(vs_operations
, S_IRUGO
, tpm_show_ppi_vs_operations
, NULL
);
441 static struct attribute
*ppi_attrs
[] = {
442 &dev_attr_version
.attr
,
443 &dev_attr_request
.attr
,
444 &dev_attr_transition_action
.attr
,
445 &dev_attr_response
.attr
,
446 &dev_attr_tcg_operations
.attr
,
447 &dev_attr_vs_operations
.attr
, NULL
,
449 static struct attribute_group ppi_attr_grp
= {
454 int tpm_add_ppi(struct kobject
*parent
)
456 return sysfs_create_group(parent
, &ppi_attr_grp
);
458 EXPORT_SYMBOL_GPL(tpm_add_ppi
);
460 void tpm_remove_ppi(struct kobject
*parent
)
462 sysfs_remove_group(parent
, &ppi_attr_grp
);
464 EXPORT_SYMBOL_GPL(tpm_remove_ppi
);
466 MODULE_LICENSE("GPL");