* [PATCH v1 1/5] char: tpm: Make implementation of read16 read32 write32 optional
2019-11-10 16:21 [PATCH v1 0/5] add tpm i2c ptp driver amirmizi6
@ 2019-11-10 16:21 ` amirmizi6
2019-11-10 16:21 ` [PATCH v1 2/5] char: tpm: Add check_data handle to tpm_tis_phy_ops in order to check data integrity amirmizi6
` (3 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: amirmizi6 @ 2019-11-10 16:21 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, mark.rutland, peterhuewe, jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, ayna, Dan.Morav, oren.tanami,
shmulik.hagar, amir.mizinski, Amir Mizinski
From: Amir Mizinski <amirmizi6@gmail.com>
Only tpm_tis has a faster way to access multiple bytes at once, every other
driver will just fall back to read_bytes/write_bytes. Therefore, move this
common code out of tpm_tis_spi into tpm_tis_core, so that it is
automatically used when low-level drivers do not implement the specialized
methods.
this commit is based on previous work by Alexander Steffen
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm_tis_core.h | 38 +++++++++++++++++++++++++++++++++++---
drivers/char/tpm/tpm_tis_spi.c | 41 -----------------------------------------
2 files changed, 35 insertions(+), 44 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index 7337819..d06c65b 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -122,13 +122,35 @@ static inline int tpm_tis_read8(struct tpm_tis_data *data, u32 addr, u8 *result)
static inline int tpm_tis_read16(struct tpm_tis_data *data, u32 addr,
u16 *result)
{
- return data->phy_ops->read16(data, addr, result);
+ __le16 result_le;
+ int rc;
+
+ if (data->phy_ops->read16)
+ return data->phy_ops->read16(data, addr, result);
+
+ rc = data->phy_ops->read_bytes(data, addr, sizeof(u16),
+ (u8 *)&result_le);
+ if (!rc)
+ *result = le16_to_cpu(result_le);
+
+ return rc;
}
static inline int tpm_tis_read32(struct tpm_tis_data *data, u32 addr,
u32 *result)
{
- return data->phy_ops->read32(data, addr, result);
+ __le32 result_le;
+ int rc;
+
+ if (data->phy_ops->read32)
+ return data->phy_ops->read32(data, addr, result);
+
+ rc = data->phy_ops->read_bytes(data, addr, sizeof(u32),
+ (u8 *)&result_le);
+ if (!rc)
+ *result = le32_to_cpu(result_le);
+
+ return rc;
}
static inline int tpm_tis_write_bytes(struct tpm_tis_data *data, u32 addr,
@@ -145,7 +167,17 @@ static inline int tpm_tis_write8(struct tpm_tis_data *data, u32 addr, u8 value)
static inline int tpm_tis_write32(struct tpm_tis_data *data, u32 addr,
u32 value)
{
- return data->phy_ops->write32(data, addr, value);
+ __le32 value_le;
+ int rc;
+
+ if (data->phy_ops->write32)
+ return data->phy_ops->write32(data, addr, value);
+
+ value_le = cpu_to_le32(value);
+ rc = data->phy_ops->write_bytes(data, addr, sizeof(u32),
+ (u8 *)&value_le);
+
+ return rc;
}
static inline bool is_bsw(void)
diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c
index 19513e6..da82924 100644
--- a/drivers/char/tpm/tpm_tis_spi.c
+++ b/drivers/char/tpm/tpm_tis_spi.c
@@ -146,50 +146,9 @@ static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr,
return tpm_tis_spi_transfer(data, addr, len, NULL, value);
}
-static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
-{
- __le16 result_le;
- int rc;
-
- rc = data->phy_ops->read_bytes(data, addr, sizeof(u16),
- (u8 *)&result_le);
- if (!rc)
- *result = le16_to_cpu(result_le);
-
- return rc;
-}
-
-static int tpm_tis_spi_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
-{
- __le32 result_le;
- int rc;
-
- rc = data->phy_ops->read_bytes(data, addr, sizeof(u32),
- (u8 *)&result_le);
- if (!rc)
- *result = le32_to_cpu(result_le);
-
- return rc;
-}
-
-static int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value)
-{
- __le32 value_le;
- int rc;
-
- value_le = cpu_to_le32(value);
- rc = data->phy_ops->write_bytes(data, addr, sizeof(u32),
- (u8 *)&value_le);
-
- return rc;
-}
-
static const struct tpm_tis_phy_ops tpm_spi_phy_ops = {
.read_bytes = tpm_tis_spi_read_bytes,
.write_bytes = tpm_tis_spi_write_bytes,
- .read16 = tpm_tis_spi_read16,
- .read32 = tpm_tis_spi_read32,
- .write32 = tpm_tis_spi_write32,
};
static int tpm_tis_spi_probe(struct spi_device *dev)
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v1 2/5] char: tpm: Add check_data handle to tpm_tis_phy_ops in order to check data integrity
2019-11-10 16:21 [PATCH v1 0/5] add tpm i2c ptp driver amirmizi6
2019-11-10 16:21 ` [PATCH v1 1/5] char: tpm: Make implementation of read16 read32 write32 optional amirmizi6
@ 2019-11-10 16:21 ` amirmizi6
2019-11-12 20:22 ` Jarkko Sakkinen
2019-11-10 16:21 ` [PATCH v1 3/5] char: tpm: rewrite "tpm_tis_req_canceled()" amirmizi6
` (2 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: amirmizi6 @ 2019-11-10 16:21 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, mark.rutland, peterhuewe, jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, ayna, Dan.Morav, oren.tanami,
shmulik.hagar, amir.mizinski, Amir Mizinski
From: Amir Mizinski <amirmizi6@gmail.com>
The current principles:
- When sending command:
1. Host writes TPM_STS.commandReady
2. Host writes command
3. Host checks TPM received data correctly
4. if not go to step 1
- When receiving data:
1. Host check TPM_STS.dataAvail is set
2. Host get data
3. Host check received data are correct.
4. if not Host write TPM_STS.responseRetry and go to step 1.
this commit is based on previous work by Christophe Richard
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm_tis_core.c | 97 +++++++++++++++++++++++++----------------
drivers/char/tpm/tpm_tis_core.h | 3 ++
2 files changed, 62 insertions(+), 38 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index c3181ea..ce7f8a1 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -242,6 +242,15 @@ static u8 tpm_tis_status(struct tpm_chip *chip)
return status;
}
+static bool tpm_tis_check_data(struct tpm_chip *chip, const u8 *buf, size_t len)
+{
+ struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+
+ if (priv->phy_ops->check_data)
+ return priv->phy_ops->check_data(priv, buf, len);
+ return true;
+}
+
static void tpm_tis_ready(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
@@ -308,47 +317,55 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int size = 0;
- int status;
+ int status, i;
u32 expected;
+ bool check_data = false;
- if (count < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ for (i = 0; i < TPM_RETRY && !check_data; i++) {
+ if (count < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
- size = recv_data(chip, buf, TPM_HEADER_SIZE);
- /* read first 10 bytes, including tag, paramsize, and result */
- if (size < TPM_HEADER_SIZE) {
- dev_err(&chip->dev, "Unable to read header\n");
- goto out;
- }
+ size = recv_data(chip, buf, TPM_HEADER_SIZE);
+ /* read first 10 bytes, including tag, paramsize, and result */
+ if (size < TPM_HEADER_SIZE) {
+ dev_err(&chip->dev, "Unable to read header\n");
+ goto out;
+ }
- expected = be32_to_cpu(*(__be32 *) (buf + 2));
- if (expected > count || expected < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ expected = be32_to_cpu(*(__be32 *) (buf + 2));
+ if (expected > count || expected < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
- size += recv_data(chip, &buf[TPM_HEADER_SIZE],
- expected - TPM_HEADER_SIZE);
- if (size < expected) {
- dev_err(&chip->dev, "Unable to read remainder of result\n");
- size = -ETIME;
- goto out;
- }
+ size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE);
+ if (size < expected) {
+ dev_err(&chip->dev, "Unable to read remainder of result\n");
+ size = -ETIME;
+ goto out;
+ }
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
- size = -ETIME;
- goto out;
- }
- status = tpm_tis_status(chip);
- if (status & TPM_STS_DATA_AVAIL) { /* retry? */
- dev_err(&chip->dev, "Error left over data\n");
- size = -EIO;
- goto out;
- }
+ if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
+ &priv->int_queue, false) < 0) {
+ size = -ETIME;
+ goto out;
+ }
+
+ status = tpm_tis_status(chip);
+ if (status & TPM_STS_DATA_AVAIL) { /* retry? */
+ dev_err(&chip->dev, "Error left over data\n");
+ size = -EIO;
+ goto out;
+ }
+ check_data = tpm_tis_check_data(chip, buf, size);
+ if (!check_data)
+ tpm_tis_write8(priv, TPM_STS(priv->locality),
+ TPM_STS_RESPONSE_RETRY);
+ }
out:
tpm_tis_ready(chip);
return size;
@@ -453,13 +470,17 @@ static void disable_interrupts(struct tpm_chip *chip)
static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
- int rc;
+ int rc, i;
u32 ordinal;
unsigned long dur;
+ bool data_valid = false;
- rc = tpm_tis_send_data(chip, buf, len);
- if (rc < 0)
- return rc;
+ for (i = 0; i < TPM_RETRY && !data_valid; i++) {
+ rc = tpm_tis_send_data(chip, buf, len);
+ if (rc < 0)
+ return rc;
+ data_valid = tpm_tis_check_data(chip, buf, len);
+ }
/* go and do it */
rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO);
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index d06c65b..486c2e9 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -34,6 +34,7 @@ enum tis_status {
TPM_STS_GO = 0x20,
TPM_STS_DATA_AVAIL = 0x10,
TPM_STS_DATA_EXPECT = 0x08,
+ TPM_STS_RESPONSE_RETRY = 0x02,
};
enum tis_int_flags {
@@ -106,6 +107,8 @@ struct tpm_tis_phy_ops {
int (*read16)(struct tpm_tis_data *data, u32 addr, u16 *result);
int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result);
int (*write32)(struct tpm_tis_data *data, u32 addr, u32 src);
+ bool (*check_data)(struct tpm_tis_data *data, const u8 *buf,
+ size_t len);
};
static inline int tpm_tis_read_bytes(struct tpm_tis_data *data, u32 addr,
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v1 2/5] char: tpm: Add check_data handle to tpm_tis_phy_ops in order to check data integrity
2019-11-10 16:21 ` [PATCH v1 2/5] char: tpm: Add check_data handle to tpm_tis_phy_ops in order to check data integrity amirmizi6
@ 2019-11-12 20:22 ` Jarkko Sakkinen
0 siblings, 0 replies; 12+ messages in thread
From: Jarkko Sakkinen @ 2019-11-12 20:22 UTC (permalink / raw)
To: amirmizi6
Cc: Eyal.Cohen, oshrialkoby85, alexander.steffen, robh+dt,
mark.rutland, peterhuewe, jgg, arnd, gregkh, devicetree,
linux-kernel, linux-integrity, oshri.alkoby, tmaimon77, gcwilson,
kgoldman, ayna, Dan.Morav, oren.tanami, shmulik.hagar,
amir.mizinski
On Sun, Nov 10, 2019 at 06:21:34PM +0200, amirmizi6@gmail.com wrote:
> From: Amir Mizinski <amirmizi6@gmail.com>
>
> The current principles:
> - When sending command:
> 1. Host writes TPM_STS.commandReady
> 2. Host writes command
> 3. Host checks TPM received data correctly
> 4. if not go to step 1
You are probably talking about steps, right?
Please check the grammar and punctation e.g. "The current steps are
roughly done when sending a command".
> - When receiving data:
> 1. Host check TPM_STS.dataAvail is set
> 2. Host get data
> 3. Host check received data are correct.
> 4. if not Host write TPM_STS.responseRetry and go to step 1.
>
> this commit is based on previous work by Christophe Richard
Sentences in English start with a capital letter and end with a full
stop.
This is completely lacking the description what the commit does.
/Jarkko
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v1 3/5] char: tpm: rewrite "tpm_tis_req_canceled()"
2019-11-10 16:21 [PATCH v1 0/5] add tpm i2c ptp driver amirmizi6
2019-11-10 16:21 ` [PATCH v1 1/5] char: tpm: Make implementation of read16 read32 write32 optional amirmizi6
2019-11-10 16:21 ` [PATCH v1 2/5] char: tpm: Add check_data handle to tpm_tis_phy_ops in order to check data integrity amirmizi6
@ 2019-11-10 16:21 ` amirmizi6
2019-11-10 18:00 ` Jerry Snitselaar
2019-11-10 16:21 ` [PATCH v1 4/5] dt-bindings: tpm: Add the TPM TIS I2C device tree binding documentaion amirmizi6
2019-11-10 16:21 ` [PATCH v1 5/5] char: tpm: add tpm_tis_i2c driver amirmizi6
4 siblings, 1 reply; 12+ messages in thread
From: amirmizi6 @ 2019-11-10 16:21 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, mark.rutland, peterhuewe, jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, ayna, Dan.Morav, oren.tanami,
shmulik.hagar, amir.mizinski, Amir Mizinski
From: Amir Mizinski <amirmizi6@gmail.com>
using this function while read/write data resulted in aborted operation.
after investigating according to TCG TPM Profile (PTP) Specifications,
i found cancel should happen only if TPM_STS.commandReady bit is lit
and couldn't find a case when the current condition is valid.
also only cmdReady bit need to be compared instead of the full lower status register byte.
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm_tis_core.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index ce7f8a1..9016f06 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -627,17 +627,7 @@ static int probe_itpm(struct tpm_chip *chip)
static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
{
- struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
-
- switch (priv->manufacturer_id) {
- case TPM_VID_WINBOND:
- return ((status == TPM_STS_VALID) ||
- (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
- case TPM_VID_STM:
- return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
- default:
- return (status == TPM_STS_COMMAND_READY);
- }
+ return ((status & TPM_STS_COMMAND_READY) == TPM_STS_COMMAND_READY);
}
static irqreturn_t tis_int_handler(int dummy, void *dev_id)
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v1 3/5] char: tpm: rewrite "tpm_tis_req_canceled()"
2019-11-10 16:21 ` [PATCH v1 3/5] char: tpm: rewrite "tpm_tis_req_canceled()" amirmizi6
@ 2019-11-10 18:00 ` Jerry Snitselaar
2019-11-12 1:25 ` Stefan Berger
0 siblings, 1 reply; 12+ messages in thread
From: Jerry Snitselaar @ 2019-11-10 18:00 UTC (permalink / raw)
To: amirmizi6, Stefan Berger
Cc: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, mark.rutland, peterhuewe, jgg, arnd, gregkh, devicetree,
linux-kernel, linux-integrity, oshri.alkoby, tmaimon77, gcwilson,
kgoldman, ayna, Dan.Morav, oren.tanami, shmulik.hagar,
amir.mizinski
On Sun Nov 10 19, amirmizi6@gmail.com wrote:
>From: Amir Mizinski <amirmizi6@gmail.com>
>
>using this function while read/write data resulted in aborted operation.
>after investigating according to TCG TPM Profile (PTP) Specifications,
>i found cancel should happen only if TPM_STS.commandReady bit is lit
>and couldn't find a case when the current condition is valid.
>also only cmdReady bit need to be compared instead of the full lower status register byte.
>
>Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
>---
> drivers/char/tpm/tpm_tis_core.c | 12 +-----------
> 1 file changed, 1 insertion(+), 11 deletions(-)
>
>diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
>index ce7f8a1..9016f06 100644
>--- a/drivers/char/tpm/tpm_tis_core.c
>+++ b/drivers/char/tpm/tpm_tis_core.c
>@@ -627,17 +627,7 @@ static int probe_itpm(struct tpm_chip *chip)
>
> static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
> {
>- struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
>-
>- switch (priv->manufacturer_id) {
>- case TPM_VID_WINBOND:
>- return ((status == TPM_STS_VALID) ||
>- (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
>- case TPM_VID_STM:
>- return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
Stefan were these cases you found that were deviating from the spec? Wondering
if dropping these will cause issues for these devices.
>- default:
>- return (status == TPM_STS_COMMAND_READY);
>- }
>+ return ((status & TPM_STS_COMMAND_READY) == TPM_STS_COMMAND_READY);
> }
>
> static irqreturn_t tis_int_handler(int dummy, void *dev_id)
>--
>2.7.4
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 3/5] char: tpm: rewrite "tpm_tis_req_canceled()"
2019-11-10 18:00 ` Jerry Snitselaar
@ 2019-11-12 1:25 ` Stefan Berger
0 siblings, 0 replies; 12+ messages in thread
From: Stefan Berger @ 2019-11-12 1:25 UTC (permalink / raw)
To: amirmizi6, Stefan Berger, Eyal.Cohen, jarkko.sakkinen,
oshrialkoby85, alexander.steffen, robh+dt, mark.rutland,
peterhuewe, jgg, arnd, gregkh, devicetree, linux-kernel,
linux-integrity, oshri.alkoby, tmaimon77, gcwilson, kgoldman,
ayna, Dan.Morav, oren.tanami, shmulik.hagar, amir.mizinski
On 11/10/19 1:00 PM, Jerry Snitselaar wrote:
> On Sun Nov 10 19, amirmizi6@gmail.com wrote:
>> From: Amir Mizinski <amirmizi6@gmail.com>
>>
>> using this function while read/write data resulted in aborted operation.
>> after investigating according to TCG TPM Profile (PTP) Specifications,
>> i found cancel should happen only if TPM_STS.commandReady bit is lit
>> and couldn't find a case when the current condition is valid.
>> also only cmdReady bit need to be compared instead of the full lower
>> status register byte.
>>
>> Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
>> ---
>> drivers/char/tpm/tpm_tis_core.c | 12 +-----------
>> 1 file changed, 1 insertion(+), 11 deletions(-)
>>
>> diff --git a/drivers/char/tpm/tpm_tis_core.c
>> b/drivers/char/tpm/tpm_tis_core.c
>> index ce7f8a1..9016f06 100644
>> --- a/drivers/char/tpm/tpm_tis_core.c
>> +++ b/drivers/char/tpm/tpm_tis_core.c
>> @@ -627,17 +627,7 @@ static int probe_itpm(struct tpm_chip *chip)
>>
>> static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
>> {
>> - struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
>> -
>> - switch (priv->manufacturer_id) {
>> - case TPM_VID_WINBOND:
>> - return ((status == TPM_STS_VALID) ||
>> - (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
>> - case TPM_VID_STM:
>> - return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
>
> Stefan were these cases you found that were deviating from the spec?
> Wondering
> if dropping these will cause issues for these devices.
I believe these devices needed special handling of the status register
as they didn't behave as the 'other' devices, so I would expect issues.
Stefan
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v1 4/5] dt-bindings: tpm: Add the TPM TIS I2C device tree binding documentaion
2019-11-10 16:21 [PATCH v1 0/5] add tpm i2c ptp driver amirmizi6
` (2 preceding siblings ...)
2019-11-10 16:21 ` [PATCH v1 3/5] char: tpm: rewrite "tpm_tis_req_canceled()" amirmizi6
@ 2019-11-10 16:21 ` amirmizi6
2019-11-14 19:10 ` Rob Herring
2019-11-10 16:21 ` [PATCH v1 5/5] char: tpm: add tpm_tis_i2c driver amirmizi6
4 siblings, 1 reply; 12+ messages in thread
From: amirmizi6 @ 2019-11-10 16:21 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, mark.rutland, peterhuewe, jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, ayna, Dan.Morav, oren.tanami,
shmulik.hagar, amir.mizinski, Amir Mizinski
From: Amir Mizinski <amirmizi6@gmail.com>
this file aim at documenting TPM TIS I2C related dt-bindings for the I2C PTP based Physical TPM.
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
.../bindings/security/tpm/tpm_tis_i2c.txt | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
diff --git a/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt b/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
new file mode 100644
index 0000000..7d5a69e
--- /dev/null
+++ b/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
@@ -0,0 +1,24 @@
+* Device Tree Bindings for I2C PTP based Trusted Platform Module(TPM)
+
+The TCG defines hardware protocol, registers and interface (based
+on the TPM Interface Specification) for accessing TPM devices
+implemented with an I2C interface.
+
+Refer to the 'I2C Interface Definition' section in 'TCG PC Client
+PlatformTPMProfile(PTP) Specification' publication for specification.
+
+Required properties:
+
+- compatible : Should be "tcg,tpm_tis-i2c"
+- reg : Address on the bus
+- tpm-pirq : Input gpio pin, used for host interrupts
+
+Example (for Raspberry Pie 3 Board with Nuvoton's NPCT75X (2.0)
+-------------------------------------------------------------------
+
+tpm_tis-i2c: tpm_tis-i2c@2e {
+
+ compatible = "tcg,tpm_tis-i2c";
+ reg = <0x2e>;
+ tpm-pirq = <&gpio 24 GPIO_ACTIVE_HIGH>;
+};
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v1 4/5] dt-bindings: tpm: Add the TPM TIS I2C device tree binding documentaion
2019-11-10 16:21 ` [PATCH v1 4/5] dt-bindings: tpm: Add the TPM TIS I2C device tree binding documentaion amirmizi6
@ 2019-11-14 19:10 ` Rob Herring
2019-11-24 18:02 ` Amir Mizinski
0 siblings, 1 reply; 12+ messages in thread
From: Rob Herring @ 2019-11-14 19:10 UTC (permalink / raw)
To: amirmizi6
Cc: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
mark.rutland, peterhuewe, jgg, arnd, gregkh, devicetree,
linux-kernel, linux-integrity, oshri.alkoby, tmaimon77, gcwilson,
kgoldman, ayna, Dan.Morav, oren.tanami, shmulik.hagar,
amir.mizinski
On Sun, Nov 10, 2019 at 06:21:36PM +0200, amirmizi6@gmail.com wrote:
> From: Amir Mizinski <amirmizi6@gmail.com>
>
> this file aim at documenting TPM TIS I2C related dt-bindings for the I2C PTP based Physical TPM.
>
> Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
> ---
> .../bindings/security/tpm/tpm_tis_i2c.txt | 24 ++++++++++++++++++++++
> 1 file changed, 24 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
Please make this a schema. See
Documentation/devicetree/writing-schema.rst.
>
> diff --git a/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt b/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
> new file mode 100644
> index 0000000..7d5a69e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
> @@ -0,0 +1,24 @@
> +* Device Tree Bindings for I2C PTP based Trusted Platform Module(TPM)
> +
> +The TCG defines hardware protocol, registers and interface (based
> +on the TPM Interface Specification) for accessing TPM devices
> +implemented with an I2C interface.
> +
> +Refer to the 'I2C Interface Definition' section in 'TCG PC Client
> +PlatformTPMProfile(PTP) Specification' publication for specification.
> +
> +Required properties:
> +
> +- compatible : Should be "tcg,tpm_tis-i2c"
s/_/-/
As this has to be under an I2C controller node, the '-i2c' part is
redundant.
There's a bigger issue that the h/w here is more than just an I2C
protocol. The chip may have multiple power supplies, clocks, reset
lines, etc. HID over I2C seems like a similar case. Does the spec define
*all* of that? If not, you need chip specific compatibles. You can keep
this as a fallback though.
> +- reg : Address on the bus
> +- tpm-pirq : Input gpio pin, used for host interrupts
GPIO connections are properties ending in '-gpios'. However, if the only
use is an interrupt, then you should use 'interrupts'.
> +
> +Example (for Raspberry Pie 3 Board with Nuvoton's NPCT75X (2.0)
> +-------------------------------------------------------------------
> +
> +tpm_tis-i2c: tpm_tis-i2c@2e {
> +
> + compatible = "tcg,tpm_tis-i2c";
> + reg = <0x2e>;
> + tpm-pirq = <&gpio 24 GPIO_ACTIVE_HIGH>;
> +};
> --
> 2.7.4
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 4/5] dt-bindings: tpm: Add the TPM TIS I2C device tree binding documentaion
2019-11-14 19:10 ` Rob Herring
@ 2019-11-24 18:02 ` Amir Mizinski
0 siblings, 0 replies; 12+ messages in thread
From: Amir Mizinski @ 2019-11-24 18:02 UTC (permalink / raw)
To: Rob Herring
Cc: Eyal.Cohen, Jarkko Sakkinen, Oshri Alkobi, Alexander Steffen,
Mark Rutland, peterhuewe, jgg, Arnd Bergmann, Greg KH,
devicetree, Linux Kernel Mailing List, linux-integrity,
IS20 Oshri Alkoby, Tomer Maimon, gcwilson, kgoldman, ayna,
IS30 Dan Morav, oren.tanami, shmulik.hager, amir.mizinski
On Thu, Nov 14, 2019 at 9:10 PM Rob Herring <robh@kernel.org> wrote:
>
> On Sun, Nov 10, 2019 at 06:21:36PM +0200, amirmizi6@gmail.com wrote:
> > From: Amir Mizinski <amirmizi6@gmail.com>
> >
> > this file aim at documenting TPM TIS I2C related dt-bindings for the I2C PTP based Physical TPM.
> >
> > Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
> > ---
> > .../bindings/security/tpm/tpm_tis_i2c.txt | 24 ++++++++++++++++++++++
> > 1 file changed, 24 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
>
> Please make this a schema. See
> Documentation/devicetree/writing-schema.rst.
>
> >
> > diff --git a/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt b/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
> > new file mode 100644
> > index 0000000..7d5a69e
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/security/tpm/tpm_tis_i2c.txt
> > @@ -0,0 +1,24 @@
> > +* Device Tree Bindings for I2C PTP based Trusted Platform Module(TPM)
> > +
> > +The TCG defines hardware protocol, registers and interface (based
> > +on the TPM Interface Specification) for accessing TPM devices
> > +implemented with an I2C interface.
> > +
> > +Refer to the 'I2C Interface Definition' section in 'TCG PC Client
> > +PlatformTPMProfile(PTP) Specification' publication for specification.
> > +
> > +Required properties:
> > +
> > +- compatible : Should be "tcg,tpm_tis-i2c"
>
> s/_/-/
>
> As this has to be under an I2C controller node, the '-i2c' part is
> redundant.
>
I wrote this Respectively with the tpm_tis-spi driver.
https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/security/tpm/tpm_tis_spi.txt
Should i change it anyway or keep the format?
Also the '-i2c' is added since its not the only protocol used over
tis, and it is handled differently from spi.
> There's a bigger issue that the h/w here is more than just an I2C
> protocol. The chip may have multiple power supplies, clocks, reset
> lines, etc. HID over I2C seems like a similar case. Does the spec define
> *all* of that? If not, you need chip specific compatibles. You can keep
> this as a fallback though.
>
> > +- reg : Address on the bus
> > +- tpm-pirq : Input gpio pin, used for host interrupts
>
> GPIO connections are properties ending in '-gpios'. However, if the only
> use is an interrupt, then you should use 'interrupts'.
>
My mistake, i didn't implemented interrupts yet so ill clear this for
now. thank you.
> > +
> > +Example (for Raspberry Pie 3 Board with Nuvoton's NPCT75X (2.0)
> > +-------------------------------------------------------------------
> > +
> > +tpm_tis-i2c: tpm_tis-i2c@2e {
> > +
> > + compatible = "tcg,tpm_tis-i2c";
> > + reg = <0x2e>;
> > + tpm-pirq = <&gpio 24 GPIO_ACTIVE_HIGH>;
> > +};
> > --
> > 2.7.4
> >
Apologies for the late response, had a personal issue that needed my attention
I'm working on making this a schema for next version. This is new for
me, if you have additional sources regarding how to write it, i'll
appreciate if you send me.
Thank you.
Amir Mizinski
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v1 5/5] char: tpm: add tpm_tis_i2c driver
2019-11-10 16:21 [PATCH v1 0/5] add tpm i2c ptp driver amirmizi6
` (3 preceding siblings ...)
2019-11-10 16:21 ` [PATCH v1 4/5] dt-bindings: tpm: Add the TPM TIS I2C device tree binding documentaion amirmizi6
@ 2019-11-10 16:21 ` amirmizi6
4 siblings, 0 replies; 12+ messages in thread
From: amirmizi6 @ 2019-11-10 16:21 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, mark.rutland, peterhuewe, jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, ayna, Dan.Morav, oren.tanami,
shmulik.hagar, amir.mizinski, Amir Mizinski
From: Amir Mizinski <amirmizi6@gmail.com>
Implements the functionality needed to communicate with an I2C TPM
according to the TCG TPM I2C Interface Specification.
Limitations:
* No IRQ support
* No support for updating GUARD_TIME
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/Kconfig | 12 ++
drivers/char/tpm/Makefile | 1 +
drivers/char/tpm/tpm_tis_i2c.c | 272 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 285 insertions(+)
create mode 100644 drivers/char/tpm/tpm_tis_i2c.c
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 88a3c06..b731a80 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -67,6 +67,18 @@ config TCG_TIS_SPI
within Linux. To compile this driver as a module, choose M here;
the module will be called tpm_tis_spi.
+config TCG_TIS_I2C
+ tristate "TPM I2C Interface Specification"
+ depends on I2C
+ depends on CRC_CCITT
+ select TCG_TIS_CORE
+ ---help---
+ If you have a TPM security chip which is connected to a regular
+ I2C master (i.e. most embedded platforms) that is compliant with the
+ TCG TPM I2C Interface Specification say Yes and it will be accessible from
+ within Linux. To compile this driver as a module, choose M here;
+ the module will be called tpm_tis_i2c.
+
config TCG_TIS_I2C_ATMEL
tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)"
depends on I2C
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index a01c4ca..15a0010 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -22,6 +22,7 @@ tpm-$(CONFIG_OF) += eventlog/of.o
obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
obj-$(CONFIG_TCG_TIS) += tpm_tis.o
obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
+obj-$(CONFIG_TCG_TIS_I2C) += tpm_tis_i2c.o
obj-$(CONFIG_TCG_TIS_I2C_ATMEL) += tpm_i2c_atmel.o
obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
obj-$(CONFIG_TCG_TIS_I2C_NUVOTON) += tpm_i2c_nuvoton.o
diff --git a/drivers/char/tpm/tpm_tis_i2c.c b/drivers/char/tpm/tpm_tis_i2c.c
new file mode 100644
index 0000000..080e82e
--- /dev/null
+++ b/drivers/char/tpm/tpm_tis_i2c.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2014-2019 Nuvoton Technology corporation
+ *
+ * TPM TIS I2C
+ *
+ * TPM TIS I2C Device Driver Interface for devices that implement the TPM I2C
+ * Interface defined by TCG PC Client Platform TPM Profile (PTP) Specification
+ * Revision 01.03 v22 at www.trustedcomputinggroup.org
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/acpi.h>
+#include <linux/freezer.h>
+#include <linux/crc-ccitt.h>
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/tpm.h>
+#include "tpm.h"
+#include "tpm_tis_core.h"
+
+#define TPM_LOC_SEL 0x04
+#define TPM_I2C_INTERFACE_CAPABILITY 0x30
+#define TPM_I2C_DEVICE_ADDRESS 0x38
+#define TPM_DATA_CSUM_ENABLE 0x40
+#define TPM_DATA_CSUM 0x44
+#define TPM_I2C_DID_VID 0x48
+#define TPM_I2C_RID 0x4C
+
+struct tpm_tis_i2c_phy {
+ struct tpm_tis_data priv;
+ struct i2c_client *i2c_client;
+ bool data_csum;
+ u8 *iobuf;
+};
+
+static inline struct tpm_tis_i2c_phy *to_tpm_tis_i2c_phy(struct tpm_tis_data *data)
+{
+ return container_of(data, struct tpm_tis_i2c_phy, priv);
+}
+
+static u8 address_to_register(u32 addr)
+{
+ addr &= 0xFFF;
+
+ switch (addr) {
+ // adapt register addresses that have changed compared to
+ // older TIS versions
+ case TPM_ACCESS(0):
+ return 0x04;
+ case TPM_LOC_SEL:
+ return 0x00;
+ case TPM_DID_VID(0):
+ return 0x48;
+ case TPM_RID(0):
+ return 0x4C;
+ default:
+ return addr;
+ }
+}
+
+static int tpm_tis_i2c_read_bytes(struct tpm_tis_data *data, u32 addr,
+ u16 len, u8 *result)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ int ret;
+ u8 reg = address_to_register(addr);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = sizeof(reg),
+ .buf = ®,
+ },
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len,
+ .buf = result,
+ .flags = I2C_M_RD,
+ },
+ };
+
+ ret = i2c_transfer(phy->i2c_client->adapter, msgs, ARRAY_SIZE(msgs));
+
+ if (ret < 0)
+ return ret;
+
+ usleep_range(250, 300); // wait default GUARD_TIME of 250µs
+
+ return 0;
+}
+
+static int tpm_tis_i2c_write_bytes(struct tpm_tis_data *data, u32 addr,
+ u16 len, const u8 *value)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ int ret;
+
+ if (phy->iobuf) {
+ if (len > TPM_BUFSIZE - 1)
+ return -EIO;
+
+ phy->iobuf[0] = address_to_register(addr);
+ memcpy(phy->iobuf + 1, value, len);
+
+ {
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len + 1,
+ .buf = phy->iobuf,
+ },
+ };
+
+ ret = i2c_transfer(phy->i2c_client->adapter, msgs,
+ ARRAY_SIZE(msgs));
+ }
+ } else {
+ u8 reg = address_to_register(addr);
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = sizeof(reg),
+ .buf = ®,
+ },
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len,
+ .buf = (u8 *)value,
+ .flags = I2C_M_NOSTART,
+ },
+ };
+
+ ret = i2c_transfer(phy->i2c_client->adapter, msgs,
+ ARRAY_SIZE(msgs));
+ }
+
+ if (ret < 0)
+ return ret;
+
+ usleep_range(250, 300); // wait default GUARD_TIME of 250µs
+
+ return 0;
+}
+
+static bool tpm_tis_i2c_check_data(struct tpm_tis_data *data,
+ const u8 *buf, size_t len)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ u16 crc, crc_tpm;
+ int rc;
+
+ if (phy->data_csum) {
+ crc = crc_ccitt(0x0000, buf, len);
+ rc = tpm_tis_read16(data, TPM_DATA_CSUM, &crc_tpm);
+ if (rc < 0)
+ return false;
+
+ crc_tpm = be16_to_cpu(crc_tpm);
+ return crc == crc_tpm;
+ }
+
+ return true;
+}
+
+static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
+
+static int csum_state_store(struct tpm_tis_data *data, u8 new_state)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ u8 cur_state;
+ int rc;
+
+ rc = tpm_tis_i2c_write_bytes(&phy->priv, TPM_DATA_CSUM_ENABLE,
+ 1, &new_state);
+ if (rc < 0)
+ return rc;
+
+ rc = tpm_tis_i2c_read_bytes(&phy->priv, TPM_DATA_CSUM_ENABLE,
+ 1, &cur_state);
+ if (rc < 0)
+ return rc;
+
+ if (new_state == cur_state)
+ phy->data_csum = (bool)new_state;
+
+ return rc;
+}
+
+static const struct tpm_tis_phy_ops tpm_i2c_phy_ops = {
+ .read_bytes = tpm_tis_i2c_read_bytes,
+ .write_bytes = tpm_tis_i2c_write_bytes,
+ .check_data = tpm_tis_i2c_check_data,
+};
+
+static int tpm_tis_i2c_probe(struct i2c_client *dev,
+ const struct i2c_device_id *id)
+{
+ struct tpm_tis_i2c_phy *phy;
+ int rc;
+ const u8 loc_init = 0;
+
+ phy = devm_kzalloc(&dev->dev, sizeof(struct tpm_tis_i2c_phy),
+ GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->i2c_client = dev;
+
+ if (!i2c_check_functionality(dev->adapter, I2C_FUNC_NOSTART)) {
+ phy->iobuf = devm_kmalloc(&dev->dev, TPM_BUFSIZE, GFP_KERNEL);
+ if (!phy->iobuf)
+ return -ENOMEM;
+ }
+
+ // select locality 0 (the driver will access only via locality 0)
+ rc = tpm_tis_i2c_write_bytes(&phy->priv, TPM_LOC_SEL, 1, &loc_init);
+ if (rc < 0)
+ return rc;
+
+ // enables the data checksum calculation
+ rc = csum_state_store(&phy->priv, 0x01);
+ if (rc < 0)
+ return rc;
+
+ return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_i2c_phy_ops,
+ NULL);
+}
+
+static const struct i2c_device_id tpm_tis_i2c_id[] = {
+ {"tpm_tis_i2c", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_id);
+
+static const struct of_device_id of_tis_i2c_match[] = {
+ { .compatible = "tcg,tpm_tis-i2c", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_tis_i2c_match);
+
+static const struct acpi_device_id acpi_tis_i2c_match[] = {
+ {"SMO0768", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, acpi_tis_i2c_match);
+
+static struct i2c_driver tpm_tis_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tpm_tis_i2c",
+ .pm = &tpm_tis_pm,
+ .of_match_table = of_match_ptr(of_tis_i2c_match),
+ .acpi_match_table = ACPI_PTR(acpi_tis_i2c_match),
+ },
+ .probe = tpm_tis_i2c_probe,
+ .id_table = tpm_tis_i2c_id,
+};
+
+module_i2c_driver(tpm_tis_i2c_driver);
+
+MODULE_DESCRIPTION("TPM Driver for native I2C access");
+MODULE_LICENSE("GPL");
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v1 2/5] char: tpm: Add check_data handle to tpm_tis_phy_ops in order to check data integrity
2019-12-02 13:01 [PATCH v1 0/5] add tpm i2c ptp driver amirmizi6
@ 2019-12-02 13:01 ` amirmizi6
0 siblings, 0 replies; 12+ messages in thread
From: amirmizi6 @ 2019-12-02 13:01 UTC (permalink / raw)
To: Eyal.Cohen, jarkko.sakkinen, oshrialkoby85, alexander.steffen,
robh+dt, mark.rutland, peterhuewe, jgg, arnd, gregkh
Cc: devicetree, linux-kernel, linux-integrity, oshri.alkoby,
tmaimon77, gcwilson, kgoldman, ayna, Dan.Morav, oren.tanami,
shmulik.hager, amir.mizinski, Amir Mizinski
From: Amir Mizinski <amirmizi6@gmail.com>
The current principles:
- When sending command:
1. Host writes TPM_STS.commandReady
2. Host writes command
3. Host checks TPM received data correctly
4. if not go to step 1
- When receiving data:
1. Host check TPM_STS.dataAvail is set
2. Host get data
3. Host check received data are correct.
4. if not Host write TPM_STS.responseRetry and go to step 1.
this commit is based on previous work by Christophe Richard
Signed-off-by: Amir Mizinski <amirmizi6@gmail.com>
---
drivers/char/tpm/tpm_tis_core.c | 97 +++++++++++++++++++++++++----------------
drivers/char/tpm/tpm_tis_core.h | 3 ++
2 files changed, 62 insertions(+), 38 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index c3181ea..ce7f8a1 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -242,6 +242,15 @@ static u8 tpm_tis_status(struct tpm_chip *chip)
return status;
}
+static bool tpm_tis_check_data(struct tpm_chip *chip, const u8 *buf, size_t len)
+{
+ struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+
+ if (priv->phy_ops->check_data)
+ return priv->phy_ops->check_data(priv, buf, len);
+ return true;
+}
+
static void tpm_tis_ready(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
@@ -308,47 +317,55 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int size = 0;
- int status;
+ int status, i;
u32 expected;
+ bool check_data = false;
- if (count < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ for (i = 0; i < TPM_RETRY && !check_data; i++) {
+ if (count < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
- size = recv_data(chip, buf, TPM_HEADER_SIZE);
- /* read first 10 bytes, including tag, paramsize, and result */
- if (size < TPM_HEADER_SIZE) {
- dev_err(&chip->dev, "Unable to read header\n");
- goto out;
- }
+ size = recv_data(chip, buf, TPM_HEADER_SIZE);
+ /* read first 10 bytes, including tag, paramsize, and result */
+ if (size < TPM_HEADER_SIZE) {
+ dev_err(&chip->dev, "Unable to read header\n");
+ goto out;
+ }
- expected = be32_to_cpu(*(__be32 *) (buf + 2));
- if (expected > count || expected < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ expected = be32_to_cpu(*(__be32 *) (buf + 2));
+ if (expected > count || expected < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
- size += recv_data(chip, &buf[TPM_HEADER_SIZE],
- expected - TPM_HEADER_SIZE);
- if (size < expected) {
- dev_err(&chip->dev, "Unable to read remainder of result\n");
- size = -ETIME;
- goto out;
- }
+ size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE);
+ if (size < expected) {
+ dev_err(&chip->dev, "Unable to read remainder of result\n");
+ size = -ETIME;
+ goto out;
+ }
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
- size = -ETIME;
- goto out;
- }
- status = tpm_tis_status(chip);
- if (status & TPM_STS_DATA_AVAIL) { /* retry? */
- dev_err(&chip->dev, "Error left over data\n");
- size = -EIO;
- goto out;
- }
+ if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
+ &priv->int_queue, false) < 0) {
+ size = -ETIME;
+ goto out;
+ }
+
+ status = tpm_tis_status(chip);
+ if (status & TPM_STS_DATA_AVAIL) { /* retry? */
+ dev_err(&chip->dev, "Error left over data\n");
+ size = -EIO;
+ goto out;
+ }
+ check_data = tpm_tis_check_data(chip, buf, size);
+ if (!check_data)
+ tpm_tis_write8(priv, TPM_STS(priv->locality),
+ TPM_STS_RESPONSE_RETRY);
+ }
out:
tpm_tis_ready(chip);
return size;
@@ -453,13 +470,17 @@ static void disable_interrupts(struct tpm_chip *chip)
static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
- int rc;
+ int rc, i;
u32 ordinal;
unsigned long dur;
+ bool data_valid = false;
- rc = tpm_tis_send_data(chip, buf, len);
- if (rc < 0)
- return rc;
+ for (i = 0; i < TPM_RETRY && !data_valid; i++) {
+ rc = tpm_tis_send_data(chip, buf, len);
+ if (rc < 0)
+ return rc;
+ data_valid = tpm_tis_check_data(chip, buf, len);
+ }
/* go and do it */
rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO);
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index d06c65b..486c2e9 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -34,6 +34,7 @@ enum tis_status {
TPM_STS_GO = 0x20,
TPM_STS_DATA_AVAIL = 0x10,
TPM_STS_DATA_EXPECT = 0x08,
+ TPM_STS_RESPONSE_RETRY = 0x02,
};
enum tis_int_flags {
@@ -106,6 +107,8 @@ struct tpm_tis_phy_ops {
int (*read16)(struct tpm_tis_data *data, u32 addr, u16 *result);
int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result);
int (*write32)(struct tpm_tis_data *data, u32 addr, u32 src);
+ bool (*check_data)(struct tpm_tis_data *data, const u8 *buf,
+ size_t len);
};
static inline int tpm_tis_read_bytes(struct tpm_tis_data *data, u32 addr,
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread