tpm 的协议分为tpm1和tpm2 这里以tpm2为例
tpm2 支持的命令定义在linux-master\include\linux\tpm.h中
enum tpm2_command_codes {
TPM2_CC_FIRST = 0x011F,
TPM2_CC_HIERARCHY_CONTROL = 0x0121,
TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
TPM2_CC_CREATE_PRIMARY = 0x0131,
TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
TPM2_CC_SELF_TEST = 0x0143,
TPM2_CC_STARTUP = 0x0144,
TPM2_CC_SHUTDOWN = 0x0145,
TPM2_CC_NV_READ = 0x014E,
TPM2_CC_CREATE = 0x0153,
TPM2_CC_LOAD = 0x0157,
TPM2_CC_SEQUENCE_UPDATE = 0x015C,
TPM2_CC_UNSEAL = 0x015E,
TPM2_CC_CONTEXT_LOAD = 0x0161,
TPM2_CC_CONTEXT_SAVE = 0x0162,
TPM2_CC_FLUSH_CONTEXT = 0x0165,
TPM2_CC_VERIFY_SIGNATURE = 0x0177,
TPM2_CC_GET_CAPABILITY = 0x017A,
TPM2_CC_GET_RANDOM = 0x017B,
TPM2_CC_PCR_READ = 0x017E,
TPM2_CC_PCR_EXTEND = 0x0182,
TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
TPM2_CC_HASH_SEQUENCE_START = 0x0186,
TPM2_CC_CREATE_LOADED = 0x0191,
TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
};
这里以TPM2_CC_SELF_TEST为例看看tpm 是如何发送命令的
static int tpm2_do_selftest(struct tpm_chip *chip)
{
struct tpm_buf buf;
int full;
int rc;
for (full = 0; full < 2; full++) {
#初始化命令,发送的命令包含一些head指令的标识
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
if (rc)
return rc;
#这里分别发送tpm1和tpm2的命令
tpm_buf_append_u8(&buf, full);
#发送命令
rc = tpm_transmit_cmd(chip, &buf, 0,
#销毁buff "attempting the self test");
tpm_buf_destroy(&buf);
#检查这个命令的执行后返回的值是否符合预期,可以看到tpm1和tpm2 的返回值是不同的
if (rc == TPM2_RC_TESTING)
rc = TPM2_RC_SUCCESS;
if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS)
return rc;
}
return rc;
}
我们看看发送命令前是如何申请buffer的
static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
#申请一个page
buf->data = (u8 *)__get_free_page(GFP_KERNEL);
if (!buf->data)
return -ENOMEM;
buf->flags = 0;
#对申请到的buff 初始化
tpm_buf_reset(buf, tag, ordinal);
return 0;
}
对buff的初始化如下:
这里可以看到tpm 协议是采用大端存储的
static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
}
最后我们看看如果发送命令给tpm 芯片
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
size_t min_rsp_body_length, const char *desc)
{
const struct tpm_header *header = (struct tpm_header *)buf->data;
int err;
ssize_t len;
#最终的发送命令,后面都是对返回值的判断
len = tpm_transmit(chip, buf->data, PAGE_SIZE);
if (len < 0)
return len;
err = be32_to_cpu(header->return_code);
if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED
&& err != TPM2_RC_TESTING && desc)
dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
desc);
if (err)
return err;
if (len < min_rsp_body_length + TPM_HEADER_SIZE)
return -EFAULT;
return 0;
}
ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz)
{
struct tpm_header *header = (struct tpm_header *)buf;
for (;;) {
#发送命令
ret = tpm_try_transmit(chip, buf, bufsiz);
if (ret < 0)
break;
rc = be32_to_cpu(header->return_code);
if (rc != TPM2_RC_RETRY && rc != TPM2_RC_TESTING)
break;
}
return ret;
}
static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
{
struct tpm_header *header = buf;
int rc;
ssize_t len = 0;
u32 count, ordinal;
unsigned long stop;
if (bufsiz < TPM_HEADER_SIZE)
return -EINVAL;
if (bufsiz > TPM_BUFSIZE)
bufsiz = TPM_BUFSIZE;
count = be32_to_cpu(header->length);
ordinal = be32_to_cpu(header->ordinal);
if (count == 0)
return -ENODATA;
if (count > bufsiz) {
dev_err(&chip->dev,
"invalid count value %x %zx\n", count, bufsiz);
return -E2BIG;
}
#原来最终还是调用tpm chip 提供的发送函数发送命令
rc = chip->ops->send(chip, buf, count);
if (rc < 0) {
if (rc != -EPIPE)
dev_err(&chip->dev,
"%s: send(): error %d\n", __func__, rc);
return rc;
}
}