PATCH 6/7] tpm: new 1.2 sysfs files

From: Kylene Jo Hall
Date: Mon Apr 03 2006 - 12:44:17 EST


With the 1.2 TPM Specification there is more useful information
available. This information is exported to the user through sysfs
functions that the 1.2 driver will use.

Signed-off-by: Kylene Hall <kjhall@xxxxxxxxxx>
---
drivers/char/tpm/tpm.c | 206 +++++++++++++++++++++++++++++++++++++++
drivers/char/tpm/tpm.h | 7 +
2 files changed, 213 insertions(+)

--- linux-2.6.16/drivers/char/tpm/tpm.c 2006-03-30 16:58:10.715155750 -0600
+++ linux-2.6.16-rc1-tpm/drivers/char/tpm/tpm.c 2006-03-30 16:51:48.567273000 -0600
@@ -431,17 +434,27 @@ out:
#define TPM_GET_CAP_RET_UINT32_2_IDX 18
#define TPM_GET_CAP_RET_UINT32_3_IDX 22
#define TPM_GET_CAP_RET_UINT32_4_IDX 26
+#define TPM_GET_CAP_PERM_DISABLE_IDX 16
+#define TPM_GET_CAP_PERM_INACTIVE_IDX 18
+#define TPM_GET_CAP_RET_BOOL_1_IDX 14
+#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16

#define TPM_CAP_IDX 13
#define TPM_CAP_SUBCAP_IDX 21

enum tpm_capabilities {
+ TPM_CAP_FLAG = 4,
TPM_CAP_PROP = 5,
};

enum tpm_sub_capabilities {
TPM_CAP_PROP_PCR = 0x1,
TPM_CAP_PROP_MANUFACTURER = 0x3,
+ TPM_CAP_FLAG_PERM = 0x8,
+ TPM_CAP_FLAG_VOL = 0x9,
+ TPM_CAP_PROP_OWNER = 0x11,
+ TPM_CAP_PROP_TIS_TIMEOUT = 0x15,
+ TPM_CAP_PROP_TIS_DURATION = 0x20,
};

/*
@@ -459,6 +472,155 @@ static const u8 tpm_cap[] = {
0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */
};

