TPM: sysfs functions consolidation

According to Dave Hansen's comments on the tpm_show_*, some of these functions
present a pattern when allocating data[] memory space and also when setting its
content. A new function was created so that this pattern could be consolidated.
Also, replaced the data[] command vectors and its indexes by meaningful structures
as pointed out by Matt Helsley too.

Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
Rajiv Andrade 2009-02-02 15:23:43 -02:00 committed by James Morris
parent faa3aad75a
commit 0883743825
2 changed files with 269 additions and 272 deletions

View File

@ -429,134 +429,148 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
#define TPM_DIGEST_SIZE 20 #define TPM_DIGEST_SIZE 20
#define TPM_ERROR_SIZE 10 #define TPM_ERROR_SIZE 10
#define TPM_RET_CODE_IDX 6 #define TPM_RET_CODE_IDX 6
#define TPM_GET_CAP_RET_SIZE_IDX 10
#define TPM_GET_CAP_RET_UINT32_1_IDX 14
#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 { enum tpm_capabilities {
TPM_CAP_FLAG = 4, TPM_CAP_FLAG = cpu_to_be32(4),
TPM_CAP_PROP = 5, TPM_CAP_PROP = cpu_to_be32(5),
CAP_VERSION_1_1 = cpu_to_be32(0x06),
CAP_VERSION_1_2 = cpu_to_be32(0x1A)
}; };
enum tpm_sub_capabilities { enum tpm_sub_capabilities {
TPM_CAP_PROP_PCR = 0x1, TPM_CAP_PROP_PCR = cpu_to_be32(0x101),
TPM_CAP_PROP_MANUFACTURER = 0x3, TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103),
TPM_CAP_FLAG_PERM = 0x8, TPM_CAP_FLAG_PERM = cpu_to_be32(0x108),
TPM_CAP_FLAG_VOL = 0x9, TPM_CAP_FLAG_VOL = cpu_to_be32(0x109),
TPM_CAP_PROP_OWNER = 0x11, TPM_CAP_PROP_OWNER = cpu_to_be32(0x111),
TPM_CAP_PROP_TIS_TIMEOUT = 0x15, TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115),
TPM_CAP_PROP_TIS_DURATION = 0x20, TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120),
}; };
/* static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
* This is a semi generic GetCapability command for use int len, const char *desc)
* with the capability type TPM_CAP_PROP or TPM_CAP_FLAG
* and their associated sub_capabilities.
*/
static const u8 tpm_cap[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 22, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
0, 0, 0, 0, /* TPM_CAP_<TYPE> */
0, 0, 0, 4, /* TPM_CAP_SUB_<TYPE> size */
0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */
};
static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len,
char *desc)
{ {
int err; int err;
len = tpm_transmit(chip, data, len); len = tpm_transmit(chip,(u8 *) cmd, len);
if (len < 0) if (len < 0)
return len; return len;
if (len == TPM_ERROR_SIZE) { if (len == TPM_ERROR_SIZE) {
err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); err = be32_to_cpu(cmd->header.out.return_code);
dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
return err; return err;
} }
return 0; return 0;
} }
#define TPM_INTERNAL_RESULT_SIZE 200
#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
#define TPM_ORD_GET_CAP cpu_to_be32(101)
static const struct tpm_input_header tpm_getcap_header = {
.tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(22),
.ordinal = TPM_ORD_GET_CAP
};
ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
const char *desc)
{
struct tpm_cmd_t tpm_cmd;
int rc;
struct tpm_chip *chip = dev_get_drvdata(dev);
tpm_cmd.header.in = tpm_getcap_header;
if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
tpm_cmd.params.getcap_in.cap = subcap_id;
/*subcap field not necessary */
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32));
} else {
if (subcap_id == TPM_CAP_FLAG_PERM ||
subcap_id == TPM_CAP_FLAG_VOL)
tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
else
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = subcap_id;
}
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
if (!rc)
*cap = tpm_cmd.params.getcap_out.cap;
return rc;
}
void tpm_gen_interrupt(struct tpm_chip *chip) void tpm_gen_interrupt(struct tpm_chip *chip)
{ {
u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; struct tpm_cmd_t tpm_cmd;
ssize_t rc; ssize_t rc;
memcpy(data, tpm_cap, sizeof(tpm_cap)); tpm_cmd.header.in = tpm_getcap_header;
data[TPM_CAP_IDX] = TPM_CAP_PROP; tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
rc = transmit_cmd(chip, data, sizeof(data), rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the timeouts"); "attempting to determine the timeouts");
} }
EXPORT_SYMBOL_GPL(tpm_gen_interrupt); EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
void tpm_get_timeouts(struct tpm_chip *chip) void tpm_get_timeouts(struct tpm_chip *chip)
{ {
u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; struct tpm_cmd_t tpm_cmd;
struct timeout_t *timeout_cap;
struct duration_t *duration_cap;
ssize_t rc; ssize_t rc;
u32 timeout; u32 timeout;
memcpy(data, tpm_cap, sizeof(tpm_cap)); tpm_cmd.header.in = tpm_getcap_header;
data[TPM_CAP_IDX] = TPM_CAP_PROP; tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
rc = transmit_cmd(chip, data, sizeof(data), rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the timeouts"); "attempting to determine the timeouts");
if (rc) if (rc)
goto duration; goto duration;
if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) if (be32_to_cpu(tpm_cmd.header.out.length)
!= 4 * sizeof(u32)) != 4 * sizeof(u32))
goto duration; goto duration;
timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
/* Don't overwrite default if value is 0 */ /* Don't overwrite default if value is 0 */
timeout = timeout = be32_to_cpu(timeout_cap->a);
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
if (timeout) if (timeout)
chip->vendor.timeout_a = usecs_to_jiffies(timeout); chip->vendor.timeout_a = usecs_to_jiffies(timeout);
timeout = timeout = be32_to_cpu(timeout_cap->b);
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
if (timeout) if (timeout)
chip->vendor.timeout_b = usecs_to_jiffies(timeout); chip->vendor.timeout_b = usecs_to_jiffies(timeout);
timeout = timeout = be32_to_cpu(timeout_cap->c);
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
if (timeout) if (timeout)
chip->vendor.timeout_c = usecs_to_jiffies(timeout); chip->vendor.timeout_c = usecs_to_jiffies(timeout);
timeout = timeout = be32_to_cpu(timeout_cap->d);
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
if (timeout) if (timeout)
chip->vendor.timeout_d = usecs_to_jiffies(timeout); chip->vendor.timeout_d = usecs_to_jiffies(timeout);
duration: duration:
memcpy(data, tpm_cap, sizeof(tpm_cap)); tpm_cmd.header.in = tpm_getcap_header;
data[TPM_CAP_IDX] = TPM_CAP_PROP; tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
rc = transmit_cmd(chip, data, sizeof(data), rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the durations"); "attempting to determine the durations");
if (rc) if (rc)
return; return;
if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) if (be32_to_cpu(tpm_cmd.header.out.return_code)
!= 3 * sizeof(u32)) != 3 * sizeof(u32))
return; return;
duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
chip->vendor.duration[TPM_SHORT] = chip->vendor.duration[TPM_SHORT] =
usecs_to_jiffies(be32_to_cpu usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
(*((__be32 *) (data +
TPM_GET_CAP_RET_UINT32_1_IDX))));
/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
* value wrong and apparently reports msecs rather than usecs. So we * value wrong and apparently reports msecs rather than usecs. So we
* fix up the resulting too-small TPM_SHORT value to make things work. * fix up the resulting too-small TPM_SHORT value to make things work.
@ -565,13 +579,9 @@ void tpm_get_timeouts(struct tpm_chip *chip)
chip->vendor.duration[TPM_SHORT] = HZ; chip->vendor.duration[TPM_SHORT] = HZ;
chip->vendor.duration[TPM_MEDIUM] = chip->vendor.duration[TPM_MEDIUM] =
usecs_to_jiffies(be32_to_cpu usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
(*((__be32 *) (data +
TPM_GET_CAP_RET_UINT32_2_IDX))));
chip->vendor.duration[TPM_LONG] = chip->vendor.duration[TPM_LONG] =
usecs_to_jiffies(be32_to_cpu usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
(*((__be32 *) (data +
TPM_GET_CAP_RET_UINT32_3_IDX))));
} }
EXPORT_SYMBOL_GPL(tpm_get_timeouts); EXPORT_SYMBOL_GPL(tpm_get_timeouts);
@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip)
} }
EXPORT_SYMBOL_GPL(tpm_continue_selftest); EXPORT_SYMBOL_GPL(tpm_continue_selftest);
#define TPM_INTERNAL_RESULT_SIZE 200
ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
char *buf) char *buf)
{ {
u8 *data; cap_t cap;
ssize_t rc; ssize_t rc;
struct tpm_chip *chip = dev_get_drvdata(dev); rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
if (chip == NULL) "attempting to determine the permanent enabled state");
return -ENODEV; if (rc)
data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
if (!data)
return -ENOMEM;
memcpy(data, tpm_cap, sizeof(tpm_cap));
data[TPM_CAP_IDX] = TPM_CAP_FLAG;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
"attemtping to determine the permanent enabled state");
if (rc) {
kfree(data);
return 0; return 0;
}
rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
kfree(data);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(tpm_show_enabled); EXPORT_SYMBOL_GPL(tpm_show_enabled);
@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled);
ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
char *buf) char *buf)
{ {
u8 *data; cap_t cap;
ssize_t rc; ssize_t rc;
struct tpm_chip *chip = dev_get_drvdata(dev); rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
if (chip == NULL) "attempting to determine the permanent active state");
return -ENODEV; if (rc)
data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
if (!data)
return -ENOMEM;
memcpy(data, tpm_cap, sizeof(tpm_cap));
data[TPM_CAP_IDX] = TPM_CAP_FLAG;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
"attemtping to determine the permanent active state");
if (rc) {
kfree(data);
return 0; return 0;
}
rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
kfree(data);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(tpm_show_active); EXPORT_SYMBOL_GPL(tpm_show_active);
@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active);
ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
char *buf) char *buf)
{ {
u8 *data; cap_t cap;
ssize_t rc; ssize_t rc;
struct tpm_chip *chip = dev_get_drvdata(dev); rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
if (chip == NULL)
return -ENODEV;
data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
if (!data)
return -ENOMEM;
memcpy(data, tpm_cap, sizeof(tpm_cap));
data[TPM_CAP_IDX] = TPM_CAP_PROP;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;
rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the owner state"); "attempting to determine the owner state");
if (rc) { if (rc)
kfree(data);
return 0; return 0;
}
rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); rc = sprintf(buf, "%d\n", cap.owned);
kfree(data);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(tpm_show_owned); EXPORT_SYMBOL_GPL(tpm_show_owned);
@ -688,31 +648,15 @@ EXPORT_SYMBOL_GPL(tpm_show_owned);
ssize_t tpm_show_temp_deactivated(struct device * dev, ssize_t tpm_show_temp_deactivated(struct device * dev,
struct device_attribute * attr, char *buf) struct device_attribute * attr, char *buf)
{ {
u8 *data; cap_t cap;
ssize_t rc; ssize_t rc;
struct tpm_chip *chip = dev_get_drvdata(dev); rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
if (chip == NULL)
return -ENODEV;
data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
if (!data)
return -ENOMEM;
memcpy(data, tpm_cap, sizeof(tpm_cap));
data[TPM_CAP_IDX] = TPM_CAP_FLAG;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the temporary state"); "attempting to determine the temporary state");
if (rc) { if (rc)
kfree(data);
return 0; return 0;
}
rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
kfree(data);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
@ -727,77 +671,64 @@ static const u8 pcrread[] = {
ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
cap_t cap;
u8 *data; u8 *data;
ssize_t rc; ssize_t rc;
int i, j, num_pcrs; int i, j, num_pcrs;
__be32 index; __be32 index;
char *str = buf; char *str = buf;
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip == NULL)
return -ENODEV;
data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
memcpy(data, tpm_cap, sizeof(tpm_cap)); rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
data[TPM_CAP_IDX] = TPM_CAP_PROP;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR;
rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the number of PCRS"); "attempting to determine the number of PCRS");
if (rc) { if (rc)
kfree(data);
return 0; return 0;
}
num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); num_pcrs = be32_to_cpu(cap.num_pcrs);
for (i = 0; i < num_pcrs; i++) { for (i = 0; i < num_pcrs; i++) {
memcpy(data, pcrread, sizeof(pcrread)); memcpy(data, pcrread, sizeof(pcrread));
index = cpu_to_be32(i); index = cpu_to_be32(i);
memcpy(data + 10, &index, 4); memcpy(data + 10, &index, 4);
rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, rc = transmit_cmd(chip, (struct tpm_cmd_t *)data,
TPM_INTERNAL_RESULT_SIZE,
"attempting to read a PCR"); "attempting to read a PCR");
if (rc) if (rc)
goto out; break;
str += sprintf(str, "PCR-%02d: ", i); str += sprintf(str, "PCR-%02d: ", i);
for (j = 0; j < TPM_DIGEST_SIZE; j++) for (j = 0; j < TPM_DIGEST_SIZE; j++)
str += sprintf(str, "%02X ", *(data + 10 + j)); str += sprintf(str, "%02X ", *(data + 10 + j));
str += sprintf(str, "\n"); str += sprintf(str, "\n");
} }
out:
kfree(data); kfree(data);
return str - buf; return str - buf;
} }
EXPORT_SYMBOL_GPL(tpm_show_pcrs); EXPORT_SYMBOL_GPL(tpm_show_pcrs);
#define READ_PUBEK_RESULT_SIZE 314 #define READ_PUBEK_RESULT_SIZE 314
static const u8 readpubek[] = { #define TPM_ORD_READPUBEK cpu_to_be32(124)
0, 193, /* TPM_TAG_RQU_COMMAND */ struct tpm_input_header tpm_readpubek_header = {
0, 0, 0, 30, /* length */ .tag = TPM_TAG_RQU_COMMAND,
0, 0, 0, 124, /* TPM_ORD_ReadPubek */ .length = cpu_to_be32(30),
.ordinal = TPM_ORD_READPUBEK
}; };
ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
u8 *data; u8 *data;
struct tpm_cmd_t tpm_cmd;
ssize_t err; ssize_t err;
int i, rc; int i, rc;
char *str = buf; char *str = buf;
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip == NULL)
return -ENODEV;
data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); tpm_cmd.header.in = tpm_readpubek_header;
if (!data) err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
return -ENOMEM;
memcpy(data, readpubek, sizeof(readpubek));
err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE,
"attempting to read the PUBEK"); "attempting to read the PUBEK");
if (err) if (err)
goto out; goto out;
@ -812,7 +743,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
256 byte modulus 256 byte modulus
ignore checksum 20 bytes ignore checksum 20 bytes
*/ */
data = tpm_cmd.params.readpubek_out_buffer;
str += str +=
sprintf(str, sprintf(str,
"Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
@ -832,65 +763,33 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
} }
out: out:
rc = str - buf; rc = str - buf;
kfree(data);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(tpm_show_pubek); 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 */
0, 0, 0, 18, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
0, 0, 0, 0,
0, 0, 0, 0
};
ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
u8 *data; cap_t cap;
ssize_t rc; ssize_t rc;
char *str = buf; char *str = buf;
struct tpm_chip *chip = dev_get_drvdata(dev); rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
if (chip == NULL)
return -ENODEV;
data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
if (!data)
return -ENOMEM;
memcpy(data, tpm_cap, sizeof(tpm_cap));
data[TPM_CAP_IDX] = TPM_CAP_PROP;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the manufacturer"); "attempting to determine the manufacturer");
if (rc) { if (rc)
kfree(data);
return 0; return 0;
}
str += sprintf(str, "Manufacturer: 0x%x\n", str += sprintf(str, "Manufacturer: 0x%x\n",
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); be32_to_cpu(cap.manufacturer_id));
memcpy(data, cap_version, sizeof(cap_version)); rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
data[CAP_VERSION_IDX] = CAP_VERSION_1_1;
rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the 1.1 version"); "attempting to determine the 1.1 version");
if (rc) if (rc)
goto out; return 0;
str += sprintf(str, str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n", "TCG version: %d.%d\nFirmware version: %d.%d\n",
(int) data[14], (int) data[15], (int) data[16], cap.tpm_version.Major, cap.tpm_version.Minor,
(int) data[17]); cap.tpm_version.revMajor, cap.tpm_version.revMinor);
out:
kfree(data);
return str - buf; return str - buf;
} }
EXPORT_SYMBOL_GPL(tpm_show_caps); EXPORT_SYMBOL_GPL(tpm_show_caps);
@ -898,51 +797,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps);
ssize_t tpm_show_caps_1_2(struct device * dev, ssize_t tpm_show_caps_1_2(struct device * dev,
struct device_attribute * attr, char *buf) struct device_attribute * attr, char *buf)
{ {
u8 *data; cap_t cap;
ssize_t len; ssize_t rc;
char *str = buf; char *str = buf;
struct tpm_chip *chip = dev_get_drvdata(dev); rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
if (chip == NULL) "attempting to determine the manufacturer");
return -ENODEV; if (rc)
data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
if (!data)
return -ENOMEM;
memcpy(data, tpm_cap, sizeof(tpm_cap));
data[TPM_CAP_IDX] = TPM_CAP_PROP;
data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
if (len <= 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))));
kfree(data);
return 0; return 0;
}
str += sprintf(str, "Manufacturer: 0x%x\n", str += sprintf(str, "Manufacturer: 0x%x\n",
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); be32_to_cpu(cap.manufacturer_id));
rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
memcpy(data, cap_version, sizeof(cap_version)); "attempting to determine the 1.2 version");
data[CAP_VERSION_IDX] = CAP_VERSION_1_2; if (rc)
return 0;
len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
if (len <= 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, str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n", "TCG version: %d.%d\nFirmware version: %d.%d\n",
(int) data[16], (int) data[17], (int) data[18], cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor,
(int) data[19]); cap.tpm_version_1_2.revMajor,
cap.tpm_version_1_2.revMinor);
out:
kfree(data);
return str - buf; return str - buf;
} }
EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);

