aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2014-12-12 14:46:35 -0500
committerPeter Huewe <peterhuewe@gmx.de>2015-01-17 08:00:09 -0500
commit0dc553652102c55a43eb1ab52e2049e478469f53 (patch)
tree1ba8392161078a209216c4e265191dd325379a6a
parentafb5abc262e962089ef2d7c2bbf71bb6f53a2a78 (diff)
tpm: fix raciness of PPI interface lookup
Traversal of the ACPI device tree was not done right. PPI interface should be looked up only from the ACPI device that is the platform device for the TPM. This could cause problems with systems with two TPM chips such as 4th gen Intel systems. In addition, added the missing license and copyright platter to the tpm_ppi.c. Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Reviewed-by: Jasob Gunthorpe <jason.gunthorpe@obsidianresearch.com> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com> Tested-by: Scot Doyle <lkml14@scotdoyle.com> Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
-rw-r--r--drivers/char/tpm/tpm-chip.c4
-rw-r--r--drivers/char/tpm/tpm.h17
-rw-r--r--drivers/char/tpm/tpm_ppi.c141
-rw-r--r--drivers/char/tpm/tpm_tis.c14
4 files changed, 112 insertions, 64 deletions
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 7dc9999e2d54..64102de91ca3 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -147,7 +147,7 @@ int tpm_chip_register(struct tpm_chip *chip)
147 if (rc) 147 if (rc)
148 goto del_misc; 148 goto del_misc;
149 149
150 rc = tpm_add_ppi(&chip->dev->kobj); 150 rc = tpm_add_ppi(chip);
151 if (rc) 151 if (rc)
152 goto del_sysfs; 152 goto del_sysfs;
153 153
@@ -191,7 +191,7 @@ void tpm_chip_unregister(struct tpm_chip *chip)
191 191
192 if (chip->bios_dir) 192 if (chip->bios_dir)
193 tpm_bios_log_teardown(chip->bios_dir); 193 tpm_bios_log_teardown(chip->bios_dir);
194 tpm_remove_ppi(&chip->dev->kobj); 194 tpm_remove_ppi(chip);
195 tpm_sysfs_del_device(chip); 195 tpm_sysfs_del_device(chip);
196 196
197 tpm_dev_del_device(chip); 197 tpm_dev_del_device(chip);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 72ff18c872d3..3409acf953f3 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -27,6 +27,7 @@
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/io.h> 28#include <linux/io.h>
29#include <linux/tpm.h> 29#include <linux/tpm.h>
30#include <linux/acpi.h>
30 31
31enum tpm_const { 32enum tpm_const {
32 TPM_MINOR = 224, /* officially assigned */ 33 TPM_MINOR = 224, /* officially assigned */
@@ -94,8 +95,11 @@ struct tpm_vendor_specific {
94#define TPM_VID_WINBOND 0x1050 95#define TPM_VID_WINBOND 0x1050
95#define TPM_VID_STM 0x104A 96#define TPM_VID_STM 0x104A
96 97
98#define TPM_PPI_VERSION_LEN 3
99
97enum tpm_chip_flags { 100enum tpm_chip_flags {
98 TPM_CHIP_FLAG_REGISTERED = BIT(0), 101 TPM_CHIP_FLAG_REGISTERED = BIT(0),
102 TPM_CHIP_FLAG_PPI = BIT(1),
99}; 103};
100 104
101struct tpm_chip { 105struct tpm_chip {
@@ -114,6 +118,11 @@ struct tpm_chip {
114 118
115 struct dentry **bios_dir; 119 struct dentry **bios_dir;
116 120
121#ifdef CONFIG_ACPI
122 acpi_handle acpi_dev_handle;
123 char ppi_version[TPM_PPI_VERSION_LEN + 1];
124#endif /* CONFIG_ACPI */
125
117 struct list_head list; 126 struct list_head list;
118}; 127};
119 128
@@ -345,15 +354,15 @@ void tpm_sysfs_del_device(struct tpm_chip *chip);
345int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); 354int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
346 355
347#ifdef CONFIG_ACPI 356#ifdef CONFIG_ACPI
348extern int tpm_add_ppi(struct kobject *); 357extern int tpm_add_ppi(struct tpm_chip *chip);
349extern void tpm_remove_ppi(struct kobject *); 358extern void tpm_remove_ppi(struct tpm_chip *chip);
350#else 359#else
351static inline int tpm_add_ppi(struct kobject *parent) 360static inline int tpm_add_ppi(struct tpm_chip *chip)
352{ 361{
353 return 0; 362 return 0;
354} 363}
355 364
356static inline void tpm_remove_ppi(struct kobject *parent) 365static inline void tpm_remove_ppi(struct tpm_chip *chip)
357{ 366{
358} 367}
359#endif 368#endif
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
index 61dcc8011ec7..af48c56f642f 100644
--- a/drivers/char/tpm/tpm_ppi.c
+++ b/drivers/char/tpm/tpm_ppi.c
@@ -1,3 +1,22 @@
1/*
2 * Copyright (C) 2012-2014 Intel Corporation
3 *
4 * Authors:
5 * Xiaoyan Zhang <xiaoyan.zhang@intel.com>
6 * Jiang Liu <jiang.liu@linux.intel.com>
7 * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
8 *
9 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
10 *
11 * This file contains implementation of the sysfs interface for PPI.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; version 2
16 * of the License.
17 */
18
19
1#include <linux/acpi.h> 20#include <linux/acpi.h>
2#include "tpm.h" 21#include "tpm.h"
3 22
@@ -12,7 +31,6 @@
12#define PPI_TPM_REQ_MAX 22 31#define PPI_TPM_REQ_MAX 22
13#define PPI_VS_REQ_START 128 32#define PPI_VS_REQ_START 128
14#define PPI_VS_REQ_END 255 33#define PPI_VS_REQ_END 255
15#define PPI_VERSION_LEN 3
16 34
17static const u8 tpm_ppi_uuid[] = { 35static const u8 tpm_ppi_uuid[] = {
18 0xA6, 0xFA, 0xDD, 0x3D, 36 0xA6, 0xFA, 0xDD, 0x3D,
@@ -22,45 +40,22 @@ static const u8 tpm_ppi_uuid[] = {
22 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 40 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
23}; 41};
24 42
25static char tpm_ppi_version[PPI_VERSION_LEN + 1];
26static acpi_handle tpm_ppi_handle;
27
28static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
29 void **return_value)
30{
31 union acpi_object *obj;
32
33 if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
34 1 << TPM_PPI_FN_VERSION))
35 return AE_OK;
36
37 /* Cache version string */
38 obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
39 TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
40 NULL, ACPI_TYPE_STRING);
41 if (obj) {
42 strlcpy(tpm_ppi_version, obj->string.pointer,
43 PPI_VERSION_LEN + 1);
44 ACPI_FREE(obj);
45 }
46
47 *return_value = handle;
48
49 return AE_CTRL_TERMINATE;
50}
51
52static inline union acpi_object * 43static inline union acpi_object *
53tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4) 44tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
45 union acpi_object *argv4)
54{ 46{
55 BUG_ON(!tpm_ppi_handle); 47 BUG_ON(!ppi_handle);
56 return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid, 48 return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid,
57 TPM_PPI_REVISION_ID, func, argv4, type); 49 TPM_PPI_REVISION_ID,
50 func, argv4, type);
58} 51}
59 52
60static ssize_t tpm_show_ppi_version(struct device *dev, 53static ssize_t tpm_show_ppi_version(struct device *dev,
61 struct device_attribute *attr, char *buf) 54 struct device_attribute *attr, char *buf)
62{ 55{
63 return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version); 56 struct tpm_chip *chip = dev_get_drvdata(dev);
57
58 return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
64} 59}
65 60
66static ssize_t tpm_show_ppi_request(struct device *dev, 61static ssize_t tpm_show_ppi_request(struct device *dev,
@@ -68,8 +63,10 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
68{ 63{
69 ssize_t size = -EINVAL; 64 ssize_t size = -EINVAL;
70 union acpi_object *obj; 65 union acpi_object *obj;
66 struct tpm_chip *chip = dev_get_drvdata(dev);
71 67
72 obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL); 68 obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
69 ACPI_TYPE_PACKAGE, NULL);
73 if (!obj) 70 if (!obj)
74 return -ENXIO; 71 return -ENXIO;
75 72
@@ -103,14 +100,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
103 int func = TPM_PPI_FN_SUBREQ; 100 int func = TPM_PPI_FN_SUBREQ;
104 union acpi_object *obj, tmp; 101 union acpi_object *obj, tmp;
105 union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); 102 union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
103 struct tpm_chip *chip = dev_get_drvdata(dev);
106 104
107 /* 105 /*
108 * the function to submit TPM operation request to pre-os environment 106 * the function to submit TPM operation request to pre-os environment
109 * is updated with function index from SUBREQ to SUBREQ2 since PPI 107 * is updated with function index from SUBREQ to SUBREQ2 since PPI
110 * version 1.1 108 * version 1.1
111 */ 109 */
112 if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, 110 if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
113 1 << TPM_PPI_FN_SUBREQ2)) 111 TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
114 func = TPM_PPI_FN_SUBREQ2; 112 func = TPM_PPI_FN_SUBREQ2;
115 113
116 /* 114 /*
@@ -119,7 +117,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
119 * string/package type. For PPI version 1.0 and 1.1, use buffer type 117 * string/package type. For PPI version 1.0 and 1.1, use buffer type
120 * for compatibility, and use package type since 1.2 according to spec. 118 * for compatibility, and use package type since 1.2 according to spec.
121 */ 119 */
122 if (strcmp(tpm_ppi_version, "1.2") < 0) { 120 if (strcmp(chip->ppi_version, "1.2") < 0) {
123 if (sscanf(buf, "%d", &req) != 1) 121 if (sscanf(buf, "%d", &req) != 1)
124 return -EINVAL; 122 return -EINVAL;
125 argv4.type = ACPI_TYPE_BUFFER; 123 argv4.type = ACPI_TYPE_BUFFER;
@@ -131,7 +129,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
131 return -EINVAL; 129 return -EINVAL;
132 } 130 }
133 131
134 obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4); 132 obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
133 &argv4);
135 if (!obj) { 134 if (!obj) {
136 return -ENXIO; 135 return -ENXIO;
137 } else { 136 } else {
@@ -157,6 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
157 .buffer.length = 0, 156 .buffer.length = 0,
158 .buffer.pointer = NULL 157 .buffer.pointer = NULL
159 }; 158 };
159 struct tpm_chip *chip = dev_get_drvdata(dev);
160 160
161 static char *info[] = { 161 static char *info[] = {
162 "None", 162 "None",
@@ -171,9 +171,10 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
171 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for 171 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
172 * compatibility, define params[3].type as buffer, if PPI version < 1.2 172 * compatibility, define params[3].type as buffer, if PPI version < 1.2
173 */ 173 */
174 if (strcmp(tpm_ppi_version, "1.2") < 0) 174 if (strcmp(chip->ppi_version, "1.2") < 0)
175 obj = &tmp; 175 obj = &tmp;
176 obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj); 176 obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
177 ACPI_TYPE_INTEGER, obj);
177 if (!obj) { 178 if (!obj) {
178 return -ENXIO; 179 return -ENXIO;
179 } else { 180 } else {
@@ -196,8 +197,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
196 acpi_status status = -EINVAL; 197 acpi_status status = -EINVAL;
197 union acpi_object *obj, *ret_obj; 198 union acpi_object *obj, *ret_obj;
198 u64 req, res; 199 u64 req, res;
200 struct tpm_chip *chip = dev_get_drvdata(dev);
199 201
200 obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL); 202 obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
203 ACPI_TYPE_PACKAGE, NULL);
201 if (!obj) 204 if (!obj)
202 return -ENXIO; 205 return -ENXIO;
203 206
@@ -248,7 +251,8 @@ cleanup:
248 return status; 251 return status;
249} 252}
250 253
251static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) 254static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
255 u32 end)
252{ 256{
253 int i; 257 int i;
254 u32 ret; 258 u32 ret;
@@ -264,14 +268,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
264 "User not required", 268 "User not required",
265 }; 269 };
266 270
267 if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, 271 if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
268 1 << TPM_PPI_FN_GETOPR)) 272 1 << TPM_PPI_FN_GETOPR))
269 return -EPERM; 273 return -EPERM;
270 274
271 tmp.integer.type = ACPI_TYPE_INTEGER; 275 tmp.integer.type = ACPI_TYPE_INTEGER;
272 for (i = start; i <= end; i++) { 276 for (i = start; i <= end; i++) {
273 tmp.integer.value = i; 277 tmp.integer.value = i;
274 obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv); 278 obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
279 ACPI_TYPE_INTEGER, &argv);
275 if (!obj) { 280 if (!obj) {
276 return -ENOMEM; 281 return -ENOMEM;
277 } else { 282 } else {
@@ -291,14 +296,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
291 struct device_attribute *attr, 296 struct device_attribute *attr,
292 char *buf) 297 char *buf)
293{ 298{
294 return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX); 299 struct tpm_chip *chip = dev_get_drvdata(dev);
300
301 return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
302 PPI_TPM_REQ_MAX);
295} 303}
296 304
297static ssize_t tpm_show_ppi_vs_operations(struct device *dev, 305static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
298 struct device_attribute *attr, 306 struct device_attribute *attr,
299 char *buf) 307 char *buf)
300{ 308{
301 return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END); 309 struct tpm_chip *chip = dev_get_drvdata(dev);
310
311 return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
312 PPI_VS_REQ_END);
302} 313}
303 314
304static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); 315static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
@@ -323,16 +334,38 @@ static struct attribute_group ppi_attr_grp = {
323 .attrs = ppi_attrs 334 .attrs = ppi_attrs
324}; 335};
325 336
326int tpm_add_ppi(struct kobject *parent) 337int tpm_add_ppi(struct tpm_chip *chip)
327{ 338{
328 /* Cache TPM ACPI handle and version string */ 339 union acpi_object *obj;
329 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, 340 int rc;
330 ppi_callback, NULL, NULL, &tpm_ppi_handle); 341
331 return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0; 342 if (!chip->acpi_dev_handle)
343 return 0;
344
345 if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
346 TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
347 return 0;
348
349 /* Cache PPI version string. */
350 obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
351 TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
352 NULL, ACPI_TYPE_STRING);
353 if (obj) {
354 strlcpy(chip->ppi_version, obj->string.pointer,
355 sizeof(chip->ppi_version));
356 ACPI_FREE(obj);
357 }
358
359 rc = sysfs_create_group(&chip->dev->kobj, &ppi_attr_grp);
360
361 if (!rc)
362 chip->flags |= TPM_CHIP_FLAG_PPI;
363
364 return rc;
332} 365}
333 366
334void tpm_remove_ppi(struct kobject *parent) 367void tpm_remove_ppi(struct tpm_chip *chip)
335{ 368{
336 if (tpm_ppi_handle) 369 if (chip->flags & TPM_CHIP_FLAG_PPI)
337 sysfs_remove_group(parent, &ppi_attr_grp); 370 sysfs_remove_group(&chip->dev->kobj, &ppi_attr_grp);
338} 371}
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 36f4fec11c2a..9695850d2afa 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -580,8 +580,9 @@ static void tpm_tis_remove(struct tpm_chip *chip)
580 release_locality(chip, chip->vendor.locality, 1); 580 release_locality(chip, chip->vendor.locality, 1);
581} 581}
582 582
583static int tpm_tis_init(struct device *dev, resource_size_t start, 583static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
584 resource_size_t len, unsigned int irq) 584 resource_size_t start, resource_size_t len,
585 unsigned int irq)
585{ 586{
586 u32 vendor, intfcaps, intmask; 587 u32 vendor, intfcaps, intmask;
587 int rc, i, irq_s, irq_e, probe; 588 int rc, i, irq_s, irq_e, probe;
@@ -597,6 +598,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
597 return PTR_ERR(chip); 598 return PTR_ERR(chip);
598 599
599 chip->vendor.priv = priv; 600 chip->vendor.priv = priv;
601 chip->acpi_dev_handle = acpi_dev_handle;
600 602
601 chip->vendor.iobase = devm_ioremap(dev, start, len); 603 chip->vendor.iobase = devm_ioremap(dev, start, len);
602 if (!chip->vendor.iobase) 604 if (!chip->vendor.iobase)
@@ -827,6 +829,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
827{ 829{
828 resource_size_t start, len; 830 resource_size_t start, len;
829 unsigned int irq = 0; 831 unsigned int irq = 0;
832 acpi_handle acpi_dev_handle = NULL;
830 833
831 start = pnp_mem_start(pnp_dev, 0); 834 start = pnp_mem_start(pnp_dev, 0);
832 len = pnp_mem_len(pnp_dev, 0); 835 len = pnp_mem_len(pnp_dev, 0);
@@ -839,7 +842,10 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
839 if (is_itpm(pnp_dev)) 842 if (is_itpm(pnp_dev))
840 itpm = true; 843 itpm = true;
841 844
842 return tpm_tis_init(&pnp_dev->dev, start, len, irq); 845 if (pnp_acpi_device(pnp_dev))
846 acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
847
848 return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq);
843} 849}
844 850
845static struct pnp_device_id tpm_pnp_tbl[] = { 851static struct pnp_device_id tpm_pnp_tbl[] = {
@@ -907,7 +913,7 @@ static int __init init_tis(void)
907 rc = PTR_ERR(pdev); 913 rc = PTR_ERR(pdev);
908 goto err_dev; 914 goto err_dev;
909 } 915 }
910 rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0); 916 rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0);
911 if (rc) 917 if (rc)
912 goto err_init; 918 goto err_init;
913 return 0; 919 return 0;