+void tpm_gen_interrupt(struct tpm_chip *chip)
+{
+ u8 data[30];
+ ssize_t len;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data)))
+ <= TPM_ERROR_SIZE)
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the timeouts\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+}
+EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
+
+void tpm_get_timeouts(struct tpm_chip *chip)
+{
+ u8 data[30];
+ ssize_t len;
+ u32 timeout;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data)))
+ <= TPM_ERROR_SIZE) {
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the timeouts\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ goto duration;
+ }
+
+ if ((len =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))))
+ != 4 * sizeof(u32))
+ goto duration;
+
+ /* Don't overwrite default if value is 0 */
+ timeout =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
+ if (timeout)
+ chip->vendor.timeout_a = timeout;
+ timeout =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
+ if (timeout)
+ chip->vendor.timeout_b = timeout;
+ timeout =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
+ if (timeout)
+ chip->vendor.timeout_c = timeout;
+ timeout =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
+ if (timeout)
+ chip->vendor.timeout_d = timeout;
+
+duration:
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data)))
+ <= TPM_ERROR_SIZE) {
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the durations\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ return;
+ }
+
+ if ((len =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))))
+ != 3 * sizeof(u32))
+ return;
+
+ chip->vendor.duration[TPM_SHORT] =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
+ chip->vendor.duration[TPM_MEDIUM] =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
+ chip->vendor.duration[TPM_LONG] =
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
+}
+EXPORT_SYMBOL_GPL(tpm_get_timeouts);
+
+ssize_t tpm_show_state(struct device * dev, struct device_attribute * attr,
+ char *buf)
+{
+ u8 data[35];
+ ssize_t len;
+ char *str = buf;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_FLAG;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data)))
+ <= TPM_ERROR_SIZE)
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the permanent state\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ else {
+ str +=
+ sprintf(str, "%s\n",
+ (data[TPM_GET_CAP_PERM_DISABLE_IDX] ==
+ 1) ? "Disabled" : "Enabled");
+ str +=
+ sprintf(str, "%s\n",
+ (data[TPM_GET_CAP_PERM_INACTIVE_IDX] ==
+ 1) ? "Inactive" : "Active");
+ }
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data)))
+ <= TPM_ERROR_SIZE)
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the owner state\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ else
+ str +=
+ sprintf(str, "%s\n",
+ (data[TPM_GET_CAP_RET_BOOL_1_IDX] ==
+ 1) ? "Owned" : "Unowned");
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_FLAG;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data)))
+ <= TPM_ERROR_SIZE) {
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the temporary state\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ goto out;
+ }
+
+ if (data[TPM_GET_CAP_TEMP_INACTIVE_IDX] != 0)
+ str += sprintf(str, "Deactivated for this boot\n");
+out:
+ return str - buf;
+}
+EXPORT_SYMBOL_GPL(tpm_show_state);
+
static const u8 pcrread[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 14, /* length */
@@ -590,6 +768,7 @@ out:
EXPORT_SYMBOL_GPL(tpm_show_pubek);

#define CAP_VERSION_1_1 6
+#define CAP_VERSION_1_2 0x1A
#define CAP_VERSION_IDX 13
static const u8 cap_version[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
@@ -651,6 +830,52 @@ out:
}
EXPORT_SYMBOL_GPL(tpm_show_caps);

+ssize_t tpm_show_caps_1_2(struct device * dev,
+ struct device_attribute * attr, char *buf)
+{
+ u8 data[30];
+ ssize_t len;
+ char *str = buf;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, tpm_cap, sizeof(tpm_cap));
+ data[TPM_CAP_IDX] = TPM_CAP_PROP;
+ data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data))) <=
+ TPM_ERROR_SIZE) {
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the manufacturer\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ return 0;
+ }
+
+ str += sprintf(str, "Manufacturer: 0x%x\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))));
+
+ memcpy(data, cap_version, sizeof(cap_version));
+ data[CAP_VERSION_IDX] = CAP_VERSION_1_2;
+
+ if ((len = tpm_transmit(chip, data, sizeof(data))) <=
+ TPM_ERROR_SIZE) {
+ dev_err(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the 1.2 version\n",
+ be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
+ goto out;
+ }
+ str += sprintf(str,
+ "TCG version: %d.%d\nFirmware version: %d.%d\n",
+ (int) data[16], (int) data[17], (int) data[18],
+ (int) data[19]);
+
+out:
+ return str - buf;
+}
+EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
+
ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
--- linux-2.6.16/drivers/char/tpm/tpm.h 2006-03-30 16:58:10.715155750 -0600
+++ linux-2.6.16-rc1-tpm/drivers/char/tpm/tpm.h 2006-03-29 14:16:30.119053500 -0600
@@ -41,8 +41,12 @@ extern ssize_t tpm_show_pcrs(struct devi
char *);
extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
char *);
+extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr,
+ char *);
extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
const char *, size_t);
+extern ssize_t tpm_show_state(struct device *, struct device_attribute *attr,
+ char *);

struct tpm_chip;

@@ -62,6 +68,7 @@ struct tpm_vendor_specific {
u8 (*status) (struct tpm_chip *);
struct miscdevice miscdev;
struct attribute_group *attr_group;
+ u32 timeout_a, timeout_b, timeout_c, timeout_d;
u32 duration[3];
};

@@ -100,6 +114,8 @@ static inline void tpm_write_index(int b
outb(value & 0xFF, base+1);
}

+extern void tpm_get_timeouts(struct tpm_chip *);
+extern void tpm_gen_interrupt(struct tpm_chip *);
extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
extern struct tpm_chip* tpm_register_hardware(struct device *,
const struct tpm_vendor_specific *);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/