欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

TPM 设备

程序员文章站 2022-06-22 21:22:16
TPM的全称是Trusted Platfrom Module ,其是一个微控制器,可以存储密匙,密码和数字证书TPM 目前看有SPI和I2C 两种接口,其一般嵌入到主板上,主要用于低于外部软件攻击和物理偷窃,保证信息存储的安全,目前有tpm1 和 tpm2 两个标准。其代码的路径在drivers\char\tpm,可以看到tpm 至少是一个字符设备.obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o我们以atmel为例来看看如果写tpm的驱动这是一个独立的模块,其入口....
TPM的全称是Trusted Platfrom Module ,其是一个微控制器,可以存储密匙,密码和数字证书
TPM 目前看有SPI和I2C 两种接口,其一般嵌入到主板上,主要用于低于外部软件攻击和物理偷窃,
保证信息存储的安全,目前有tpm1 和 tpm2 两个标准。
其代码的路径在drivers\char\tpm,可以看到tpm 至少是一个字符设备.
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
我们以atmel为例来看看如果写tpm的驱动
这是一个独立的模块,其入口函数在init_atmel
static int __init init_atmel(void)
{
	int rc = 0;
	void __iomem *iobase = NULL;
	int have_region, region_size;
	unsigned long base;
	struct  tpm_chip *chip;
	struct tpm_atmel_priv *priv;
#常规操作,注册driver.
	rc = platform_driver_register(&atml_drv);
	if (rc)
		return rc;
#拿到io 资源
	if ((iobase = atmel_get_base_addr(&base, &region_size)) == NULL) {
		rc = -ENODEV;
		goto err_unreg_drv;
	}
#判断io资源是否有效
	have_region =
	    (atmel_request_region
	     (base, region_size, "tpm_atmel0") == NULL) ? 0 : 1;
#注册一个device,从这里看ateml这个设备,或者tpm 设备都不需要bios 来传递dsdttable,毕竟是tpm 设备不一定存在.
	pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0);
	if (IS_ERR(pdev)) {
		rc = PTR_ERR(pdev);
		goto err_rel_reg;
	}
#申请社保的私有资源
	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		rc = -ENOMEM;
		goto err_unreg_dev;
	}
#私有资源就是io 相关的资源
	priv->iobase = iobase;
	priv->base = base;
	priv->have_region = have_region;
	priv->region_size = region_size;
#这里是最重要的第一步,区别于一般的驱动,这里要申请一个tpm_chip 资源,其第二个参数对卡的读写的一些操作。
	chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
	if (IS_ERR(chip)) {
		rc = PTR_ERR(chip);
		goto err_unreg_dev;
	}

	dev_set_drvdata(&chip->dev, priv);
#注册一个字符设备,并添加一个sys的文件系统。到这里tpm设备就注册完毕了。
	rc = tpm_chip_register(chip);
	if (rc)
		goto err_unreg_dev;

	return 0;
}
那我们看看一个tpm 设备到底要听那些编程接口呢?
static const struct tpm_class_ops tpm_atmel = {
	.recv = tpm_atml_recv,
	.send = tpm_atml_send,
	.cancel = tpm_atml_cancel,
	.status = tpm_atml_status,
	.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
	.req_complete_val = ATML_STATUS_DATA_AVAIL,
	.req_canceled = tpm_atml_req_canceled,
};
从这里可以看到kernel 为我们提供了一个通用的接口,驱动只要填充tpm_class_ops就可以
根据这个接口,可以自己写一个不依赖硬件的tpm 模拟设备.
我们看看tpm设备具体怎么接受信息
static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
	struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev);
	u8 status, *hdr = buf;
	u32 size;
	int i;
	__be32 *native_size;

	/* start reading header */
	if (count < 6)
		return -EIO;

	for (i = 0; i < 6; i++) {
#可以看到这里主要是直接读tpm的寄存器来读取信息
		status = ioread8(priv->iobase + 1);
		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
			dev_err(&chip->dev, "error reading header\n");
			return -EIO;
		}
		*buf++ = ioread8(priv->iobase);
	}

	/* size of the data received */
	native_size = (__force __be32 *) (hdr + 2);
	size = be32_to_cpu(*native_size);

}

static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
{
	struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev);
	int i;

	dev_dbg(&chip->dev, "tpm_atml_send:\n");
	for (i = 0; i < count; i++) {
		dev_dbg(&chip->dev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
#通过直接写tpm的寄存器来写信息
		iowrite8(buf[i], priv->iobase);
	}

	return 0;
}

 

本文地址:https://blog.csdn.net/tiantao2012/article/details/107457532

相关标签: Linux 源码分析