View File

@ -123,6 +123,130 @@ static inline void tpm_write_index(int base, int index, int value)
outb(index, base); outb(index, base);
outb(value & 0xFF, base+1); outb(value & 0xFF, base+1);
} }
struct tpm_input_header {
__be16 tag;
__be32 length;
__be32 ordinal;
}__attribute__((packed));
struct tpm_output_header {
__be16 tag;
__be32 length;
__be32 return_code;
}__attribute__((packed));
struct stclear_flags_t {
__be16 tag;
u8 deactivated;
u8 disableForceClear;
u8 physicalPresence;
u8 physicalPresenceLock;
u8 bGlobalLock;
}__attribute__((packed));
struct tpm_version_t {
u8 Major;
u8 Minor;
u8 revMajor;
u8 revMinor;
}__attribute__((packed));
struct tpm_version_1_2_t {
__be16 tag;
u8 Major;
u8 Minor;
u8 revMajor;
u8 revMinor;
}__attribute__((packed));
struct timeout_t {
__be32 a;
__be32 b;
__be32 c;
__be32 d;
}__attribute__((packed));
struct duration_t {
__be32 tpm_short;
__be32 tpm_medium;
__be32 tpm_long;
}__attribute__((packed));
struct permanent_flags_t {
__be16 tag;
u8 disable;
u8 ownership;
u8 deactivated;
u8 readPubek;
u8 disableOwnerClear;
u8 allowMaintenance;
u8 physicalPresenceLifetimeLock;
u8 physicalPresenceHWEnable;
u8 physicalPresenceCMDEnable;
u8 CEKPUsed;
u8 TPMpost;
u8 TPMpostLock;
u8 FIPS;
u8 operator;
u8 enableRevokeEK;
u8 nvLocked;
u8 readSRKPub;
u8 tpmEstablished;
u8 maintenanceDone;
u8 disableFullDALogicInfo;
}__attribute__((packed));
typedef union {
struct permanent_flags_t perm_flags;
struct stclear_flags_t stclear_flags;
bool owned;
__be32 num_pcrs;
struct tpm_version_t tpm_version;
struct tpm_version_1_2_t tpm_version_1_2;
__be32 manufacturer_id;
struct timeout_t timeout;
struct duration_t duration;
} cap_t;
struct tpm_getcap_params_in {
__be32 cap;
__be32 subcap_size;
__be32 subcap;
}__attribute__((packed));
struct tpm_getcap_params_out {
__be32 cap_size;
cap_t cap;
}__attribute__((packed));
struct tpm_readpubek_params_out {
u8 algorithm[4];
u8 encscheme[2];
u8 sigscheme[2];
u8 parameters[12]; /*assuming RSA*/
__be32 keysize;
u8 modulus[256];
u8 checksum[20];
}__attribute__((packed));
typedef union {
struct tpm_input_header in;
struct tpm_output_header out;
} tpm_cmd_header;
typedef union {
struct tpm_getcap_params_out getcap_out;
struct tpm_readpubek_params_out readpubek_out;
u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
struct tpm_getcap_params_in getcap_in;
} tpm_cmd_params;
struct tpm_cmd_t {
tpm_cmd_header header;
tpm_cmd_params params;
}__attribute__((packed));
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
extern void tpm_get_timeouts(struct tpm_chip *); extern void tpm_get_timeouts(struct tpm_chip *);
extern void tpm_gen_interrupt(struct tpm_chip *); extern void tpm_gen_interrupt(struct tpm_chip *);