tpmrm 的全称是tpm resource manager。这样的tpm设备会带一个spaces,详细的解释如下:https://lwn.net/Articles/716259/
This patch set adds support for TPM spaces that provide an isolated
execution context for transient objects and HMAC and policy sessions. A
space is swapped into TPM volatile memory only when it is used and
swapped out after the use.
从下面的代码中可以看到tpmrm 对应的字符设备是tpmrm,而普通的tpm设备对应的tpm
tools/testing/selftests/tpm2/tpm2.py
class Client:
FLAG_DEBUG = 0x01
FLAG_SPACE = 0x02
FLAG_NONBLOCK = 0x04
TPM_IOC_NEW_SPACE = 0xa200
def __init__(self, flags = 0):
self.flags = flags
if (self.flags & Client.FLAG_SPACE) == 0:
self.tpm = open('/dev/tpm0', 'r+b', buffering=0)
else:
self.tpm = open('/dev/tpmrm0', 'r+b', buffering=0)
在申请tpm_chip 的函数中,可以看到一个自带space的tpm设备也可以被当作是不带tpm的设备
struct tpm_chip *tpm_chip_alloc(struct device *pdev,
const struct tpm_class_ops *ops)
{
if (chip->flags & TPM_CHIP_FLAG_TPM2)
get_device(&chip->dev);
if (chip->dev_num == 0)
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
else
chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
chip->devs.devt =
MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num);
if (rc)
goto out;
rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
if (rc)
goto out;
if (!pdev)
chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
#可以看到tpmrm和tpm 对应的是否设备fops是不同的,一个tpm_chip中同时包含这两部分设备
cdev_init(&chip->cdev, &tpm_fops);
cdev_init(&chip->cdevs, &tpmrm_fops);
}
我们看看space 初始化主要是申请内存
int tpm2_init_space(struct tpm_space *space)
{
space->context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!space->context_buf)
return -ENOMEM;
space->session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (space->session_buf == NULL) {
kfree(space->context_buf);
return -ENOMEM;
}
return 0;
}
在看看如何load 一个context
static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
unsigned int *offset, u32 *handle)
{
struct tpm_buf tbuf;
struct tpm2_context *ctx;
unsigned int body_size;
int rc;
#初始化命令给tpm 芯片,执行cotext load 命令
rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
if (rc)
return rc;
ctx = (struct tpm2_context *)&buf[*offset];
body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
tpm_buf_append(&tbuf, &buf[*offset], body_size);
#发送命令
rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
rc == TPM2_RC_REFERENCE_H0) {
/*
* TPM_RC_HANDLE means that the session context can't
* be loaded because of an internal counter mismatch
* that makes the TPM think there might have been a
* replay. This might happen if the context was saved
* and loaded outside the space.
*
* TPM_RC_REFERENCE_H0 means the session has been
* flushed outside the space
*/
*handle = 0;
tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (rc > 0) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
tpm_buf_destroy(&tbuf);
return -EFAULT;
}
#最终返回一个u32的值,从这里看到看到context 可以有多个
*handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
*offset += body_size;
tpm_buf_destroy(&tbuf);
return 0;
}
#从下面可以看到context 会有多个.
static int tpm2_load_space(struct tpm_chip *chip)
{
struct tpm_space *space = &chip->work_space;
unsigned int offset;
int i;
int rc;
for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
if (!space->context_tbl[i])
continue;
/* sanity check, should never happen */
if (~space->context_tbl[i]) {
dev_err(&chip->dev, "context table is inconsistent");
return -EFAULT;
}
rc = tpm2_load_context(chip, space->context_buf, &offset,
&space->context_tbl[i]);
if (rc)
return rc;
}
}