Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751834AbaKZAmd (ORCPT ); Tue, 25 Nov 2014 19:42:33 -0500 Received: from e9.ny.us.ibm.com ([32.97.182.139]:53781 "EHLO e9.ny.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751409AbaKZAmb (ORCPT ); Tue, 25 Nov 2014 19:42:31 -0500 Message-ID: <547521F1.7040209@linux.vnet.ibm.com> Date: Tue, 25 Nov 2014 19:42:25 -0500 From: Stefan Berger User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 MIME-Version: 1.0 To: Jarkko Sakkinen , Peter Huewe , Ashley Lai , Marcel Selhorst CC: christophe.ricard@gmail.com, josh.triplett@intel.com, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, Will Arthur , tpmdd-devel@lists.sourceforge.net, jason.gunthorpe@obsidianresearch.com, trousers-tech@lists.sourceforge.net Subject: Re: [tpmdd-devel] [PATCH v7 07/10] tpm: TPM 2.0 baseline support References: <1415713513-16524-1-git-send-email-jarkko.sakkinen@linux.intel.com> <1415713513-16524-8-git-send-email-jarkko.sakkinen@linux.intel.com> In-Reply-To: <1415713513-16524-8-git-send-email-jarkko.sakkinen@linux.intel.com> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 14112600-0033-0000-0000-000001262EB0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote: > TPM 2.0 devices are separated by adding a field 'flags' to struct > tpm_chip and defining a flag TPM_CHIP_FLAG_TPM2 for tagging them. > > This patch adds the following internal functions: > > - tpm2_get_random() > - tpm2_get_tpm_pt() > - tpm2_pcr_extend() > - tpm2_pcr_read() > - tpm2_startup() > > Additionally, the following exported functions are implemented for > implementing TPM 2.0 device drivers: > > - tpm2_do_selftest() > - tpm2_calc_ordinal_durations() > - tpm2_gen_interrupt() > > The existing functions that are exported for the use for existing > subsystems have been changed to check the flags field in struct > tpm_chip and use appropriate TPM 2.0 counterpart if > TPM_CHIP_FLAG_TPM2 is est. > > The code for tpm2_calc_ordinal_duration() and tpm2_startup() were > originally written by Will Arthur. > > Signed-off-by: Jarkko Sakkinen > Signed-off-by: Will Arthur > --- > drivers/char/tpm/Makefile | 2 +- > drivers/char/tpm/tpm-chip.c | 21 +- > drivers/char/tpm/tpm-interface.c | 24 +- > drivers/char/tpm/tpm.h | 67 +++++ > drivers/char/tpm/tpm2-cmd.c | 566 +++++++++++++++++++++++++++++++++++++++ > 5 files changed, 668 insertions(+), 12 deletions(-) > create mode 100644 drivers/char/tpm/tpm2-cmd.c > > diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile > index 837da04..ae56af9 100644 > --- a/drivers/char/tpm/Makefile > +++ b/drivers/char/tpm/Makefile > @@ -2,7 +2,7 @@ > # Makefile for the kernel tpm device drivers. > # > obj-$(CONFIG_TCG_TPM) += tpm.o > -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o > +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o > tpm-$(CONFIG_ACPI) += tpm_ppi.o > > ifdef CONFIG_ACPI > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c > index 5d268ac..4d25b24 100644 > --- a/drivers/char/tpm/tpm-chip.c > +++ b/drivers/char/tpm/tpm-chip.c > @@ -213,11 +213,14 @@ int tpm_chip_register(struct tpm_chip *chip) > if (rc) > return rc; > > - rc = tpm_add_ppi(chip); > - if (rc) > - goto out_err; > + /* Populate sysfs for TPM1 devices. */ > + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { > + rc = tpm_add_ppi(chip); > + if (rc) > + goto out_err; > > - chip->bios_dir = tpm_bios_log_setup(chip->devname); > + chip->bios_dir = tpm_bios_log_setup(chip->devname); > + } > > /* Make the chip available. */ > spin_lock(&driver_lock); > @@ -248,10 +251,12 @@ void tpm_chip_unregister(struct tpm_chip *chip) > spin_unlock(&driver_lock); > synchronize_rcu(); > > - tpm_remove_ppi(chip); > - > - if (chip->bios_dir) > - tpm_bios_log_teardown(chip->bios_dir); > + /* Clean up sysfs for TPM1 devices. */ > + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { > + if (chip->bios_dir) > + tpm_bios_log_teardown(chip->bios_dir); > + tpm_remove_ppi(chip); > + } > > tpm_dev_del_device(chip); > } > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c > index 9e4ce4d..e62b835 100644 > --- a/drivers/char/tpm/tpm-interface.c > +++ b/drivers/char/tpm/tpm-interface.c > @@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, > if (chip->vendor.irq) > goto out_recv; > > - stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); > + if (chip->flags & TPM_CHIP_FLAG_TPM2) > + stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal); > + else > + stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); > do { > u8 status = chip->ops->status(chip); > if ((status & chip->ops->req_complete_mask) == > @@ -483,7 +486,7 @@ static const struct tpm_input_header tpm_startup_header = { > static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) > { > struct tpm_cmd_t start_cmd; > - start_cmd.header.in = tpm_startup_header; > + > start_cmd.params.startup_in.startup_type = startup_type; > return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, > "attempting to start the TPM"); > @@ -680,7 +683,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) > chip = tpm_chip_find_get(chip_num); > if (chip == NULL) > return -ENODEV; > - rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); > + if (chip->flags & TPM_CHIP_FLAG_TPM2) > + rc = tpm2_pcr_read(chip, pcr_idx, res_buf); > + else > + rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); > tpm_chip_put(chip); > return rc; > } > @@ -714,6 +720,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) > if (chip == NULL) > return -ENODEV; > > + if (chip->flags & TPM_CHIP_FLAG_TPM2) { > + rc = tpm2_pcr_extend(chip, pcr_idx, hash); > + tpm_chip_put(chip); > + return rc; > + } > + > cmd.header.in = pcrextend_header; > cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); > memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); > @@ -974,6 +986,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) > if (chip == NULL) > return -ENODEV; > > + if (chip->flags & TPM_CHIP_FLAG_TPM2) { > + err = tpm2_get_random(chip, out, max); > + tpm_chip_put(chip); > + return err; > + } > + > do { > tpm_cmd.header.in = tpm_getrandom_header; > tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h > index 9d062e6..8a434d2 100644 > --- a/drivers/char/tpm/tpm.h > +++ b/drivers/char/tpm/tpm.h > @@ -62,6 +62,57 @@ enum tpm_duration { > #define TPM_ERR_INVALID_POSTINIT 38 > > #define TPM_HEADER_SIZE 10 > + > +enum tpm2_const { > + TPM2_PLATFORM_PCR = 24, > + TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8), > + TPM2_TIMEOUT_A = 750 * 1000, > + TPM2_TIMEOUT_B = 2000 * 1000, > + TPM2_TIMEOUT_C = 200 * 1000, > + TPM2_TIMEOUT_D = 30 * 1000, > + TPM2_DURATION_SHORT = 20 * 1000, > + TPM2_DURATION_MEDIUM = 750 * 1000, > + TPM2_DURATION_LONG = 2000 * 1000, > +}; > + > +enum tpm2_structures { > + TPM2_ST_NO_SESSIONS = 0x8001, > + TPM2_ST_SESSIONS = 0x8002, > +}; > + > +enum tpm2_return_codes { > + TPM2_RC_TESTING = 0x090A, > + TPM2_RC_DISABLED = 0x0120, > +}; > + > +enum tpm2_algorithms { > + TPM2_ALG_SHA1 = 0x0004, > +}; > + > +enum tpm2_command_codes { > + TPM2_CC_FIRST = 0x011F, > + TPM2_CC_SELF_TEST = 0x0143, > + TPM2_CC_STARTUP = 0x0144, > + TPM2_CC_GET_CAPABILITY = 0x017A, > + TPM2_CC_GET_RANDOM = 0x017B, > + TPM2_CC_PCR_READ = 0x017E, > + TPM2_CC_PCR_EXTEND = 0x0182, > + TPM2_CC_LAST = 0x018F, > +}; > + > +enum tpm2_permanent_handles { > + TPM2_RS_PW = 0x40000009, > +}; > + > +enum tpm2_capabilities { > + TPM2_CAP_TPM_PROPERTIES = 6, > +}; > + > +enum tpm2_startup_types { > + TPM2_SU_CLEAR = 0x0000, > + TPM2_SU_STATE = 0x0001, > +}; > + > struct tpm_chip; > > struct tpm_vendor_specific { > @@ -96,12 +147,17 @@ struct tpm_vendor_specific { > > #define TPM_PPI_VERSION_LEN 3 > > +enum tpm_chip_flags { > + TPM_CHIP_FLAG_TPM2 = BIT(0), > +}; > + > struct tpm_chip { > struct device *pdev; /* Device stuff */ > struct device dev; > struct cdev cdev; > > const struct tpm_class_ops *ops; > + unsigned int flags; > > int dev_num; /* /dev/tpm# */ > char devname[7]; > @@ -362,3 +418,14 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip) > { > } > #endif > + > +int tpm2_startup(struct tpm_chip *chip, __be16 startup_type); > +int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); > +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); > +int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); > + > +extern ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, > + u32 *value, const char *desc); > +extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); > +extern int tpm2_do_selftest(struct tpm_chip *chip); > +extern int tpm2_gen_interrupt(struct tpm_chip *chip); > diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c > new file mode 100644 > index 0000000..458a17d > --- /dev/null > +++ b/drivers/char/tpm/tpm2-cmd.c > @@ -0,0 +1,566 @@ > +/* > + * Copyright (C) 2014 Intel Corporation > + * > + * Authors: > + * Jarkko Sakkinen > + * > + * Maintained by: > + * > + * This file contains TPM2 protocol implementations of the commands > + * used by the kernel internally. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; version 2 > + * of the License. > + */ > + > +#include "tpm.h" > + > +struct tpm2_startup_in { > + __be16 startup_type; > +} __packed; > + > +struct tpm2_self_test_in { > + u8 full_test; > +} __packed; > + > +struct tpm2_pcr_read_in { > + __be32 pcr_selects_cnt; > + __be16 hash_alg; > + u8 pcr_select_size; > + u8 pcr_select[TPM2_PCR_SELECT_MIN]; > +} __packed; > + > +struct tpm2_pcr_read_out { > + __be32 update_cnt; > + __be32 pcr_selects_cnt; > + __be16 hash_alg; > + u8 pcr_select_size; > + u8 pcr_select[TPM2_PCR_SELECT_MIN]; > + __be32 digests_cnt; > + __be16 digest_size; > + u8 digest[TPM_DIGEST_SIZE]; > +} __packed; > + > +struct tpm2_null_auth_area { > + __be32 handle; > + __be16 nonce_size; > + u8 attributes; > + __be16 auth_size; > +} __packed; > + > +struct tpm2_pcr_extend_in { > + __be32 pcr_idx; > + __be32 auth_area_size; > + struct tpm2_null_auth_area auth_area; > + __be32 digest_cnt; > + __be16 hash_alg; > + u8 digest[TPM_DIGEST_SIZE]; > +} __packed; > + > +struct tpm2_get_tpm_pt_in { > + __be32 cap_id; > + __be32 property_id; > + __be32 property_cnt; > +} __packed; > + > +struct tpm2_get_tpm_pt_out { > + u8 more_data; > + __be32 subcap_id; > + __be32 property_cnt; > + __be32 property_id; > + __be32 value; > +} __packed; > + > +struct tpm2_get_random_in { > + __be16 size; > +} __packed; > + > +struct tpm2_get_random_out { > + __be16 size; > + u8 buffer[TPM_MAX_RNG_DATA]; > +} __packed; > + > +union tpm2_cmd_params { > + struct tpm2_startup_in startup_in; > + struct tpm2_self_test_in selftest_in; > + struct tpm2_pcr_read_in pcrread_in; > + struct tpm2_pcr_read_out pcrread_out; > + struct tpm2_pcr_extend_in pcrextend_in; > + struct tpm2_get_tpm_pt_in get_tpm_pt_in; > + struct tpm2_get_tpm_pt_out get_tpm_pt_out; > + struct tpm2_get_random_in getrandom_in; > + struct tpm2_get_random_out getrandom_out; > +}; > + > +struct tpm2_cmd { > + tpm_cmd_header header; > + union tpm2_cmd_params params; > +} __packed; > + > +/* > + * Array with one entry per ordinal defining the maximum amount > + * of time the chip could take to return the result. The values > + * of the SHORT, MEDIUM, and LONG durations are taken from the > + * PC Client Profile (PTP) specification. > + */ > +static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { > + TPM_UNDEFINED, /* 11F */ > + TPM_UNDEFINED, /* 120 */ > + TPM_LONG, /* 121 */ > + TPM_UNDEFINED, /* 122 */ > + TPM_UNDEFINED, /* 123 */ > + TPM_UNDEFINED, /* 124 */ > + TPM_UNDEFINED, /* 125 */ > + TPM_UNDEFINED, /* 126 */ > + TPM_UNDEFINED, /* 127 */ > + TPM_UNDEFINED, /* 128 */ > + TPM_LONG, /* 129 */ > + TPM_UNDEFINED, /* 12a */ > + TPM_UNDEFINED, /* 12b */ > + TPM_UNDEFINED, /* 12c */ > + TPM_UNDEFINED, /* 12d */ > + TPM_UNDEFINED, /* 12e */ > + TPM_UNDEFINED, /* 12f */ > + TPM_UNDEFINED, /* 130 */ > + TPM_UNDEFINED, /* 131 */ > + TPM_UNDEFINED, /* 132 */ > + TPM_UNDEFINED, /* 133 */ > + TPM_UNDEFINED, /* 134 */ > + TPM_UNDEFINED, /* 135 */ > + TPM_UNDEFINED, /* 136 */ > + TPM_UNDEFINED, /* 137 */ > + TPM_UNDEFINED, /* 138 */ > + TPM_UNDEFINED, /* 139 */ > + TPM_UNDEFINED, /* 13a */ > + TPM_UNDEFINED, /* 13b */ > + TPM_UNDEFINED, /* 13c */ > + TPM_UNDEFINED, /* 13d */ > + TPM_MEDIUM, /* 13e */ > + TPM_UNDEFINED, /* 13f */ > + TPM_UNDEFINED, /* 140 */ > + TPM_UNDEFINED, /* 141 */ > + TPM_UNDEFINED, /* 142 */ > + TPM_LONG, /* 143 */ > + TPM_MEDIUM, /* 144 */ > + TPM_UNDEFINED, /* 145 */ > + TPM_UNDEFINED, /* 146 */ > + TPM_UNDEFINED, /* 147 */ > + TPM_UNDEFINED, /* 148 */ > + TPM_UNDEFINED, /* 149 */ > + TPM_UNDEFINED, /* 14a */ > + TPM_UNDEFINED, /* 14b */ > + TPM_UNDEFINED, /* 14c */ > + TPM_UNDEFINED, /* 14d */ > + TPM_LONG, /* 14e */ > + TPM_UNDEFINED, /* 14f */ > + TPM_UNDEFINED, /* 150 */ > + TPM_UNDEFINED, /* 151 */ > + TPM_UNDEFINED, /* 152 */ > + TPM_UNDEFINED, /* 153 */ > + TPM_UNDEFINED, /* 154 */ > + TPM_UNDEFINED, /* 155 */ > + TPM_UNDEFINED, /* 156 */ > + TPM_UNDEFINED, /* 157 */ > + TPM_UNDEFINED, /* 158 */ > + TPM_UNDEFINED, /* 159 */ > + TPM_UNDEFINED, /* 15a */ > + TPM_UNDEFINED, /* 15b */ > + TPM_MEDIUM, /* 15c */ > + TPM_UNDEFINED, /* 15d */ > + TPM_UNDEFINED, /* 15e */ > + TPM_UNDEFINED, /* 15f */ > + TPM_UNDEFINED, /* 160 */ > + TPM_UNDEFINED, /* 161 */ > + TPM_UNDEFINED, /* 162 */ > + TPM_UNDEFINED, /* 163 */ > + TPM_UNDEFINED, /* 164 */ > + TPM_UNDEFINED, /* 165 */ > + TPM_UNDEFINED, /* 166 */ > + TPM_UNDEFINED, /* 167 */ > + TPM_UNDEFINED, /* 168 */ > + TPM_UNDEFINED, /* 169 */ > + TPM_UNDEFINED, /* 16a */ > + TPM_UNDEFINED, /* 16b */ > + TPM_UNDEFINED, /* 16c */ > + TPM_UNDEFINED, /* 16d */ > + TPM_UNDEFINED, /* 16e */ > + TPM_UNDEFINED, /* 16f */ > + TPM_UNDEFINED, /* 170 */ > + TPM_UNDEFINED, /* 171 */ > + TPM_UNDEFINED, /* 172 */ > + TPM_UNDEFINED, /* 173 */ > + TPM_UNDEFINED, /* 174 */ > + TPM_UNDEFINED, /* 175 */ > + TPM_UNDEFINED, /* 176 */ > + TPM_LONG, /* 177 */ > + TPM_UNDEFINED, /* 178 */ > + TPM_UNDEFINED, /* 179 */ > + TPM_MEDIUM, /* 17a */ > + TPM_LONG, /* 17b */ > + TPM_UNDEFINED, /* 17c */ > + TPM_UNDEFINED, /* 17d */ > + TPM_UNDEFINED, /* 17e */ > + TPM_UNDEFINED, /* 17f */ > + TPM_UNDEFINED, /* 180 */ > + TPM_UNDEFINED, /* 181 */ > + TPM_MEDIUM, /* 182 */ > + TPM_UNDEFINED, /* 183 */ > + TPM_UNDEFINED, /* 184 */ > + TPM_MEDIUM, /* 185 */ > + TPM_MEDIUM, /* 186 */ > + TPM_UNDEFINED, /* 187 */ > + TPM_UNDEFINED, /* 188 */ > + TPM_UNDEFINED, /* 189 */ > + TPM_UNDEFINED, /* 18a */ > + TPM_UNDEFINED, /* 18b */ > + TPM_UNDEFINED, /* 18c */ > + TPM_UNDEFINED, /* 18d */ > + TPM_UNDEFINED, /* 18e */ > + TPM_UNDEFINED /* 18f */ > +}; > + > +static const struct tpm_input_header tpm2_startup_header = { > + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), > + .length = cpu_to_be32(12), 12 -> sizeof(struct tpm_input_header) + sizeof(struct pm2_startup_in) > + .ordinal = cpu_to_be32(TPM2_CC_STARTUP) > +}; > + > +/** > + * tpm2_startup() - send startup command to the TPM chip > + * @chip: TPM chip to use. > + * @startup_type startup type. The value is either > + * TPM_SU_CLEAR or TPM_SU_STATE. > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. Replace 'When's with 'If's. (when being 'temporal') > + */ > +int tpm2_startup(struct tpm_chip *chip, __be16 startup_type) > +{ > + struct tpm2_cmd cmd; > + > + cmd.header.in = tpm2_startup_header; > + > + cmd.params.startup_in.startup_type = startup_type; > + return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), > + "attempting to start the TPM"); > +} > + > +#define TPM2_PCR_READ_IN_SIZE \ > + (sizeof(struct tpm_input_header) + \ > + sizeof(struct tpm2_pcr_read_in)) > + Ah! You could also use a #define above! > +static const struct tpm_input_header tpm2_pcrread_header = { > + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), > + .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE), > + .ordinal = cpu_to_be32(TPM2_CC_PCR_READ) > +}; > + > +/** > + * tpm2_pcr_read() - read a PCR value > + * @chip: TPM chip to use. > + * @pcr_idx: index of the PCR to read. > + * @ref_buf: buffer to store the resulting hash, > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. > + */ Replace 'When's with 'If's. Also further below. > +int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) > +{ > + int rc; > + struct tpm2_cmd cmd; > + u8 *buf; > + int i, j; > + > + if (pcr_idx >= TPM2_PLATFORM_PCR) > + return -EINVAL; > + > + cmd.header.in = tpm2_pcrread_header; > + cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1); > + cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); > + cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN; > + > + for (i = 0; i < TPM2_PCR_SELECT_MIN; i++) { > + j = pcr_idx - i * 8; > + > + cmd.params.pcrread_in.pcr_select[i] = > + (j >= 0 && j < 8) ? 1 << j : 0; > + } Umpf - what's this? You need to set the PCR index as an index in the bitfield? pcr_idx >> 3 gives you the index into the array, assuming that [0] holds bits for PCR0 to 7. 1 << (pcr_idx & 0x7) gives you the bit to set, assuming bit 0 is to be set for PCR 0 1 << (7- (pcr_idx & 0x7)) gives you the bit to set, assuming bit 7 is to be set for PCR 0. memset(cmd.params.pcrread_in.pcr_select, 0, sizeof(cmd.params.pcrread_in.pcr_select)); cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); > + > + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), > + "attempting to read a pcr value"); > + > + if (rc == 0) { > + buf = cmd.params.pcrread_out.digest; > + memcpy(res_buf, buf, TPM_DIGEST_SIZE); > + } > + > + return rc; > +} > + > +/** > + * tpm2_pcr_extend() - extend a PCR value > + * @chip: TPM chip to use. > + * @pcr_idx: index of the PCR. > + * @hash: hash value to use for the extend operation. > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. > + */ > +static const struct tpm_input_header tpm2_pcrextend_header = { > + .tag = cpu_to_be16(TPM2_ST_SESSIONS), > + .length = cpu_to_be32(sizeof(struct tpm_input_header) + > + sizeof(struct tpm2_pcr_extend_in)), > + .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND) > +}; > + > +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) > +{ > + struct tpm2_cmd cmd; > + int rc; > + > + cmd.header.in = tpm2_pcrextend_header; > + cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); > + cmd.params.pcrextend_in.auth_area_size = > + cpu_to_be32(sizeof(struct tpm2_null_auth_area)); > + cmd.params.pcrextend_in.auth_area.handle = > + cpu_to_be32(TPM2_RS_PW); > + cmd.params.pcrextend_in.auth_area.nonce_size = 0; > + cmd.params.pcrextend_in.auth_area.attributes = 0; > + cmd.params.pcrextend_in.auth_area.auth_size = 0; > + cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1); > + cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); > + memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE); > + > + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), > + "attempting extend a PCR value"); > + > + return rc; > +} > + > +static const struct tpm_input_header tpm2_getrandom_header = { > + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), > + .length = cpu_to_be32(sizeof(struct tpm_input_header) + > + sizeof(struct tpm2_get_random_in)), > + .ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM) > +}; > + > +/** > + * tpm2_get_random() - get random bytes from the TPM RNG > + * @chip: TPM chip to use > + * @out: destination buffer for the random bytes > + * @max: the max number of bytes to write to @out > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. > + */ > +int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) > +{ > + struct tpm2_cmd cmd; > + u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); num_bytes = min_t(u32, max, sizeof(tpm2_cmd.params.getrandom_out.buffer); This way you tie it to the actual buffer size of the buffer the TPM can fill > + int err, total = 0, retries = 5; > + u8 *dest = out; > + > + if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) ... || max > sizeof((tpm2_cmd.params.getrandom_out.buffer) > + return -EINVAL; > + > + do { > + cmd.header.in = tpm2_getrandom_header; > + cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); > + > + err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), > + "attempting get random"); > + if (err) > + break; > + > + recd = be16_to_cpu(cmd.params.getrandom_out.size); > + memcpy(dest, cmd.params.getrandom_out.buffer, recd); to be on the safe side, I would do /* never accept more bytes than we asked for */ recd = min(recd, num_bytes); memcpy(dest, cmd.params.getrandom_out.buffer, recd); so that the destination buffer can never be overwritten beyond its boundaries by a TPM that just ends up sending you more bytes than you asked for (firmware bug). > + > + dest += recd; > + total += recd; > + num_bytes -= recd; > + } while (retries-- && total < max); > + > + return total ? total : -EIO; > +} > + > +#define TPM2_GET_TPM_PT_IN_SIZE \ > + (sizeof(struct tpm_input_header) + \ > + sizeof(struct tpm2_get_tpm_pt_in)) > + > +static const struct tpm_input_header tpm2_get_tpm_pt_header = { > + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), > + .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE), > + .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY) > +}; > + > +/** > + * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property > + * @chip: TPM chip to use. > + * @property_id: property ID. > + * @value: output variable. > + * @desc: passed to tpm_transmit_cmd() > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. > + */ > +ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, > + const char *desc) > +{ > + struct tpm2_cmd cmd; > + int rc; > + > + cmd.header.in = tpm2_get_tpm_pt_header; > + cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES); > + cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); > + cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); > + > + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc); > + if (!rc) > + *value = cmd.params.get_tpm_pt_out.value; > + > + return rc; > +} > +EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt); > + > +/* > + * tpm2_calc_ordinal_duration() - maximum duration for a command > + * @chip: TPM chip to use. > + * @ordinal: command code number. > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. > + */ > +unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) > +{ > + int index = TPM_UNDEFINED; > + int duration = 0; > + > + if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST) > + index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST]; > + > + if (index != TPM_UNDEFINED) > + duration = chip->vendor.duration[index]; > + if (duration <= 0) > + return 2 * 60 * HZ; > + else > + return duration; > +} > +EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration); > + > +static const struct tpm_input_header tpm2_selftest_header = { > + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), > + .length = cpu_to_be32(sizeof(struct tpm_input_header) + > + sizeof(struct tpm2_self_test_in)), > + .ordinal = cpu_to_be32(TPM2_CC_SELF_TEST) > +}; > + > +#define TPM2_SELF_TEST_IN_SIZE \ > + (sizeof(struct tpm_input_header) + sizeof(struct tpm2_self_test_in)) > + > +/** > + * tpm2_continue_selftest() - start a self test > + * @chip: TPM chip to use > + * @full: test all commands instead of testing only those that were not > + * previously tested. > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. > + */ > +static int tpm2_start_selftest(struct tpm_chip *chip, bool full) > +{ > + int rc; > + struct tpm2_cmd cmd; > + > + cmd.header.in = tpm2_selftest_header; > + cmd.params.selftest_in.full_test = full; > + > + rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, > + "continue selftest"); > + > + return rc; > +} > + > +/** > + * tpm2_do_selftest() - run a full self test > + * @chip: TPM chip to use > + * > + * During the self test TPM2 commands return with the error code RC_TESTING. > + * Waiting is done by issuing PCR read until it executes successfully. > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. > + */ > +int tpm2_do_selftest(struct tpm_chip *chip) > +{ > + int rc; > + unsigned int loops; > + unsigned int delay_msec = 100; > + unsigned long duration; > + struct tpm2_cmd cmd; > + int i; > + > + duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST); > + > + loops = jiffies_to_msecs(duration) / delay_msec; > + > + rc = tpm2_start_selftest(chip, true); > + if (rc) > + return rc; > + > + for (i = 0; i < loops; i++) { > + /* Attempt to read a PCR value */ > + cmd.header.in = tpm2_pcrread_header; > + cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1); > + cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); > + cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN; > + cmd.params.pcrread_in.pcr_select[0] = 0x01; > + cmd.params.pcrread_in.pcr_select[1] = 0x00; > + cmd.params.pcrread_in.pcr_select[2] = 0x00; > + > + rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL); > + if (rc < 0) > + break; > + > + rc = be32_to_cpu(cmd.header.out.return_code); > + if (rc != TPM2_RC_TESTING) > + break; > + > + msleep(delay_msec); > + } > + > + return rc; > +} > +EXPORT_SYMBOL_GPL(tpm2_do_selftest); > + > +/** > + * tpm2_gen_interrupt() - generate an interrupt > + * @chip: TPM chip to use > + * > + * 0 is returned when the operation is successful. When a negative number is > + * returned it remarks a POSIX error code. When a positive number is returned > + * it remarks a TPM error. > + */ > + > +int tpm2_gen_interrupt(struct tpm_chip *chip) > +{ > + u32 dummy; > + int rc; > + > + rc = tpm2_get_tpm_pt(chip, > + TPM2_CAP_TPM_PROPERTIES, > + &dummy, > + "attempting to generate an interrupt"); > + > + return rc; > +} > +EXPORT_SYMBOL_GPL(tpm2_gen_interrupt); Stefan -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/