diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 16:57:44 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 16:57:44 -0500 |
| commit | 683b96f4d1d132fcefa4a0bd11916649800d7361 (patch) | |
| tree | 95ba7e1c1edc15639be080773b4c32d2be60b0a4 /drivers | |
| parent | 0f1d6dfe03ca4e36132221b918499c6f0b0f048d (diff) | |
| parent | 50523a29d900d5a403e0352d3d7aeda6a33df25c (diff) | |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"Generally pretty quiet for this release. Highlights:
Yama:
- allow ptrace access for original parent after re-parenting
TPM:
- add documentation
- many bugfixes & cleanups
- define a generic open() method for ascii & bios measurements
Integrity:
- Harden against malformed xattrs
SELinux:
- bugfixes & cleanups
Smack:
- Remove unnecessary smack_known_invalid label
- Do not apply star label in smack_setprocattr hook
- parse mnt opts after privileges check (fixes unpriv DoS vuln)"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (56 commits)
Yama: allow access for the current ptrace parent
tpm: adjust return value of tpm_read_log
tpm: vtpm_proxy: conditionally call tpm_chip_unregister
tpm: Fix handling of missing event log
tpm: Check the bios_dir entry for NULL before accessing it
tpm: return -ENODEV if np is not set
tpm: cleanup of printk error messages
tpm: replace of_find_node_by_name() with dev of_node property
tpm: redefine read_log() to handle ACPI/OF at runtime
tpm: fix the missing .owner in tpm_bios_measurements_ops
tpm: have event log use the tpm_chip
tpm: drop tpm1_chip_register(/unregister)
tpm: replace dynamically allocated bios_dir with a static array
tpm: replace symbolic permission with octal for securityfs files
char: tpm: fix kerneldoc tpm2_unseal_trusted name typo
tpm_tis: Allow tpm_tis to be bound using DT
tpm, tpm_vtpm_proxy: add kdoc comments for VTPM_PROXY_IOC_NEW_DEV
tpm: Only call pm_runtime_get_sync if device has a parent
tpm: define a generic open() method for ascii & bios measurements
Documentation: tpm: add the Physical TPM device tree binding documentation
...
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/char/tpm/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/char/tpm/Makefile | 14 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm-chip.c | 38 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm-interface.c | 110 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm-sysfs.c | 7 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm.h | 41 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 2 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_acpi.c | 46 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_crb.c | 173 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_eventlog.c | 230 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_eventlog.h | 22 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_of.c | 48 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_tis.c | 11 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_tis_core.c | 64 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_vtpm_proxy.c | 85 | ||||
| -rw-r--r-- | drivers/char/tpm/xen-tpmfront.c | 1 |
16 files changed, 519 insertions, 375 deletions
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 9faa0b1e7766..277186d3b668 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig | |||
| @@ -32,7 +32,7 @@ config TCG_TIS_CORE | |||
| 32 | 32 | ||
| 33 | config TCG_TIS | 33 | config TCG_TIS |
| 34 | tristate "TPM Interface Specification 1.2 Interface / TPM 2.0 FIFO Interface" | 34 | tristate "TPM Interface Specification 1.2 Interface / TPM 2.0 FIFO Interface" |
| 35 | depends on X86 | 35 | depends on X86 || OF |
| 36 | select TCG_TIS_CORE | 36 | select TCG_TIS_CORE |
| 37 | ---help--- | 37 | ---help--- |
| 38 | If you have a TPM security chip that is compliant with the | 38 | If you have a TPM security chip that is compliant with the |
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index a385fb8c17de..a05b1ebd0b26 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile | |||
| @@ -2,16 +2,10 @@ | |||
| 2 | # Makefile for the kernel tpm device drivers. | 2 | # Makefile for the kernel tpm device drivers. |
| 3 | # | 3 | # |
| 4 | obj-$(CONFIG_TCG_TPM) += tpm.o | 4 | obj-$(CONFIG_TCG_TPM) += tpm.o |
| 5 | tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o | 5 | tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ |
| 6 | tpm-$(CONFIG_ACPI) += tpm_ppi.o | 6 | tpm_eventlog.o |
| 7 | 7 | tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o | |
| 8 | ifdef CONFIG_ACPI | 8 | tpm-$(CONFIG_OF) += tpm_of.o |
| 9 | tpm-y += tpm_eventlog.o tpm_acpi.o | ||
| 10 | else | ||
| 11 | ifdef CONFIG_TCG_IBMVTPM | ||
| 12 | tpm-y += tpm_eventlog.o tpm_of.o | ||
| 13 | endif | ||
| 14 | endif | ||
| 15 | obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o | 9 | obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o |
| 16 | obj-$(CONFIG_TCG_TIS) += tpm_tis.o | 10 | obj-$(CONFIG_TCG_TIS) += tpm_tis.o |
| 17 | obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o | 11 | obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o |
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index e5950131bd90..7a4869151d3b 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c | |||
| @@ -127,6 +127,7 @@ static void tpm_dev_release(struct device *dev) | |||
| 127 | idr_remove(&dev_nums_idr, chip->dev_num); | 127 | idr_remove(&dev_nums_idr, chip->dev_num); |
| 128 | mutex_unlock(&idr_lock); | 128 | mutex_unlock(&idr_lock); |
| 129 | 129 | ||
| 130 | kfree(chip->log.bios_event_log); | ||
| 130 | kfree(chip); | 131 | kfree(chip); |
| 131 | } | 132 | } |
| 132 | 133 | ||
| @@ -276,27 +277,6 @@ static void tpm_del_char_device(struct tpm_chip *chip) | |||
| 276 | up_write(&chip->ops_sem); | 277 | up_write(&chip->ops_sem); |
| 277 | } | 278 | } |
| 278 | 279 | ||
| 279 | static int tpm1_chip_register(struct tpm_chip *chip) | ||
| 280 | { | ||
| 281 | if (chip->flags & TPM_CHIP_FLAG_TPM2) | ||
| 282 | return 0; | ||
| 283 | |||
| 284 | tpm_sysfs_add_device(chip); | ||
| 285 | |||
| 286 | chip->bios_dir = tpm_bios_log_setup(dev_name(&chip->dev)); | ||
| 287 | |||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | |||
| 291 | static void tpm1_chip_unregister(struct tpm_chip *chip) | ||
| 292 | { | ||
| 293 | if (chip->flags & TPM_CHIP_FLAG_TPM2) | ||
| 294 | return; | ||
| 295 | |||
| 296 | if (chip->bios_dir) | ||
| 297 | tpm_bios_log_teardown(chip->bios_dir); | ||
| 298 | } | ||
| 299 | |||
| 300 | static void tpm_del_legacy_sysfs(struct tpm_chip *chip) | 280 | static void tpm_del_legacy_sysfs(struct tpm_chip *chip) |
| 301 | { | 281 | { |
| 302 | struct attribute **i; | 282 | struct attribute **i; |
| @@ -363,20 +343,20 @@ int tpm_chip_register(struct tpm_chip *chip) | |||
| 363 | return rc; | 343 | return rc; |
| 364 | } | 344 | } |
| 365 | 345 | ||
| 366 | rc = tpm1_chip_register(chip); | 346 | tpm_sysfs_add_device(chip); |
| 367 | if (rc) | 347 | |
| 348 | rc = tpm_bios_log_setup(chip); | ||
| 349 | if (rc != 0 && rc != -ENODEV) | ||
| 368 | return rc; | 350 | return rc; |
| 369 | 351 | ||
| 370 | tpm_add_ppi(chip); | 352 | tpm_add_ppi(chip); |
| 371 | 353 | ||
| 372 | rc = tpm_add_char_device(chip); | 354 | rc = tpm_add_char_device(chip); |
| 373 | if (rc) { | 355 | if (rc) { |
| 374 | tpm1_chip_unregister(chip); | 356 | tpm_bios_log_teardown(chip); |
| 375 | return rc; | 357 | return rc; |
| 376 | } | 358 | } |
| 377 | 359 | ||
| 378 | chip->flags |= TPM_CHIP_FLAG_REGISTERED; | ||
| 379 | |||
| 380 | rc = tpm_add_legacy_sysfs(chip); | 360 | rc = tpm_add_legacy_sysfs(chip); |
| 381 | if (rc) { | 361 | if (rc) { |
| 382 | tpm_chip_unregister(chip); | 362 | tpm_chip_unregister(chip); |
| @@ -402,12 +382,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); | |||
| 402 | */ | 382 | */ |
| 403 | void tpm_chip_unregister(struct tpm_chip *chip) | 383 | void tpm_chip_unregister(struct tpm_chip *chip) |
| 404 | { | 384 | { |
| 405 | if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED)) | ||
| 406 | return; | ||
| 407 | |||
| 408 | tpm_del_legacy_sysfs(chip); | 385 | tpm_del_legacy_sysfs(chip); |
| 409 | 386 | tpm_bios_log_teardown(chip); | |
| 410 | tpm1_chip_unregister(chip); | ||
| 411 | tpm_del_char_device(chip); | 387 | tpm_del_char_device(chip); |
| 412 | } | 388 | } |
| 413 | EXPORT_SYMBOL_GPL(tpm_chip_unregister); | 389 | EXPORT_SYMBOL_GPL(tpm_chip_unregister); |
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 3a9149cf0110..a2688ac2b48f 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/mutex.h> | 29 | #include <linux/mutex.h> |
| 30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
| 31 | #include <linux/freezer.h> | 31 | #include <linux/freezer.h> |
| 32 | #include <linux/pm_runtime.h> | ||
| 32 | 33 | ||
| 33 | #include "tpm.h" | 34 | #include "tpm.h" |
| 34 | #include "tpm_eventlog.h" | 35 | #include "tpm_eventlog.h" |
| @@ -356,6 +357,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, | |||
| 356 | if (!(flags & TPM_TRANSMIT_UNLOCKED)) | 357 | if (!(flags & TPM_TRANSMIT_UNLOCKED)) |
| 357 | mutex_lock(&chip->tpm_mutex); | 358 | mutex_lock(&chip->tpm_mutex); |
| 358 | 359 | ||
| 360 | if (chip->dev.parent) | ||
| 361 | pm_runtime_get_sync(chip->dev.parent); | ||
| 362 | |||
| 359 | rc = chip->ops->send(chip, (u8 *) buf, count); | 363 | rc = chip->ops->send(chip, (u8 *) buf, count); |
| 360 | if (rc < 0) { | 364 | if (rc < 0) { |
| 361 | dev_err(&chip->dev, | 365 | dev_err(&chip->dev, |
| @@ -397,6 +401,9 @@ out_recv: | |||
| 397 | dev_err(&chip->dev, | 401 | dev_err(&chip->dev, |
| 398 | "tpm_transmit: tpm_recv: error %zd\n", rc); | 402 | "tpm_transmit: tpm_recv: error %zd\n", rc); |
| 399 | out: | 403 | out: |
| 404 | if (chip->dev.parent) | ||
| 405 | pm_runtime_put_sync(chip->dev.parent); | ||
| 406 | |||
| 400 | if (!(flags & TPM_TRANSMIT_UNLOCKED)) | 407 | if (!(flags & TPM_TRANSMIT_UNLOCKED)) |
| 401 | mutex_unlock(&chip->tpm_mutex); | 408 | mutex_unlock(&chip->tpm_mutex); |
| 402 | return rc; | 409 | return rc; |
| @@ -437,26 +444,29 @@ static const struct tpm_input_header tpm_getcap_header = { | |||
| 437 | .ordinal = TPM_ORD_GET_CAP | 444 | .ordinal = TPM_ORD_GET_CAP |
| 438 | }; | 445 | }; |
| 439 | 446 | ||
| 440 | ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, | 447 | ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, |
| 441 | const char *desc) | 448 | const char *desc) |
| 442 | { | 449 | { |
| 443 | struct tpm_cmd_t tpm_cmd; | 450 | struct tpm_cmd_t tpm_cmd; |
| 444 | int rc; | 451 | int rc; |
| 445 | 452 | ||
| 446 | tpm_cmd.header.in = tpm_getcap_header; | 453 | tpm_cmd.header.in = tpm_getcap_header; |
| 447 | if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) { | 454 | if (subcap_id == TPM_CAP_VERSION_1_1 || |
| 448 | tpm_cmd.params.getcap_in.cap = subcap_id; | 455 | subcap_id == TPM_CAP_VERSION_1_2) { |
| 456 | tpm_cmd.params.getcap_in.cap = cpu_to_be32(subcap_id); | ||
| 449 | /*subcap field not necessary */ | 457 | /*subcap field not necessary */ |
| 450 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0); | 458 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0); |
| 451 | tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32)); | 459 | tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32)); |
| 452 | } else { | 460 | } else { |
| 453 | if (subcap_id == TPM_CAP_FLAG_PERM || | 461 | if (subcap_id == TPM_CAP_FLAG_PERM || |
| 454 | subcap_id == TPM_CAP_FLAG_VOL) | 462 | subcap_id == TPM_CAP_FLAG_VOL) |
| 455 | tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG; | 463 | tpm_cmd.params.getcap_in.cap = |
| 464 | cpu_to_be32(TPM_CAP_FLAG); | ||
| 456 | else | 465 | else |
| 457 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | 466 | tpm_cmd.params.getcap_in.cap = |
| 467 | cpu_to_be32(TPM_CAP_PROP); | ||
| 458 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); | 468 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
| 459 | tpm_cmd.params.getcap_in.subcap = subcap_id; | 469 | tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id); |
| 460 | } | 470 | } |
| 461 | rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, | 471 | rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, |
| 462 | desc); | 472 | desc); |
| @@ -488,12 +498,14 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) | |||
| 488 | 498 | ||
| 489 | int tpm_get_timeouts(struct tpm_chip *chip) | 499 | int tpm_get_timeouts(struct tpm_chip *chip) |
| 490 | { | 500 | { |
| 491 | struct tpm_cmd_t tpm_cmd; | 501 | cap_t cap; |
| 492 | unsigned long new_timeout[4]; | 502 | unsigned long new_timeout[4]; |
| 493 | unsigned long old_timeout[4]; | 503 | unsigned long old_timeout[4]; |
| 494 | struct duration_t *duration_cap; | ||
| 495 | ssize_t rc; | 504 | ssize_t rc; |
| 496 | 505 | ||
| 506 | if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) | ||
| 507 | return 0; | ||
| 508 | |||
| 497 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { | 509 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
| 498 | /* Fixed timeouts for TPM2 */ | 510 | /* Fixed timeouts for TPM2 */ |
| 499 | chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); | 511 | chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); |
| @@ -506,46 +518,30 @@ int tpm_get_timeouts(struct tpm_chip *chip) | |||
| 506 | msecs_to_jiffies(TPM2_DURATION_MEDIUM); | 518 | msecs_to_jiffies(TPM2_DURATION_MEDIUM); |
| 507 | chip->duration[TPM_LONG] = | 519 | chip->duration[TPM_LONG] = |
| 508 | msecs_to_jiffies(TPM2_DURATION_LONG); | 520 | msecs_to_jiffies(TPM2_DURATION_LONG); |
| 521 | |||
| 522 | chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS; | ||
| 509 | return 0; | 523 | return 0; |
| 510 | } | 524 | } |
| 511 | 525 | ||
| 512 | tpm_cmd.header.in = tpm_getcap_header; | 526 | rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, |
| 513 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | 527 | "attempting to determine the timeouts"); |
| 514 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); | ||
| 515 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; | ||
| 516 | rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, | ||
| 517 | NULL); | ||
| 518 | |||
| 519 | if (rc == TPM_ERR_INVALID_POSTINIT) { | 528 | if (rc == TPM_ERR_INVALID_POSTINIT) { |
| 520 | /* The TPM is not started, we are the first to talk to it. | 529 | /* The TPM is not started, we are the first to talk to it. |
| 521 | Execute a startup command. */ | 530 | Execute a startup command. */ |
| 522 | dev_info(&chip->dev, "Issuing TPM_STARTUP"); | 531 | dev_info(&chip->dev, "Issuing TPM_STARTUP\n"); |
| 523 | if (tpm_startup(chip, TPM_ST_CLEAR)) | 532 | if (tpm_startup(chip, TPM_ST_CLEAR)) |
| 524 | return rc; | 533 | return rc; |
| 525 | 534 | ||
| 526 | tpm_cmd.header.in = tpm_getcap_header; | 535 | rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, |
| 527 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | 536 | "attempting to determine the timeouts"); |
| 528 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); | ||
| 529 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; | ||
| 530 | rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, | ||
| 531 | 0, NULL); | ||
| 532 | } | 537 | } |
| 533 | if (rc) { | 538 | if (rc) |
| 534 | dev_err(&chip->dev, | 539 | return rc; |
| 535 | "A TPM error (%zd) occurred attempting to determine the timeouts\n", | ||
| 536 | rc); | ||
| 537 | goto duration; | ||
| 538 | } | ||
| 539 | |||
| 540 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || | ||
| 541 | be32_to_cpu(tpm_cmd.header.out.length) | ||
| 542 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) | ||
| 543 | return -EINVAL; | ||
| 544 | 540 | ||
| 545 | old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); | 541 | old_timeout[0] = be32_to_cpu(cap.timeout.a); |
| 546 | old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); | 542 | old_timeout[1] = be32_to_cpu(cap.timeout.b); |
| 547 | old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); | 543 | old_timeout[2] = be32_to_cpu(cap.timeout.c); |
| 548 | old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); | 544 | old_timeout[3] = be32_to_cpu(cap.timeout.d); |
| 549 | memcpy(new_timeout, old_timeout, sizeof(new_timeout)); | 545 | memcpy(new_timeout, old_timeout, sizeof(new_timeout)); |
| 550 | 546 | ||
| 551 | /* | 547 | /* |
| @@ -583,29 +579,17 @@ int tpm_get_timeouts(struct tpm_chip *chip) | |||
| 583 | chip->timeout_c = usecs_to_jiffies(new_timeout[2]); | 579 | chip->timeout_c = usecs_to_jiffies(new_timeout[2]); |
| 584 | chip->timeout_d = usecs_to_jiffies(new_timeout[3]); | 580 | chip->timeout_d = usecs_to_jiffies(new_timeout[3]); |
| 585 | 581 | ||
| 586 | duration: | 582 | rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap, |
| 587 | tpm_cmd.header.in = tpm_getcap_header; | 583 | "attempting to determine the durations"); |
| 588 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | ||
| 589 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); | ||
| 590 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; | ||
| 591 | |||
| 592 | rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, | ||
| 593 | "attempting to determine the durations"); | ||
| 594 | if (rc) | 584 | if (rc) |
| 595 | return rc; | 585 | return rc; |
| 596 | 586 | ||
| 597 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || | ||
| 598 | be32_to_cpu(tpm_cmd.header.out.length) | ||
| 599 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) | ||
| 600 | return -EINVAL; | ||
| 601 | |||
| 602 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; | ||
| 603 | chip->duration[TPM_SHORT] = | 587 | chip->duration[TPM_SHORT] = |
| 604 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); | 588 | usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short)); |
| 605 | chip->duration[TPM_MEDIUM] = | 589 | chip->duration[TPM_MEDIUM] = |
| 606 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); | 590 | usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium)); |
| 607 | chip->duration[TPM_LONG] = | 591 | chip->duration[TPM_LONG] = |
| 608 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); | 592 | usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long)); |
| 609 | 593 | ||
| 610 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above | 594 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above |
| 611 | * value wrong and apparently reports msecs rather than usecs. So we | 595 | * value wrong and apparently reports msecs rather than usecs. So we |
| @@ -619,6 +603,8 @@ duration: | |||
| 619 | chip->duration_adjusted = true; | 603 | chip->duration_adjusted = true; |
| 620 | dev_info(&chip->dev, "Adjusting TPM timeout parameters."); | 604 | dev_info(&chip->dev, "Adjusting TPM timeout parameters."); |
| 621 | } | 605 | } |
| 606 | |||
| 607 | chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS; | ||
| 622 | return 0; | 608 | return 0; |
| 623 | } | 609 | } |
| 624 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | 610 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); |
| @@ -726,6 +712,14 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) | |||
| 726 | } | 712 | } |
| 727 | EXPORT_SYMBOL_GPL(tpm_pcr_read); | 713 | EXPORT_SYMBOL_GPL(tpm_pcr_read); |
| 728 | 714 | ||
| 715 | #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) | ||
| 716 | #define EXTEND_PCR_RESULT_SIZE 34 | ||
| 717 | static const struct tpm_input_header pcrextend_header = { | ||
| 718 | .tag = TPM_TAG_RQU_COMMAND, | ||
| 719 | .length = cpu_to_be32(34), | ||
| 720 | .ordinal = TPM_ORD_PCR_EXTEND | ||
| 721 | }; | ||
| 722 | |||
| 729 | /** | 723 | /** |
| 730 | * tpm_pcr_extend - extend pcr value with hash | 724 | * tpm_pcr_extend - extend pcr value with hash |
| 731 | * @chip_num: tpm idx # or AN& | 725 | * @chip_num: tpm idx # or AN& |
| @@ -736,14 +730,6 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); | |||
| 736 | * isn't, protect against the chip disappearing, by incrementing | 730 | * isn't, protect against the chip disappearing, by incrementing |
| 737 | * the module usage count. | 731 | * the module usage count. |
| 738 | */ | 732 | */ |
| 739 | #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) | ||
| 740 | #define EXTEND_PCR_RESULT_SIZE 34 | ||
| 741 | static const struct tpm_input_header pcrextend_header = { | ||
| 742 | .tag = TPM_TAG_RQU_COMMAND, | ||
| 743 | .length = cpu_to_be32(34), | ||
| 744 | .ordinal = TPM_ORD_PCR_EXTEND | ||
| 745 | }; | ||
| 746 | |||
| 747 | int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) | 733 | int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) |
| 748 | { | 734 | { |
| 749 | struct tpm_cmd_t cmd; | 735 | struct tpm_cmd_t cmd; |
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index a76ab4af9fb2..848ad6580b46 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c | |||
| @@ -193,7 +193,7 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, | |||
| 193 | be32_to_cpu(cap.manufacturer_id)); | 193 | be32_to_cpu(cap.manufacturer_id)); |
| 194 | 194 | ||
| 195 | /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ | 195 | /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ |
| 196 | rc = tpm_getcap(chip, CAP_VERSION_1_2, &cap, | 196 | rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap, |
| 197 | "attempting to determine the 1.2 version"); | 197 | "attempting to determine the 1.2 version"); |
| 198 | if (!rc) { | 198 | if (!rc) { |
| 199 | str += sprintf(str, | 199 | str += sprintf(str, |
| @@ -204,7 +204,7 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, | |||
| 204 | cap.tpm_version_1_2.revMinor); | 204 | cap.tpm_version_1_2.revMinor); |
| 205 | } else { | 205 | } else { |
| 206 | /* Otherwise just use TPM_STRUCT_VER */ | 206 | /* Otherwise just use TPM_STRUCT_VER */ |
| 207 | rc = tpm_getcap(chip, CAP_VERSION_1_1, &cap, | 207 | rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap, |
| 208 | "attempting to determine the 1.1 version"); | 208 | "attempting to determine the 1.1 version"); |
| 209 | if (rc) | 209 | if (rc) |
| 210 | return 0; | 210 | return 0; |
| @@ -284,6 +284,9 @@ static const struct attribute_group tpm_dev_group = { | |||
| 284 | 284 | ||
| 285 | void tpm_sysfs_add_device(struct tpm_chip *chip) | 285 | void tpm_sysfs_add_device(struct tpm_chip *chip) |
| 286 | { | 286 | { |
| 287 | if (chip->flags & TPM_CHIP_FLAG_TPM2) | ||
| 288 | return; | ||
| 289 | |||
| 287 | /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del | 290 | /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del |
| 288 | * is called before ops is null'd and the sysfs core synchronizes this | 291 | * is called before ops is null'd and the sysfs core synchronizes this |
| 289 | * removal so that no callbacks are running or can run again | 292 | * removal so that no callbacks are running or can run again |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 4d183c97f6a6..1ae976894257 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
| @@ -35,11 +35,14 @@ | |||
| 35 | #include <linux/cdev.h> | 35 | #include <linux/cdev.h> |
| 36 | #include <linux/highmem.h> | 36 | #include <linux/highmem.h> |
| 37 | 37 | ||
| 38 | #include "tpm_eventlog.h" | ||
| 39 | |||
| 38 | enum tpm_const { | 40 | enum tpm_const { |
| 39 | TPM_MINOR = 224, /* officially assigned */ | 41 | TPM_MINOR = 224, /* officially assigned */ |
| 40 | TPM_BUFSIZE = 4096, | 42 | TPM_BUFSIZE = 4096, |
| 41 | TPM_NUM_DEVICES = 65536, | 43 | TPM_NUM_DEVICES = 65536, |
| 42 | TPM_RETRY = 50, /* 5 seconds */ | 44 | TPM_RETRY = 50, /* 5 seconds */ |
| 45 | TPM_NUM_EVENT_LOG_FILES = 3, | ||
| 43 | }; | 46 | }; |
| 44 | 47 | ||
| 45 | enum tpm_timeout { | 48 | enum tpm_timeout { |
| @@ -139,10 +142,15 @@ enum tpm2_startup_types { | |||
| 139 | #define TPM_PPI_VERSION_LEN 3 | 142 | #define TPM_PPI_VERSION_LEN 3 |
| 140 | 143 | ||
| 141 | enum tpm_chip_flags { | 144 | enum tpm_chip_flags { |
| 142 | TPM_CHIP_FLAG_REGISTERED = BIT(0), | ||
| 143 | TPM_CHIP_FLAG_TPM2 = BIT(1), | 145 | TPM_CHIP_FLAG_TPM2 = BIT(1), |
| 144 | TPM_CHIP_FLAG_IRQ = BIT(2), | 146 | TPM_CHIP_FLAG_IRQ = BIT(2), |
| 145 | TPM_CHIP_FLAG_VIRTUAL = BIT(3), | 147 | TPM_CHIP_FLAG_VIRTUAL = BIT(3), |
| 148 | TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), | ||
| 149 | }; | ||
| 150 | |||
| 151 | struct tpm_chip_seqops { | ||
| 152 | struct tpm_chip *chip; | ||
| 153 | const struct seq_operations *seqops; | ||
| 146 | }; | 154 | }; |
| 147 | 155 | ||
| 148 | struct tpm_chip { | 156 | struct tpm_chip { |
| @@ -156,6 +164,10 @@ struct tpm_chip { | |||
| 156 | struct rw_semaphore ops_sem; | 164 | struct rw_semaphore ops_sem; |
| 157 | const struct tpm_class_ops *ops; | 165 | const struct tpm_class_ops *ops; |
| 158 | 166 | ||
| 167 | struct tpm_bios_log log; | ||
| 168 | struct tpm_chip_seqops bin_log_seqops; | ||
| 169 | struct tpm_chip_seqops ascii_log_seqops; | ||
| 170 | |||
| 159 | unsigned int flags; | 171 | unsigned int flags; |
| 160 | 172 | ||
| 161 | int dev_num; /* /dev/tpm# */ | 173 | int dev_num; /* /dev/tpm# */ |
| @@ -171,7 +183,7 @@ struct tpm_chip { | |||
| 171 | unsigned long duration[3]; /* jiffies */ | 183 | unsigned long duration[3]; /* jiffies */ |
| 172 | bool duration_adjusted; | 184 | bool duration_adjusted; |
| 173 | 185 | ||
| 174 | struct dentry **bios_dir; | 186 | struct dentry *bios_dir[TPM_NUM_EVENT_LOG_FILES]; |
| 175 | 187 | ||
| 176 | const struct attribute_group *groups[3]; | 188 | const struct attribute_group *groups[3]; |
| 177 | unsigned int groups_cnt; | 189 | unsigned int groups_cnt; |
| @@ -282,21 +294,20 @@ typedef union { | |||
| 282 | } cap_t; | 294 | } cap_t; |
| 283 | 295 | ||
| 284 | enum tpm_capabilities { | 296 | enum tpm_capabilities { |
| 285 | TPM_CAP_FLAG = cpu_to_be32(4), | 297 | TPM_CAP_FLAG = 4, |
| 286 | TPM_CAP_PROP = cpu_to_be32(5), | 298 | TPM_CAP_PROP = 5, |
| 287 | CAP_VERSION_1_1 = cpu_to_be32(0x06), | 299 | TPM_CAP_VERSION_1_1 = 0x06, |
| 288 | CAP_VERSION_1_2 = cpu_to_be32(0x1A) | 300 | TPM_CAP_VERSION_1_2 = 0x1A, |
| 289 | }; | 301 | }; |
| 290 | 302 | ||
| 291 | enum tpm_sub_capabilities { | 303 | enum tpm_sub_capabilities { |
| 292 | TPM_CAP_PROP_PCR = cpu_to_be32(0x101), | 304 | TPM_CAP_PROP_PCR = 0x101, |
| 293 | TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), | 305 | TPM_CAP_PROP_MANUFACTURER = 0x103, |
| 294 | TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), | 306 | TPM_CAP_FLAG_PERM = 0x108, |
| 295 | TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), | 307 | TPM_CAP_FLAG_VOL = 0x109, |
| 296 | TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), | 308 | TPM_CAP_PROP_OWNER = 0x111, |
| 297 | TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), | 309 | TPM_CAP_PROP_TIS_TIMEOUT = 0x115, |
| 298 | TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), | 310 | TPM_CAP_PROP_TIS_DURATION = 0x120, |
| 299 | |||
| 300 | }; | 311 | }; |
| 301 | 312 | ||
| 302 | struct tpm_getcap_params_in { | 313 | struct tpm_getcap_params_in { |
| @@ -484,7 +495,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, | |||
| 484 | unsigned int flags); | 495 | unsigned int flags); |
| 485 | ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, | 496 | ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, |
| 486 | unsigned int flags, const char *desc); | 497 | unsigned int flags, const char *desc); |
| 487 | ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, | 498 | ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, |
| 488 | const char *desc); | 499 | const char *desc); |
| 489 | int tpm_get_timeouts(struct tpm_chip *); | 500 | int tpm_get_timeouts(struct tpm_chip *); |
| 490 | int tpm1_auto_startup(struct tpm_chip *chip); | 501 | int tpm1_auto_startup(struct tpm_chip *chip); |
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 7df55d58c939..da5b782a9731 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c | |||
| @@ -680,7 +680,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, | |||
| 680 | } | 680 | } |
| 681 | 681 | ||
| 682 | /** | 682 | /** |
| 683 | * tpm_unseal_trusted() - unseal the payload of a trusted key | 683 | * tpm2_unseal_trusted() - unseal the payload of a trusted key |
| 684 | * @chip_num: TPM chip to use | 684 | * @chip_num: TPM chip to use |
| 685 | * @payload: the key data in clear and encrypted form | 685 | * @payload: the key data in clear and encrypted form |
| 686 | * @options: authentication values and other options | 686 | * @options: authentication values and other options |
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 565a9478cb94..b7718c95fd0b 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c | |||
| @@ -6,10 +6,11 @@ | |||
| 6 | * Stefan Berger <stefanb@us.ibm.com> | 6 | * Stefan Berger <stefanb@us.ibm.com> |
| 7 | * Reiner Sailer <sailer@watson.ibm.com> | 7 | * Reiner Sailer <sailer@watson.ibm.com> |
| 8 | * Kylene Hall <kjhall@us.ibm.com> | 8 | * Kylene Hall <kjhall@us.ibm.com> |
| 9 | * Nayna Jain <nayna@linux.vnet.ibm.com> | ||
| 9 | * | 10 | * |
| 10 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | 11 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> |
| 11 | * | 12 | * |
| 12 | * Access to the eventlog extended by the TCG BIOS of PC platform | 13 | * Access to the event log extended by the TCG BIOS of PC platform |
| 13 | * | 14 | * |
| 14 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
| 15 | * modify it under the terms of the GNU General Public License | 16 | * modify it under the terms of the GNU General Public License |
| @@ -45,29 +46,28 @@ struct acpi_tcpa { | |||
| 45 | }; | 46 | }; |
| 46 | 47 | ||
| 47 | /* read binary bios log */ | 48 | /* read binary bios log */ |
| 48 | int read_log(struct tpm_bios_log *log) | 49 | int tpm_read_log_acpi(struct tpm_chip *chip) |
| 49 | { | 50 | { |
| 50 | struct acpi_tcpa *buff; | 51 | struct acpi_tcpa *buff; |
| 51 | acpi_status status; | 52 | acpi_status status; |
| 52 | void __iomem *virt; | 53 | void __iomem *virt; |
| 53 | u64 len, start; | 54 | u64 len, start; |
| 55 | struct tpm_bios_log *log; | ||
| 54 | 56 | ||
| 55 | if (log->bios_event_log != NULL) { | 57 | log = &chip->log; |
| 56 | printk(KERN_ERR | 58 | |
| 57 | "%s: ERROR - Eventlog already initialized\n", | 59 | /* Unfortuntely ACPI does not associate the event log with a specific |
| 58 | __func__); | 60 | * TPM, like PPI. Thus all ACPI TPMs will read the same log. |
| 59 | return -EFAULT; | 61 | */ |
| 60 | } | 62 | if (!chip->acpi_dev_handle) |
| 63 | return -ENODEV; | ||
| 61 | 64 | ||
| 62 | /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ | 65 | /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ |
| 63 | status = acpi_get_table(ACPI_SIG_TCPA, 1, | 66 | status = acpi_get_table(ACPI_SIG_TCPA, 1, |
| 64 | (struct acpi_table_header **)&buff); | 67 | (struct acpi_table_header **)&buff); |
| 65 | 68 | ||
| 66 | if (ACPI_FAILURE(status)) { | 69 | if (ACPI_FAILURE(status)) |
| 67 | printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", | 70 | return -ENODEV; |
| 68 | __func__); | ||
| 69 | return -EIO; | ||
| 70 | } | ||
| 71 | 71 | ||
| 72 | switch(buff->platform_class) { | 72 | switch(buff->platform_class) { |
| 73 | case BIOS_SERVER: | 73 | case BIOS_SERVER: |
| @@ -81,29 +81,29 @@ int read_log(struct tpm_bios_log *log) | |||
| 81 | break; | 81 | break; |
| 82 | } | 82 | } |
| 83 | if (!len) { | 83 | if (!len) { |
| 84 | printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); | 84 | dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__); |
| 85 | return -EIO; | 85 | return -EIO; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /* malloc EventLog space */ | 88 | /* malloc EventLog space */ |
| 89 | log->bios_event_log = kmalloc(len, GFP_KERNEL); | 89 | log->bios_event_log = kmalloc(len, GFP_KERNEL); |
| 90 | if (!log->bios_event_log) { | 90 | if (!log->bios_event_log) |
| 91 | printk("%s: ERROR - Not enough Memory for BIOS measurements\n", | ||
| 92 | __func__); | ||
| 93 | return -ENOMEM; | 91 | return -ENOMEM; |
| 94 | } | ||
| 95 | 92 | ||
| 96 | log->bios_event_log_end = log->bios_event_log + len; | 93 | log->bios_event_log_end = log->bios_event_log + len; |
| 97 | 94 | ||
| 98 | virt = acpi_os_map_iomem(start, len); | 95 | virt = acpi_os_map_iomem(start, len); |
| 99 | if (!virt) { | 96 | if (!virt) |
| 100 | kfree(log->bios_event_log); | 97 | goto err; |
| 101 | printk("%s: ERROR - Unable to map memory\n", __func__); | ||
| 102 | return -EIO; | ||
| 103 | } | ||
| 104 | 98 | ||
| 105 | memcpy_fromio(log->bios_event_log, virt, len); | 99 | memcpy_fromio(log->bios_event_log, virt, len); |
| 106 | 100 | ||
| 107 | acpi_os_unmap_iomem(virt, len); | 101 | acpi_os_unmap_iomem(virt, len); |
| 108 | return 0; | 102 | return 0; |
| 103 | |||
| 104 | err: | ||
| 105 | kfree(log->bios_event_log); | ||
| 106 | log->bios_event_log = NULL; | ||
| 107 | return -EIO; | ||
| 108 | |||
| 109 | } | 109 | } |
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index a7c870af916c..717b6b47c042 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/highmem.h> | 19 | #include <linux/highmem.h> |
| 20 | #include <linux/rculist.h> | 20 | #include <linux/rculist.h> |
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/pm_runtime.h> | ||
| 22 | #include "tpm.h" | 23 | #include "tpm.h" |
| 23 | 24 | ||
| 24 | #define ACPI_SIG_TPM2 "TPM2" | 25 | #define ACPI_SIG_TPM2 "TPM2" |
| @@ -83,7 +84,71 @@ struct crb_priv { | |||
| 83 | u32 cmd_size; | 84 | u32 cmd_size; |
| 84 | }; | 85 | }; |
| 85 | 86 | ||
| 86 | static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); | 87 | /** |
| 88 | * crb_go_idle - request tpm crb device to go the idle state | ||
| 89 | * | ||
| 90 | * @dev: crb device | ||
| 91 | * @priv: crb private data | ||
| 92 | * | ||
| 93 | * Write CRB_CTRL_REQ_GO_IDLE to TPM_CRB_CTRL_REQ | ||
| 94 | * The device should respond within TIMEOUT_C by clearing the bit. | ||
| 95 | * Anyhow, we do not wait here as a consequent CMD_READY request | ||
| 96 | * will be handled correctly even if idle was not completed. | ||
| 97 | * | ||
| 98 | * The function does nothing for devices with ACPI-start method. | ||
| 99 | * | ||
| 100 | * Return: 0 always | ||
| 101 | */ | ||
| 102 | static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) | ||
| 103 | { | ||
| 104 | if (priv->flags & CRB_FL_ACPI_START) | ||
| 105 | return 0; | ||
| 106 | |||
| 107 | iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->cca->req); | ||
| 108 | /* we don't really care when this settles */ | ||
| 109 | |||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * crb_cmd_ready - request tpm crb device to enter ready state | ||
| 115 | * | ||
| 116 | * @dev: crb device | ||
| 117 | * @priv: crb private data | ||
| 118 | * | ||
| 119 | * Write CRB_CTRL_REQ_CMD_READY to TPM_CRB_CTRL_REQ | ||
| 120 | * and poll till the device acknowledge it by clearing the bit. | ||
| 121 | * The device should respond within TIMEOUT_C. | ||
| 122 | * | ||
| 123 | * The function does nothing for devices with ACPI-start method | ||
| 124 | * | ||
| 125 | * Return: 0 on success -ETIME on timeout; | ||
| 126 | */ | ||
| 127 | static int __maybe_unused crb_cmd_ready(struct device *dev, | ||
| 128 | struct crb_priv *priv) | ||
| 129 | { | ||
| 130 | ktime_t stop, start; | ||
| 131 | |||
| 132 | if (priv->flags & CRB_FL_ACPI_START) | ||
| 133 | return 0; | ||
| 134 | |||
| 135 | iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->cca->req); | ||
| 136 | |||
| 137 | start = ktime_get(); | ||
| 138 | stop = ktime_add(start, ms_to_ktime(TPM2_TIMEOUT_C)); | ||
| 139 | do { | ||
| 140 | if (!(ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY)) | ||
| 141 | return 0; | ||
| 142 | usleep_range(50, 100); | ||
| 143 | } while (ktime_before(ktime_get(), stop)); | ||
| 144 | |||
| 145 | if (ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY) { | ||
| 146 | dev_warn(dev, "cmdReady timed out\n"); | ||
| 147 | return -ETIME; | ||
| 148 | } | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 87 | 152 | ||
| 88 | static u8 crb_status(struct tpm_chip *chip) | 153 | static u8 crb_status(struct tpm_chip *chip) |
| 89 | { | 154 | { |
| @@ -196,21 +261,6 @@ static const struct tpm_class_ops tpm_crb = { | |||
| 196 | .req_complete_val = CRB_DRV_STS_COMPLETE, | 261 | .req_complete_val = CRB_DRV_STS_COMPLETE, |
| 197 | }; | 262 | }; |
| 198 | 263 | ||
| 199 | static int crb_init(struct acpi_device *device, struct crb_priv *priv) | ||
| 200 | { | ||
| 201 | struct tpm_chip *chip; | ||
| 202 | |||
| 203 | chip = tpmm_chip_alloc(&device->dev, &tpm_crb); | ||
| 204 | if (IS_ERR(chip)) | ||
| 205 | return PTR_ERR(chip); | ||
| 206 | |||
| 207 | dev_set_drvdata(&chip->dev, priv); | ||
| 208 | chip->acpi_dev_handle = device->handle; | ||
| 209 | chip->flags = TPM_CHIP_FLAG_TPM2; | ||
| 210 | |||
| 211 | return tpm_chip_register(chip); | ||
| 212 | } | ||
| 213 | |||
| 214 | static int crb_check_resource(struct acpi_resource *ares, void *data) | 264 | static int crb_check_resource(struct acpi_resource *ares, void *data) |
| 215 | { | 265 | { |
| 216 | struct resource *io_res = data; | 266 | struct resource *io_res = data; |
| @@ -249,6 +299,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, | |||
| 249 | struct list_head resources; | 299 | struct list_head resources; |
| 250 | struct resource io_res; | 300 | struct resource io_res; |
| 251 | struct device *dev = &device->dev; | 301 | struct device *dev = &device->dev; |
| 302 | u32 pa_high, pa_low; | ||
| 252 | u64 cmd_pa; | 303 | u64 cmd_pa; |
| 253 | u32 cmd_size; | 304 | u32 cmd_size; |
| 254 | u64 rsp_pa; | 305 | u64 rsp_pa; |
| @@ -276,12 +327,27 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, | |||
| 276 | if (IS_ERR(priv->cca)) | 327 | if (IS_ERR(priv->cca)) |
| 277 | return PTR_ERR(priv->cca); | 328 | return PTR_ERR(priv->cca); |
| 278 | 329 | ||
| 279 | cmd_pa = ((u64) ioread32(&priv->cca->cmd_pa_high) << 32) | | 330 | /* |
| 280 | (u64) ioread32(&priv->cca->cmd_pa_low); | 331 | * PTT HW bug w/a: wake up the device to access |
| 332 | * possibly not retained registers. | ||
| 333 | */ | ||
| 334 | ret = crb_cmd_ready(dev, priv); | ||
| 335 | if (ret) | ||
| 336 | return ret; | ||
| 337 | |||
| 338 | pa_high = ioread32(&priv->cca->cmd_pa_high); | ||
| 339 | pa_low = ioread32(&priv->cca->cmd_pa_low); | ||
| 340 | cmd_pa = ((u64)pa_high << 32) | pa_low; | ||
| 281 | cmd_size = ioread32(&priv->cca->cmd_size); | 341 | cmd_size = ioread32(&priv->cca->cmd_size); |
| 342 | |||
| 343 | dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n", | ||
| 344 | pa_high, pa_low, cmd_size); | ||
| 345 | |||
| 282 | priv->cmd = crb_map_res(dev, priv, &io_res, cmd_pa, cmd_size); | 346 | priv->cmd = crb_map_res(dev, priv, &io_res, cmd_pa, cmd_size); |
| 283 | if (IS_ERR(priv->cmd)) | 347 | if (IS_ERR(priv->cmd)) { |
| 284 | return PTR_ERR(priv->cmd); | 348 | ret = PTR_ERR(priv->cmd); |
| 349 | goto out; | ||
| 350 | } | ||
| 285 | 351 | ||
| 286 | memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8); | 352 | memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8); |
| 287 | rsp_pa = le64_to_cpu(rsp_pa); | 353 | rsp_pa = le64_to_cpu(rsp_pa); |
| @@ -289,7 +355,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, | |||
| 289 | 355 | ||
| 290 | if (cmd_pa != rsp_pa) { | 356 | if (cmd_pa != rsp_pa) { |
| 291 | priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size); | 357 | priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size); |
| 292 | return PTR_ERR_OR_ZERO(priv->rsp); | 358 | ret = PTR_ERR_OR_ZERO(priv->rsp); |
| 359 | goto out; | ||
| 293 | } | 360 | } |
| 294 | 361 | ||
| 295 | /* According to the PTP specification, overlapping command and response | 362 | /* According to the PTP specification, overlapping command and response |
| @@ -297,18 +364,25 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, | |||
| 297 | */ | 364 | */ |
| 298 | if (cmd_size != rsp_size) { | 365 | if (cmd_size != rsp_size) { |
| 299 | dev_err(dev, FW_BUG "overlapping command and response buffer sizes are not identical"); | 366 | dev_err(dev, FW_BUG "overlapping command and response buffer sizes are not identical"); |
| 300 | return -EINVAL; | 367 | ret = -EINVAL; |
| 368 | goto out; | ||
| 301 | } | 369 | } |
| 370 | |||
| 302 | priv->cmd_size = cmd_size; | 371 | priv->cmd_size = cmd_size; |
| 303 | 372 | ||
| 304 | priv->rsp = priv->cmd; | 373 | priv->rsp = priv->cmd; |
| 305 | return 0; | 374 | |
| 375 | out: | ||
| 376 | crb_go_idle(dev, priv); | ||
| 377 | |||
| 378 | return ret; | ||
| 306 | } | 379 | } |
| 307 | 380 | ||
| 308 | static int crb_acpi_add(struct acpi_device *device) | 381 | static int crb_acpi_add(struct acpi_device *device) |
| 309 | { | 382 | { |
| 310 | struct acpi_table_tpm2 *buf; | 383 | struct acpi_table_tpm2 *buf; |
| 311 | struct crb_priv *priv; | 384 | struct crb_priv *priv; |
| 385 | struct tpm_chip *chip; | ||
| 312 | struct device *dev = &device->dev; | 386 | struct device *dev = &device->dev; |
| 313 | acpi_status status; | 387 | acpi_status status; |
| 314 | u32 sm; | 388 | u32 sm; |
| @@ -346,7 +420,33 @@ static int crb_acpi_add(struct acpi_device *device) | |||
| 346 | if (rc) | 420 | if (rc) |
| 347 | return rc; | 421 | return rc; |
| 348 | 422 | ||
| 349 | return crb_init(device, priv); | 423 | chip = tpmm_chip_alloc(dev, &tpm_crb); |
| 424 | if (IS_ERR(chip)) | ||
| 425 | return PTR_ERR(chip); | ||
| 426 | |||
| 427 | dev_set_drvdata(&chip->dev, priv); | ||
| 428 | chip->acpi_dev_handle = device->handle; | ||
| 429 | chip->flags = TPM_CHIP_FLAG_TPM2; | ||
| 430 | |||
| 431 | rc = crb_cmd_ready(dev, priv); | ||
| 432 | if (rc) | ||
| 433 | return rc; | ||
| 434 | |||
| 435 | pm_runtime_get_noresume(dev); | ||
| 436 | pm_runtime_set_active(dev); | ||
| 437 | pm_runtime_enable(dev); | ||
| 438 | |||
| 439 | rc = tpm_chip_register(chip); | ||
| 440 | if (rc) { | ||
| 441 | crb_go_idle(dev, priv); | ||
| 442 | pm_runtime_put_noidle(dev); | ||
| 443 | pm_runtime_disable(dev); | ||
| 444 | return rc; | ||
| 445 | } | ||
| 446 | |||
| 447 | pm_runtime_put(dev); | ||
| 448 | |||
| 449 | return 0; | ||
| 350 | } | 450 | } |
| 351 | 451 | ||
| 352 | static int crb_acpi_remove(struct acpi_device *device) | 452 | static int crb_acpi_remove(struct acpi_device *device) |
| @@ -356,9 +456,34 @@ static int crb_acpi_remove(struct acpi_device *device) | |||
| 356 | 456 | ||
| 357 | tpm_chip_unregister(chip); | 457 | tpm_chip_unregister(chip); |
| 358 | 458 | ||
| 459 | pm_runtime_disable(dev); | ||
| 460 | |||
| 359 | return 0; | 461 | return 0; |
| 360 | } | 462 | } |
| 361 | 463 | ||
| 464 | #ifdef CONFIG_PM | ||
| 465 | static int crb_pm_runtime_suspend(struct device *dev) | ||
| 466 | { | ||
| 467 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 468 | struct crb_priv *priv = dev_get_drvdata(&chip->dev); | ||
| 469 | |||
| 470 | return crb_go_idle(dev, priv); | ||
| 471 | } | ||
| 472 | |||
| 473 | static int crb_pm_runtime_resume(struct device *dev) | ||
| 474 | { | ||
| 475 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 476 | struct crb_priv *priv = dev_get_drvdata(&chip->dev); | ||
| 477 | |||
| 478 | return crb_cmd_ready(dev, priv); | ||
| 479 | } | ||
| 480 | #endif /* CONFIG_PM */ | ||
| 481 | |||
| 482 | static const struct dev_pm_ops crb_pm = { | ||
| 483 | SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume) | ||
| 484 | SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL) | ||
| 485 | }; | ||
| 486 | |||
| 362 | static struct acpi_device_id crb_device_ids[] = { | 487 | static struct acpi_device_id crb_device_ids[] = { |
| 363 | {"MSFT0101", 0}, | 488 | {"MSFT0101", 0}, |
| 364 | {"", 0}, | 489 | {"", 0}, |
diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index e7228863290e..11bb1138a828 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c | |||
| @@ -7,10 +7,11 @@ | |||
| 7 | * Stefan Berger <stefanb@us.ibm.com> | 7 | * Stefan Berger <stefanb@us.ibm.com> |
| 8 | * Reiner Sailer <sailer@watson.ibm.com> | 8 | * Reiner Sailer <sailer@watson.ibm.com> |
| 9 | * Kylene Hall <kjhall@us.ibm.com> | 9 | * Kylene Hall <kjhall@us.ibm.com> |
| 10 | * Nayna Jain <nayna@linux.vnet.ibm.com> | ||
| 10 | * | 11 | * |
| 11 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | 12 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> |
| 12 | * | 13 | * |
| 13 | * Access to the eventlog created by a system's firmware / BIOS | 14 | * Access to the event log created by a system's firmware / BIOS |
| 14 | * | 15 | * |
| 15 | * This program is free software; you can redistribute it and/or | 16 | * This program is free software; you can redistribute it and/or |
| 16 | * modify it under the terms of the GNU General Public License | 17 | * modify it under the terms of the GNU General Public License |
| @@ -72,7 +73,8 @@ static const char* tcpa_pc_event_id_strings[] = { | |||
| 72 | static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) | 73 | static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) |
| 73 | { | 74 | { |
| 74 | loff_t i; | 75 | loff_t i; |
| 75 | struct tpm_bios_log *log = m->private; | 76 | struct tpm_chip *chip = m->private; |
| 77 | struct tpm_bios_log *log = &chip->log; | ||
| 76 | void *addr = log->bios_event_log; | 78 | void *addr = log->bios_event_log; |
| 77 | void *limit = log->bios_event_log_end; | 79 | void *limit = log->bios_event_log_end; |
| 78 | struct tcpa_event *event; | 80 | struct tcpa_event *event; |
| @@ -119,7 +121,8 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v, | |||
| 119 | loff_t *pos) | 121 | loff_t *pos) |
| 120 | { | 122 | { |
| 121 | struct tcpa_event *event = v; | 123 | struct tcpa_event *event = v; |
| 122 | struct tpm_bios_log *log = m->private; | 124 | struct tpm_chip *chip = m->private; |
| 125 | struct tpm_bios_log *log = &chip->log; | ||
| 123 | void *limit = log->bios_event_log_end; | 126 | void *limit = log->bios_event_log_end; |
| 124 | u32 converted_event_size; | 127 | u32 converted_event_size; |
| 125 | u32 converted_event_type; | 128 | u32 converted_event_type; |
| @@ -260,13 +263,10 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) | |||
| 260 | static int tpm_bios_measurements_release(struct inode *inode, | 263 | static int tpm_bios_measurements_release(struct inode *inode, |
| 261 | struct file *file) | 264 | struct file *file) |
| 262 | { | 265 | { |
| 263 | struct seq_file *seq = file->private_data; | 266 | struct seq_file *seq = (struct seq_file *)file->private_data; |
| 264 | struct tpm_bios_log *log = seq->private; | 267 | struct tpm_chip *chip = (struct tpm_chip *)seq->private; |
| 265 | 268 | ||
| 266 | if (log) { | 269 | put_device(&chip->dev); |
| 267 | kfree(log->bios_event_log); | ||
| 268 | kfree(log); | ||
| 269 | } | ||
| 270 | 270 | ||
| 271 | return seq_release(inode, file); | 271 | return seq_release(inode, file); |
| 272 | } | 272 | } |
| @@ -304,151 +304,159 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) | |||
| 304 | return 0; | 304 | return 0; |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | static const struct seq_operations tpm_ascii_b_measurments_seqops = { | 307 | static const struct seq_operations tpm_ascii_b_measurements_seqops = { |
| 308 | .start = tpm_bios_measurements_start, | 308 | .start = tpm_bios_measurements_start, |
| 309 | .next = tpm_bios_measurements_next, | 309 | .next = tpm_bios_measurements_next, |
| 310 | .stop = tpm_bios_measurements_stop, | 310 | .stop = tpm_bios_measurements_stop, |
| 311 | .show = tpm_ascii_bios_measurements_show, | 311 | .show = tpm_ascii_bios_measurements_show, |
| 312 | }; | 312 | }; |
| 313 | 313 | ||
| 314 | static const struct seq_operations tpm_binary_b_measurments_seqops = { | 314 | static const struct seq_operations tpm_binary_b_measurements_seqops = { |
| 315 | .start = tpm_bios_measurements_start, | 315 | .start = tpm_bios_measurements_start, |
| 316 | .next = tpm_bios_measurements_next, | 316 | .next = tpm_bios_measurements_next, |
| 317 | .stop = tpm_bios_measurements_stop, | 317 | .stop = tpm_bios_measurements_stop, |
| 318 | .show = tpm_binary_bios_measurements_show, | 318 | .show = tpm_binary_bios_measurements_show, |
| 319 | }; | 319 | }; |
| 320 | 320 | ||
| 321 | static int tpm_ascii_bios_measurements_open(struct inode *inode, | 321 | static int tpm_bios_measurements_open(struct inode *inode, |
| 322 | struct file *file) | 322 | struct file *file) |
| 323 | { | 323 | { |
| 324 | int err; | 324 | int err; |
| 325 | struct tpm_bios_log *log; | ||
| 326 | struct seq_file *seq; | 325 | struct seq_file *seq; |
| 327 | 326 | struct tpm_chip_seqops *chip_seqops; | |
| 328 | log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); | 327 | const struct seq_operations *seqops; |
| 329 | if (!log) | 328 | struct tpm_chip *chip; |
| 330 | return -ENOMEM; | 329 | |
| 331 | 330 | inode_lock(inode); | |
| 332 | if ((err = read_log(log))) | 331 | if (!inode->i_private) { |
| 333 | goto out_free; | 332 | inode_unlock(inode); |
| 333 | return -ENODEV; | ||
| 334 | } | ||
| 335 | chip_seqops = (struct tpm_chip_seqops *)inode->i_private; | ||
| 336 | seqops = chip_seqops->seqops; | ||
| 337 | chip = chip_seqops->chip; | ||
| 338 | get_device(&chip->dev); | ||
| 339 | inode_unlock(inode); | ||
| 334 | 340 | ||
| 335 | /* now register seq file */ | 341 | /* now register seq file */ |
| 336 | err = seq_open(file, &tpm_ascii_b_measurments_seqops); | 342 | err = seq_open(file, seqops); |
| 337 | if (!err) { | 343 | if (!err) { |
| 338 | seq = file->private_data; | 344 | seq = file->private_data; |
| 339 | seq->private = log; | 345 | seq->private = chip; |
| 340 | } else { | ||
| 341 | goto out_free; | ||
| 342 | } | 346 | } |
| 343 | 347 | ||
| 344 | out: | ||
| 345 | return err; | 348 | return err; |
| 346 | out_free: | ||
| 347 | kfree(log->bios_event_log); | ||
| 348 | kfree(log); | ||
| 349 | goto out; | ||
| 350 | } | 349 | } |
| 351 | 350 | ||
| 352 | static const struct file_operations tpm_ascii_bios_measurements_ops = { | 351 | static const struct file_operations tpm_bios_measurements_ops = { |
| 353 | .open = tpm_ascii_bios_measurements_open, | 352 | .owner = THIS_MODULE, |
| 353 | .open = tpm_bios_measurements_open, | ||
| 354 | .read = seq_read, | 354 | .read = seq_read, |
| 355 | .llseek = seq_lseek, | 355 | .llseek = seq_lseek, |
| 356 | .release = tpm_bios_measurements_release, | 356 | .release = tpm_bios_measurements_release, |
| 357 | }; | 357 | }; |
| 358 | 358 | ||
| 359 | static int tpm_binary_bios_measurements_open(struct inode *inode, | 359 | static int tpm_read_log(struct tpm_chip *chip) |
| 360 | struct file *file) | ||
| 361 | { | 360 | { |
| 362 | int err; | 361 | int rc; |
| 363 | struct tpm_bios_log *log; | ||
| 364 | struct seq_file *seq; | ||
| 365 | |||
| 366 | log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); | ||
| 367 | if (!log) | ||
| 368 | return -ENOMEM; | ||
| 369 | 362 | ||
| 370 | if ((err = read_log(log))) | 363 | if (chip->log.bios_event_log != NULL) { |
| 371 | goto out_free; | 364 | dev_dbg(&chip->dev, |
| 372 | 365 | "%s: ERROR - event log already initialized\n", | |
| 373 | /* now register seq file */ | 366 | __func__); |
| 374 | err = seq_open(file, &tpm_binary_b_measurments_seqops); | 367 | return -EFAULT; |
| 375 | if (!err) { | ||
| 376 | seq = file->private_data; | ||
| 377 | seq->private = log; | ||
| 378 | } else { | ||
| 379 | goto out_free; | ||
| 380 | } | 368 | } |
| 381 | 369 | ||
| 382 | out: | 370 | rc = tpm_read_log_acpi(chip); |
| 383 | return err; | 371 | if (rc != -ENODEV) |
| 384 | out_free: | 372 | return rc; |
| 385 | kfree(log->bios_event_log); | ||
| 386 | kfree(log); | ||
| 387 | goto out; | ||
| 388 | } | ||
| 389 | |||
| 390 | static const struct file_operations tpm_binary_bios_measurements_ops = { | ||
| 391 | .open = tpm_binary_bios_measurements_open, | ||
| 392 | .read = seq_read, | ||
| 393 | .llseek = seq_lseek, | ||
| 394 | .release = tpm_bios_measurements_release, | ||
| 395 | }; | ||
| 396 | 373 | ||
| 397 | static int is_bad(void *p) | 374 | return tpm_read_log_of(chip); |
| 398 | { | ||
| 399 | if (!p) | ||
| 400 | return 1; | ||
| 401 | if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV)) | ||
| 402 | return 1; | ||
| 403 | return 0; | ||
| 404 | } | 375 | } |
| 405 | 376 | ||
| 406 | struct dentry **tpm_bios_log_setup(const char *name) | 377 | /* |
| 378 | * tpm_bios_log_setup() - Read the event log from the firmware | ||
| 379 | * @chip: TPM chip to use. | ||
| 380 | * | ||
| 381 | * If an event log is found then the securityfs files are setup to | ||
| 382 | * export it to userspace, otherwise nothing is done. | ||
| 383 | * | ||
| 384 | * Returns -ENODEV if the firmware has no event log or securityfs is not | ||
| 385 | * supported. | ||
| 386 | */ | ||
| 387 | int tpm_bios_log_setup(struct tpm_chip *chip) | ||
| 407 | { | 388 | { |
| 408 | struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file; | 389 | const char *name = dev_name(&chip->dev); |
| 409 | 390 | unsigned int cnt; | |
| 410 | tpm_dir = securityfs_create_dir(name, NULL); | 391 | int rc = 0; |
| 411 | if (is_bad(tpm_dir)) | 392 | |
| 412 | goto out; | 393 | if (chip->flags & TPM_CHIP_FLAG_TPM2) |
| 413 | 394 | return 0; | |
| 414 | bin_file = | 395 | |
| 396 | rc = tpm_read_log(chip); | ||
| 397 | if (rc) | ||
| 398 | return rc; | ||
| 399 | |||
| 400 | cnt = 0; | ||
| 401 | chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); | ||
| 402 | /* NOTE: securityfs_create_dir can return ENODEV if securityfs is | ||
| 403 | * compiled out. The caller should ignore the ENODEV return code. | ||
| 404 | */ | ||
| 405 | if (IS_ERR(chip->bios_dir[cnt])) | ||
| 406 | goto err; | ||
| 407 | cnt++; | ||
| 408 | |||
| 409 | chip->bin_log_seqops.chip = chip; | ||
| 410 | chip->bin_log_seqops.seqops = &tpm_binary_b_measurements_seqops; | ||
| 411 | |||
| 412 | chip->bios_dir[cnt] = | ||
| 415 | securityfs_create_file("binary_bios_measurements", | 413 | securityfs_create_file("binary_bios_measurements", |
| 416 | S_IRUSR | S_IRGRP, tpm_dir, NULL, | 414 | 0440, chip->bios_dir[0], |
| 417 | &tpm_binary_bios_measurements_ops); | 415 | (void *)&chip->bin_log_seqops, |
| 418 | if (is_bad(bin_file)) | 416 | &tpm_bios_measurements_ops); |
| 419 | goto out_tpm; | 417 | if (IS_ERR(chip->bios_dir[cnt])) |
| 418 | goto err; | ||
| 419 | cnt++; | ||
| 420 | |||
| 421 | chip->ascii_log_seqops.chip = chip; | ||
| 422 | chip->ascii_log_seqops.seqops = &tpm_ascii_b_measurements_seqops; | ||
| 420 | 423 | ||
| 421 | ascii_file = | 424 | chip->bios_dir[cnt] = |
| 422 | securityfs_create_file("ascii_bios_measurements", | 425 | securityfs_create_file("ascii_bios_measurements", |
| 423 | S_IRUSR | S_IRGRP, tpm_dir, NULL, | 426 | 0440, chip->bios_dir[0], |
| 424 | &tpm_ascii_bios_measurements_ops); | 427 | (void *)&chip->ascii_log_seqops, |
| 425 | if (is_bad(ascii_file)) | 428 | &tpm_bios_measurements_ops); |
| 426 | goto out_bin; | 429 | if (IS_ERR(chip->bios_dir[cnt])) |
| 427 | 430 | goto err; | |
| 428 | ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL); | 431 | cnt++; |
| 429 | if (!ret) | 432 | |
| 430 | goto out_ascii; | 433 | return 0; |
| 431 | 434 | ||
| 432 | ret[0] = ascii_file; | 435 | err: |
| 433 | ret[1] = bin_file; | 436 | rc = PTR_ERR(chip->bios_dir[cnt]); |
| 434 | ret[2] = tpm_dir; | 437 | chip->bios_dir[cnt] = NULL; |
| 435 | 438 | tpm_bios_log_teardown(chip); | |
| 436 | return ret; | 439 | return rc; |
| 437 | |||
| 438 | out_ascii: | ||
| 439 | securityfs_remove(ascii_file); | ||
| 440 | out_bin: | ||
| 441 | securityfs_remove(bin_file); | ||
| 442 | out_tpm: | ||
| 443 | securityfs_remove(tpm_dir); | ||
| 444 | out: | ||
| 445 | return NULL; | ||
| 446 | } | 440 | } |
| 447 | 441 | ||
| 448 | void tpm_bios_log_teardown(struct dentry **lst) | 442 | void tpm_bios_log_teardown(struct tpm_chip *chip) |
| 449 | { | 443 | { |
| 450 | int i; | 444 | int i; |
| 451 | 445 | struct inode *inode; | |
| 452 | for (i = 0; i < 3; i++) | 446 | |
| 453 | securityfs_remove(lst[i]); | 447 | /* securityfs_remove currently doesn't take care of handling sync |
| 448 | * between removal and opening of pseudo files. To handle this, a | ||
| 449 | * workaround is added by making i_private = NULL here during removal | ||
| 450 | * and to check it during open(), both within inode_lock()/unlock(). | ||
| 451 | * This design ensures that open() either safely gets kref or fails. | ||
| 452 | */ | ||
| 453 | for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) { | ||
| 454 | if (chip->bios_dir[i]) { | ||
| 455 | inode = d_inode(chip->bios_dir[i]); | ||
| 456 | inode_lock(inode); | ||
| 457 | inode->i_private = NULL; | ||
| 458 | inode_unlock(inode); | ||
| 459 | securityfs_remove(chip->bios_dir[i]); | ||
| 460 | } | ||
| 461 | } | ||
| 454 | } | 462 | } |
diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h index 8de62b09be51..1660d74ea79a 100644 --- a/drivers/char/tpm/tpm_eventlog.h +++ b/drivers/char/tpm/tpm_eventlog.h | |||
| @@ -73,20 +73,24 @@ enum tcpa_pc_event_ids { | |||
| 73 | HOST_TABLE_OF_DEVICES, | 73 | HOST_TABLE_OF_DEVICES, |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | int read_log(struct tpm_bios_log *log); | 76 | #if defined(CONFIG_ACPI) |
| 77 | 77 | int tpm_read_log_acpi(struct tpm_chip *chip); | |
| 78 | #if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \ | ||
| 79 | defined(CONFIG_ACPI) | ||
| 80 | extern struct dentry **tpm_bios_log_setup(const char *); | ||
| 81 | extern void tpm_bios_log_teardown(struct dentry **); | ||
| 82 | #else | 78 | #else |
| 83 | static inline struct dentry **tpm_bios_log_setup(const char *name) | 79 | static inline int tpm_read_log_acpi(struct tpm_chip *chip) |
| 84 | { | 80 | { |
| 85 | return NULL; | 81 | return -ENODEV; |
| 86 | } | 82 | } |
| 87 | static inline void tpm_bios_log_teardown(struct dentry **dir) | 83 | #endif |
| 84 | #if defined(CONFIG_OF) | ||
| 85 | int tpm_read_log_of(struct tpm_chip *chip); | ||
| 86 | #else | ||
| 87 | static inline int tpm_read_log_of(struct tpm_chip *chip) | ||
| 88 | { | 88 | { |
| 89 | return -ENODEV; | ||
| 89 | } | 90 | } |
| 90 | #endif | 91 | #endif |
| 91 | 92 | ||
| 93 | int tpm_bios_log_setup(struct tpm_chip *chip); | ||
| 94 | void tpm_bios_log_teardown(struct tpm_chip *chip); | ||
| 95 | |||
| 92 | #endif | 96 | #endif |
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 570f30c5c5f4..7dee42d7b5e0 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * Copyright 2012 IBM Corporation | 2 | * Copyright 2012 IBM Corporation |
| 3 | * | 3 | * |
| 4 | * Author: Ashley Lai <ashleydlai@gmail.com> | 4 | * Author: Ashley Lai <ashleydlai@gmail.com> |
| 5 | * Nayna Jain <nayna@linux.vnet.ibm.com> | ||
| 5 | * | 6 | * |
| 6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | 7 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> |
| 7 | * | 8 | * |
| @@ -20,55 +21,38 @@ | |||
| 20 | #include "tpm.h" | 21 | #include "tpm.h" |
| 21 | #include "tpm_eventlog.h" | 22 | #include "tpm_eventlog.h" |
| 22 | 23 | ||
| 23 | int read_log(struct tpm_bios_log *log) | 24 | int tpm_read_log_of(struct tpm_chip *chip) |
| 24 | { | 25 | { |
| 25 | struct device_node *np; | 26 | struct device_node *np; |
| 26 | const u32 *sizep; | 27 | const u32 *sizep; |
| 27 | const u64 *basep; | 28 | const u64 *basep; |
| 29 | struct tpm_bios_log *log; | ||
| 28 | 30 | ||
| 29 | if (log->bios_event_log != NULL) { | 31 | log = &chip->log; |
| 30 | pr_err("%s: ERROR - Eventlog already initialized\n", __func__); | 32 | if (chip->dev.parent && chip->dev.parent->of_node) |
| 31 | return -EFAULT; | 33 | np = chip->dev.parent->of_node; |
| 32 | } | 34 | else |
| 33 | |||
| 34 | np = of_find_node_by_name(NULL, "vtpm"); | ||
| 35 | if (!np) { | ||
| 36 | pr_err("%s: ERROR - IBMVTPM not supported\n", __func__); | ||
| 37 | return -ENODEV; | 35 | return -ENODEV; |
| 38 | } | ||
| 39 | 36 | ||
| 40 | sizep = of_get_property(np, "linux,sml-size", NULL); | 37 | sizep = of_get_property(np, "linux,sml-size", NULL); |
| 41 | if (sizep == NULL) { | ||
| 42 | pr_err("%s: ERROR - SML size not found\n", __func__); | ||
| 43 | goto cleanup_eio; | ||
| 44 | } | ||
| 45 | if (*sizep == 0) { | ||
| 46 | pr_err("%s: ERROR - event log area empty\n", __func__); | ||
| 47 | goto cleanup_eio; | ||
| 48 | } | ||
| 49 | |||
| 50 | basep = of_get_property(np, "linux,sml-base", NULL); | 38 | basep = of_get_property(np, "linux,sml-base", NULL); |
| 51 | if (basep == NULL) { | 39 | if (sizep == NULL && basep == NULL) |
| 52 | pr_err("%s: ERROR - SML not found\n", __func__); | 40 | return -ENODEV; |
| 53 | goto cleanup_eio; | 41 | if (sizep == NULL || basep == NULL) |
| 42 | return -EIO; | ||
| 43 | |||
| 44 | if (*sizep == 0) { | ||
| 45 | dev_warn(&chip->dev, "%s: Event log area empty\n", __func__); | ||
| 46 | return -EIO; | ||
| 54 | } | 47 | } |
| 55 | 48 | ||
| 56 | log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); | 49 | log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); |
| 57 | if (!log->bios_event_log) { | 50 | if (!log->bios_event_log) |
| 58 | pr_err("%s: ERROR - Not enough memory for BIOS measurements\n", | ||
| 59 | __func__); | ||
| 60 | of_node_put(np); | ||
| 61 | return -ENOMEM; | 51 | return -ENOMEM; |
| 62 | } | ||
| 63 | 52 | ||
| 64 | log->bios_event_log_end = log->bios_event_log + *sizep; | 53 | log->bios_event_log_end = log->bios_event_log + *sizep; |
| 65 | 54 | ||
| 66 | memcpy(log->bios_event_log, __va(*basep), *sizep); | 55 | memcpy(log->bios_event_log, __va(*basep), *sizep); |
| 67 | of_node_put(np); | ||
| 68 | 56 | ||
| 69 | return 0; | 57 | return 0; |
| 70 | |||
| 71 | cleanup_eio: | ||
| 72 | of_node_put(np); | ||
| 73 | return -EIO; | ||
| 74 | } | 58 | } |
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index eaf5730d79eb..0127af130cb1 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | #include <linux/wait.h> | 28 | #include <linux/wait.h> |
| 29 | #include <linux/acpi.h> | 29 | #include <linux/acpi.h> |
| 30 | #include <linux/freezer.h> | 30 | #include <linux/freezer.h> |
| 31 | #include <linux/of.h> | ||
| 32 | #include <linux/of_device.h> | ||
| 31 | #include "tpm.h" | 33 | #include "tpm.h" |
| 32 | #include "tpm_tis_core.h" | 34 | #include "tpm_tis_core.h" |
| 33 | 35 | ||
| @@ -354,12 +356,21 @@ static int tpm_tis_plat_remove(struct platform_device *pdev) | |||
| 354 | return 0; | 356 | return 0; |
| 355 | } | 357 | } |
| 356 | 358 | ||
| 359 | #ifdef CONFIG_OF | ||
| 360 | static const struct of_device_id tis_of_platform_match[] = { | ||
| 361 | {.compatible = "tcg,tpm-tis-mmio"}, | ||
| 362 | {}, | ||
| 363 | }; | ||
| 364 | MODULE_DEVICE_TABLE(of, tis_of_platform_match); | ||
| 365 | #endif | ||
| 366 | |||
| 357 | static struct platform_driver tis_drv = { | 367 | static struct platform_driver tis_drv = { |
| 358 | .probe = tpm_tis_plat_probe, | 368 | .probe = tpm_tis_plat_probe, |
| 359 | .remove = tpm_tis_plat_remove, | 369 | .remove = tpm_tis_plat_remove, |
| 360 | .driver = { | 370 | .driver = { |
| 361 | .name = "tpm_tis", | 371 | .name = "tpm_tis", |
| 362 | .pm = &tpm_tis_pm, | 372 | .pm = &tpm_tis_pm, |
| 373 | .of_match_table = of_match_ptr(tis_of_platform_match), | ||
| 363 | }, | 374 | }, |
| 364 | }; | 375 | }; |
| 365 | 376 | ||
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index e3bf31b37138..7993678954a2 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c | |||
| @@ -180,12 +180,19 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | |||
| 180 | struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); | 180 | struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); |
| 181 | int size = 0, burstcnt, rc; | 181 | int size = 0, burstcnt, rc; |
| 182 | 182 | ||
| 183 | while (size < count && | 183 | while (size < count) { |
| 184 | wait_for_tpm_stat(chip, | 184 | rc = wait_for_tpm_stat(chip, |
| 185 | TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 185 | TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
| 186 | chip->timeout_c, | 186 | chip->timeout_c, |
| 187 | &priv->read_queue, true) == 0) { | 187 | &priv->read_queue, true); |
| 188 | burstcnt = min_t(int, get_burstcount(chip), count - size); | 188 | if (rc < 0) |
| 189 | return rc; | ||
| 190 | burstcnt = get_burstcount(chip); | ||
| 191 | if (burstcnt < 0) { | ||
| 192 | dev_err(&chip->dev, "Unable to read burstcount\n"); | ||
| 193 | return burstcnt; | ||
| 194 | } | ||
| 195 | burstcnt = min_t(int, burstcnt, count - size); | ||
| 189 | 196 | ||
| 190 | rc = tpm_tis_read_bytes(priv, TPM_DATA_FIFO(priv->locality), | 197 | rc = tpm_tis_read_bytes(priv, TPM_DATA_FIFO(priv->locality), |
| 191 | burstcnt, buf + size); | 198 | burstcnt, buf + size); |
| @@ -229,8 +236,11 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
| 229 | goto out; | 236 | goto out; |
| 230 | } | 237 | } |
| 231 | 238 | ||
| 232 | wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, | 239 | if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, |
| 233 | &priv->int_queue, false); | 240 | &priv->int_queue, false) < 0) { |
| 241 | size = -ETIME; | ||
| 242 | goto out; | ||
| 243 | } | ||
| 234 | status = tpm_tis_status(chip); | 244 | status = tpm_tis_status(chip); |
| 235 | if (status & TPM_STS_DATA_AVAIL) { /* retry? */ | 245 | if (status & TPM_STS_DATA_AVAIL) { /* retry? */ |
| 236 | dev_err(&chip->dev, "Error left over data\n"); | 246 | dev_err(&chip->dev, "Error left over data\n"); |
| @@ -271,7 +281,13 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) | |||
| 271 | } | 281 | } |
| 272 | 282 | ||
| 273 | while (count < len - 1) { | 283 | while (count < len - 1) { |
| 274 | burstcnt = min_t(int, get_burstcount(chip), len - count - 1); | 284 | burstcnt = get_burstcount(chip); |
| 285 | if (burstcnt < 0) { | ||
| 286 | dev_err(&chip->dev, "Unable to read burstcount\n"); | ||
| 287 | rc = burstcnt; | ||
| 288 | goto out_err; | ||
| 289 | } | ||
| 290 | burstcnt = min_t(int, burstcnt, len - count - 1); | ||
| 275 | rc = tpm_tis_write_bytes(priv, TPM_DATA_FIFO(priv->locality), | 291 | rc = tpm_tis_write_bytes(priv, TPM_DATA_FIFO(priv->locality), |
| 276 | burstcnt, buf + count); | 292 | burstcnt, buf + count); |
| 277 | if (rc < 0) | 293 | if (rc < 0) |
| @@ -279,8 +295,11 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) | |||
| 279 | 295 | ||
| 280 | count += burstcnt; | 296 | count += burstcnt; |
| 281 | 297 | ||
| 282 | wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, | 298 | if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, |
| 283 | &priv->int_queue, false); | 299 | &priv->int_queue, false) < 0) { |
| 300 | rc = -ETIME; | ||
| 301 | goto out_err; | ||
| 302 | } | ||
| 284 | status = tpm_tis_status(chip); | 303 | status = tpm_tis_status(chip); |
| 285 | if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { | 304 | if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { |
| 286 | rc = -EIO; | 305 | rc = -EIO; |
| @@ -293,8 +312,11 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) | |||
| 293 | if (rc < 0) | 312 | if (rc < 0) |
| 294 | goto out_err; | 313 | goto out_err; |
| 295 | 314 | ||
| 296 | wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, | 315 | if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, |
| 297 | &priv->int_queue, false); | 316 | &priv->int_queue, false) < 0) { |
| 317 | rc = -ETIME; | ||
| 318 | goto out_err; | ||
| 319 | } | ||
| 298 | status = tpm_tis_status(chip); | 320 | status = tpm_tis_status(chip); |
| 299 | if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) { | 321 | if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) { |
| 300 | rc = -EIO; | 322 | rc = -EIO; |
| @@ -755,20 +777,20 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, | |||
| 755 | if (intfcaps & TPM_INTF_DATA_AVAIL_INT) | 777 | if (intfcaps & TPM_INTF_DATA_AVAIL_INT) |
| 756 | dev_dbg(dev, "\tData Avail Int Support\n"); | 778 | dev_dbg(dev, "\tData Avail Int Support\n"); |
| 757 | 779 | ||
| 758 | /* Very early on issue a command to the TPM in polling mode to make | ||
| 759 | * sure it works. May as well use that command to set the proper | ||
| 760 | * timeouts for the driver. | ||
| 761 | */ | ||
| 762 | if (tpm_get_timeouts(chip)) { | ||
| 763 | dev_err(dev, "Could not get TPM timeouts and durations\n"); | ||
| 764 | rc = -ENODEV; | ||
| 765 | goto out_err; | ||
| 766 | } | ||
| 767 | |||
| 768 | /* INTERRUPT Setup */ | 780 | /* INTERRUPT Setup */ |
| 769 | init_waitqueue_head(&priv->read_queue); | 781 | init_waitqueue_head(&priv->read_queue); |
| 770 | init_waitqueue_head(&priv->int_queue); | 782 | init_waitqueue_head(&priv->int_queue); |
| 771 | if (irq != -1) { | 783 | if (irq != -1) { |
| 784 | /* Before doing irq testing issue a command to the TPM in polling mode | ||
| 785 | * to make sure it works. May as well use that command to set the | ||
| 786 | * proper timeouts for the driver. | ||
| 787 | */ | ||
| 788 | if (tpm_get_timeouts(chip)) { | ||
| 789 | dev_err(dev, "Could not get TPM timeouts and durations\n"); | ||
| 790 | rc = -ENODEV; | ||
| 791 | goto out_err; | ||
| 792 | } | ||
| 793 | |||
| 772 | if (irq) { | 794 | if (irq) { |
| 773 | tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED, | 795 | tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED, |
| 774 | irq); | 796 | irq); |
diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index 9a940332c157..5463b58af26e 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2015, 2016 IBM Corporation | 2 | * Copyright (C) 2015, 2016 IBM Corporation |
| 3 | * Copyright (C) 2016 Intel Corporation | ||
| 3 | * | 4 | * |
| 4 | * Author: Stefan Berger <stefanb@us.ibm.com> | 5 | * Author: Stefan Berger <stefanb@us.ibm.com> |
| 5 | * | 6 | * |
| @@ -41,6 +42,7 @@ struct proxy_dev { | |||
| 41 | long state; /* internal state */ | 42 | long state; /* internal state */ |
| 42 | #define STATE_OPENED_FLAG BIT(0) | 43 | #define STATE_OPENED_FLAG BIT(0) |
| 43 | #define STATE_WAIT_RESPONSE_FLAG BIT(1) /* waiting for emulator response */ | 44 | #define STATE_WAIT_RESPONSE_FLAG BIT(1) /* waiting for emulator response */ |
| 45 | #define STATE_REGISTERED_FLAG BIT(2) | ||
| 44 | 46 | ||
| 45 | size_t req_len; /* length of queued TPM request */ | 47 | size_t req_len; /* length of queued TPM request */ |
| 46 | size_t resp_len; /* length of queued TPM response */ | 48 | size_t resp_len; /* length of queued TPM response */ |
| @@ -369,12 +371,9 @@ static void vtpm_proxy_work(struct work_struct *work) | |||
| 369 | 371 | ||
| 370 | rc = tpm_chip_register(proxy_dev->chip); | 372 | rc = tpm_chip_register(proxy_dev->chip); |
| 371 | if (rc) | 373 | if (rc) |
| 372 | goto err; | 374 | vtpm_proxy_fops_undo_open(proxy_dev); |
| 373 | 375 | else | |
| 374 | return; | 376 | proxy_dev->state |= STATE_REGISTERED_FLAG; |
| 375 | |||
| 376 | err: | ||
| 377 | vtpm_proxy_fops_undo_open(proxy_dev); | ||
| 378 | } | 377 | } |
| 379 | 378 | ||
| 380 | /* | 379 | /* |
| @@ -515,7 +514,8 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev) | |||
| 515 | */ | 514 | */ |
| 516 | vtpm_proxy_fops_undo_open(proxy_dev); | 515 | vtpm_proxy_fops_undo_open(proxy_dev); |
| 517 | 516 | ||
| 518 | tpm_chip_unregister(proxy_dev->chip); | 517 | if (proxy_dev->state & STATE_REGISTERED_FLAG) |
| 518 | tpm_chip_unregister(proxy_dev->chip); | ||
| 519 | 519 | ||
| 520 | vtpm_proxy_delete_proxy_dev(proxy_dev); | 520 | vtpm_proxy_delete_proxy_dev(proxy_dev); |
| 521 | } | 521 | } |
| @@ -524,6 +524,50 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev) | |||
| 524 | * Code related to the control device /dev/vtpmx | 524 | * Code related to the control device /dev/vtpmx |
| 525 | */ | 525 | */ |
| 526 | 526 | ||
| 527 | /** | ||
| 528 | * vtpmx_ioc_new_dev - handler for the %VTPM_PROXY_IOC_NEW_DEV ioctl | ||
| 529 | * @file: /dev/vtpmx | ||
| 530 | * @ioctl: the ioctl number | ||
| 531 | * @arg: pointer to the struct vtpmx_proxy_new_dev | ||
| 532 | * | ||
| 533 | * Creates an anonymous file that is used by the process acting as a TPM to | ||
| 534 | * communicate with the client processes. The function will also add a new TPM | ||
| 535 | * device through which data is proxied to this TPM acting process. The caller | ||
| 536 | * will be provided with a file descriptor to communicate with the clients and | ||
| 537 | * major and minor numbers for the TPM device. | ||
| 538 | */ | ||
| 539 | static long vtpmx_ioc_new_dev(struct file *file, unsigned int ioctl, | ||
| 540 | unsigned long arg) | ||
| 541 | { | ||
| 542 | void __user *argp = (void __user *)arg; | ||
| 543 | struct vtpm_proxy_new_dev __user *vtpm_new_dev_p; | ||
| 544 | struct vtpm_proxy_new_dev vtpm_new_dev; | ||
| 545 | struct file *vtpm_file; | ||
| 546 | |||
| 547 | if (!capable(CAP_SYS_ADMIN)) | ||
| 548 | return -EPERM; | ||
| 549 | |||
| 550 | vtpm_new_dev_p = argp; | ||
| 551 | |||
| 552 | if (copy_from_user(&vtpm_new_dev, vtpm_new_dev_p, | ||
| 553 | sizeof(vtpm_new_dev))) | ||
| 554 | return -EFAULT; | ||
| 555 | |||
| 556 | vtpm_file = vtpm_proxy_create_device(&vtpm_new_dev); | ||
| 557 | if (IS_ERR(vtpm_file)) | ||
| 558 | return PTR_ERR(vtpm_file); | ||
| 559 | |||
| 560 | if (copy_to_user(vtpm_new_dev_p, &vtpm_new_dev, | ||
| 561 | sizeof(vtpm_new_dev))) { | ||
| 562 | put_unused_fd(vtpm_new_dev.fd); | ||
| 563 | fput(vtpm_file); | ||
| 564 | return -EFAULT; | ||
| 565 | } | ||
| 566 | |||
| 567 | fd_install(vtpm_new_dev.fd, vtpm_file); | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 527 | /* | 571 | /* |
| 528 | * vtpmx_fops_ioctl: ioctl on /dev/vtpmx | 572 | * vtpmx_fops_ioctl: ioctl on /dev/vtpmx |
| 529 | * | 573 | * |
| @@ -531,34 +575,11 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev) | |||
| 531 | * Returns 0 on success, a negative error code otherwise. | 575 | * Returns 0 on success, a negative error code otherwise. |
| 532 | */ | 576 | */ |
| 533 | static long vtpmx_fops_ioctl(struct file *f, unsigned int ioctl, | 577 | static long vtpmx_fops_ioctl(struct file *f, unsigned int ioctl, |
| 534 | unsigned long arg) | 578 | unsigned long arg) |
| 535 | { | 579 | { |
| 536 | void __user *argp = (void __user *)arg; | ||
| 537 | struct vtpm_proxy_new_dev __user *vtpm_new_dev_p; | ||
| 538 | struct vtpm_proxy_new_dev vtpm_new_dev; | ||
| 539 | struct file *file; | ||
| 540 | |||
| 541 | switch (ioctl) { | 580 | switch (ioctl) { |
| 542 | case VTPM_PROXY_IOC_NEW_DEV: | 581 | case VTPM_PROXY_IOC_NEW_DEV: |
| 543 | if (!capable(CAP_SYS_ADMIN)) | 582 | return vtpmx_ioc_new_dev(f, ioctl, arg); |
| 544 | return -EPERM; | ||
| 545 | vtpm_new_dev_p = argp; | ||
| 546 | if (copy_from_user(&vtpm_new_dev, vtpm_new_dev_p, | ||
| 547 | sizeof(vtpm_new_dev))) | ||
| 548 | return -EFAULT; | ||
| 549 | file = vtpm_proxy_create_device(&vtpm_new_dev); | ||
| 550 | if (IS_ERR(file)) | ||
| 551 | return PTR_ERR(file); | ||
| 552 | if (copy_to_user(vtpm_new_dev_p, &vtpm_new_dev, | ||
| 553 | sizeof(vtpm_new_dev))) { | ||
| 554 | put_unused_fd(vtpm_new_dev.fd); | ||
| 555 | fput(file); | ||
| 556 | return -EFAULT; | ||
| 557 | } | ||
| 558 | |||
| 559 | fd_install(vtpm_new_dev.fd, file); | ||
| 560 | return 0; | ||
| 561 | |||
| 562 | default: | 583 | default: |
| 563 | return -ENOIOCTLCMD; | 584 | return -ENOIOCTLCMD; |
| 564 | } | 585 | } |
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 50072cc4fe5c..5aaa268f3a78 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c | |||
| @@ -307,7 +307,6 @@ static int tpmfront_probe(struct xenbus_device *dev, | |||
| 307 | rv = setup_ring(dev, priv); | 307 | rv = setup_ring(dev, priv); |
| 308 | if (rv) { | 308 | if (rv) { |
| 309 | chip = dev_get_drvdata(&dev->dev); | 309 | chip = dev_get_drvdata(&dev->dev); |
| 310 | tpm_chip_unregister(chip); | ||
| 311 | ring_free(priv); | 310 | ring_free(priv); |
| 312 | return rv; | 311 | return rv; |
| 313 | } | 312 | } |
