diff options
Diffstat (limited to 'drivers/char/tpm/tpm.c')
-rw-r--r-- | drivers/char/tpm/tpm.c | 74 |
1 files changed, 64 insertions, 10 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 3af9f4d1a23f..f26afdb1a702 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -30,12 +30,7 @@ #include <linux/freezer.h> #include "tpm.h" - -enum tpm_const { - TPM_MINOR = 224, /* officially assigned */ - TPM_BUFSIZE = 4096, - TPM_NUM_DEVICES = 256, -}; +#include "tpm_eventlog.h" enum tpm_duration { TPM_SHORT = 0, @@ -482,6 +477,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, #define TPM_INTERNAL_RESULT_SIZE 200 #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) #define TPM_ORD_GET_CAP cpu_to_be32(101) +#define TPM_ORD_GET_RANDOM cpu_to_be32(70) static const struct tpm_input_header tpm_getcap_header = { .tag = TPM_TAG_RQU_COMMAND, @@ -919,7 +915,7 @@ EXPORT_SYMBOL_GPL(tpm_show_pcrs); #define READ_PUBEK_RESULT_SIZE 314 #define TPM_ORD_READPUBEK cpu_to_be32(124) -struct tpm_input_header tpm_readpubek_header = { +static struct tpm_input_header tpm_readpubek_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(30), .ordinal = TPM_ORD_READPUBEK @@ -1175,7 +1171,7 @@ int tpm_release(struct inode *inode, struct file *file) flush_work(&chip->work); file->private_data = NULL; atomic_set(&chip->data_pending, 0); - kfree(chip->data_buffer); + kzfree(chip->data_buffer); clear_bit(0, &chip->is_open); put_device(chip->dev); return 0; @@ -1227,7 +1223,6 @@ ssize_t tpm_read(struct file *file, char __user *buf, del_singleshot_timer_sync(&chip->user_read_timer); flush_work(&chip->work); ret_size = atomic_read(&chip->data_pending); - atomic_set(&chip->data_pending, 0); if (ret_size > 0) { /* relay data */ ssize_t orig_ret_size = ret_size; if (size < ret_size) @@ -1242,6 +1237,8 @@ ssize_t tpm_read(struct file *file, char __user *buf, mutex_unlock(&chip->buffer_mutex); } + atomic_set(&chip->data_pending, 0); + return ret_size; } EXPORT_SYMBOL_GPL(tpm_read); @@ -1326,6 +1323,58 @@ int tpm_pm_resume(struct device *dev) } EXPORT_SYMBOL_GPL(tpm_pm_resume); +#define TPM_GETRANDOM_RESULT_SIZE 18 +static struct tpm_input_header tpm_getrandom_header = { + .tag = TPM_TAG_RQU_COMMAND, + .length = cpu_to_be32(14), + .ordinal = TPM_ORD_GET_RANDOM +}; + +/** + * tpm_get_random() - Get random bytes from the tpm's RNG + * @chip_num: A specific chip number for the request or TPM_ANY_NUM + * @out: destination buffer for the random bytes + * @max: the max number of bytes to write to @out + * + * Returns < 0 on error and the number of bytes read on success + */ +int tpm_get_random(u32 chip_num, u8 *out, size_t max) +{ + struct tpm_chip *chip; + struct tpm_cmd_t tpm_cmd; + u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); + int err, total = 0, retries = 5; + u8 *dest = out; + + chip = tpm_chip_find_get(chip_num); + if (chip == NULL) + return -ENODEV; + + if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) + return -EINVAL; + + do { + tpm_cmd.header.in = tpm_getrandom_header; + tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); + + err = transmit_cmd(chip, &tpm_cmd, + TPM_GETRANDOM_RESULT_SIZE + num_bytes, + "attempting get random"); + if (err) + break; + + recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); + memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); + + dest += recd; + total += recd; + num_bytes -= recd; + } while (retries-- && total < max); + + return total ? total : -EIO; +} +EXPORT_SYMBOL_GPL(tpm_get_random); + /* In case vendor provided release function, call it too.*/ void tpm_dev_vendor_release(struct tpm_chip *chip) @@ -1346,7 +1395,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); * Once all references to platform device are down to 0, * release all allocated structures. */ -void tpm_dev_release(struct device *dev) +static void tpm_dev_release(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); @@ -1427,6 +1476,11 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, goto put_device; } + if (sys_add_ppi(&dev->kobj)) { + misc_deregister(&chip->vendor.miscdev); + goto put_device; + } + chip->bios_dir = tpm_bios_log_setup(devname); /* Make chip available */ |