Subject: [PATCH] Re: [PATCH] drivers/net: remove network drivers' last few uses of IRQF_SAMPLE_RANDOM

From: Jeff Garzik <[email-masked]>
Date: Thu, 15 May 2008 15:55:38 -0400

Jeff Garzik wrote:
> Someone (hi Jesse?) should implement support for TPM_GetRandom.

Here's an example patch (compile-tested only) to get people started.

This function calls the TPM command, and returns TPM header + RNG data 
in the supplied buffer.

A hw_random driver for TPM still needs to (a) parse the TPM header for 
return code, (b) extract RNG bytes out at offset 14, and (c) figure out 
some way to get a tpm_chip pointer.

Spec at 
https://www.trustedcomputinggroup.org/specs/TPM/TCPA_Main_TCG_Architecture_v1_1b.pdf 
describes TPM_GetRandom on page 215.

	Jeff

diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index a5d8bcb..4c3963b 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -579,6 +579,31 @@ void tpm_continue_selftest(struct tpm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(tpm_continue_selftest);
 
+int tpm_getrandom(struct tpm_chip *chip, void *buf, size_t buflen)
+{
+	u8 rng_cmd[] = {
+		0, 193,			/* TPM_TAG_RQU_COMMAND */
+		0, 0, 0, 14,		/* length */
+		0, 0, 0, 70,		/* TPM_ORD_GetRandom */
+		0, 0, 0, 0,		/* number of bytes to return */
+	};
+	size_t tmp;
+
+	if (buflen <= sizeof(rng_cmd))
+		return -ENOSPC;
+
+	/* patch in requested/returned byte count.  TODO: more than 8-bit */
+	tmp = buflen - sizeof(rng_cmd);
+	if (tmp > 255)
+		tmp = 255;
+	rng_cmd[13] = tmp;
+
+	memcpy(buf, rng_cmd, sizeof(rng_cmd));
+
+	return tpm_transmit(chip, buf, buflen);
+}
+EXPORT_SYMBOL_GPL(tpm_getrandom);
+
 ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
 			char *buf)
 {
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e885148..bbab3c8 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -127,6 +127,7 @@ static inline void tpm_write_index(int base, int index, int value)
 extern void tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern void tpm_continue_selftest(struct tpm_chip *);
+extern int tpm_getrandom(struct tpm_chip *, void *, size_t);
 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 *);