Unverified Commit 6f2b577e authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!10690 [OLK-6.6] Support Trusted computing(TC) feature for hygon CPU

Merge Pull Request from: @chench00 
 
Support Trusted computing(TC) feature for hygon CPU

issue:
https://gitee.com/openeuler/kernel/issues/I9B9XS

This Trusted computing function modules are implemented inside the hygon CPU: 
TPM2.0 module (Trusted Platform Module, international standard);
TCM2.0 module (Trusted Crypto Module, traditional Chinese standard);
TPCM module (Trusted Platform Control Module, emerging Chinese standard);
TDM module (Trusted Dynamic Measuring, private).
The above functional modules can be used to realize the core functions of trusted computing, such as trusted startup, dynamic measurement, trusted storage, trusted reporting, etc.
 
 
Link:https://gitee.com/openeuler/kernel/pulls/10690

 

Reviewed-by: default avatarLiu Chao <liuchao173@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents c191ebe4 21efec08
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -8815,6 +8815,11 @@ CONFIG_CRYPTO_DEV_CCP_DD=m
CONFIG_CRYPTO_DEV_SP_CCP=y
CONFIG_CRYPTO_DEV_CCP_CRYPTO=m
CONFIG_CRYPTO_DEV_SP_PSP=y
CONFIG_HYGON_PSP2CPU_CMD=y
CONFIG_TCG_HYGON=m
CONFIG_TCM_HYGON=m
CONFIG_TDM_DEV_HYGON=y
CONFIG_TDM_KERNEL_GUARD=m
# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set
CONFIG_CRYPTO_DEV_NITROX=m
CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m
+24 −0
Original line number Diff line number Diff line
@@ -210,5 +210,29 @@ config TCG_FTPM_TEE
	help
	  This driver proxies for firmware TPM running in TEE.

config TCG_HYGON
        tristate "Hygon TPM Interface"
        depends on ACPI
        depends on CRYPTO_DEV_CCP_DD
        depends on CRYPTO_DEV_SP_PSP
        default y
        help
          If you want to make Hygon TPM support available, 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_hygon.

config TCM_HYGON
        tristate "Hygon TCM Interface"
        depends on ACPI
        depends on CRYPTO_DEV_CCP_DD
        depends on CRYPTO_DEV_SP_PSP
        default y
        help
          If you want to make Hygon TCM support available, 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
          tcm_hygon.

source "drivers/char/tpm/st33zp24/Kconfig"
endif # TCG_TPM
+2 −0
Original line number Diff line number Diff line
@@ -42,3 +42,5 @@ obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
obj-$(CONFIG_TCG_CRB) += tpm_crb.o
obj-$(CONFIG_TCG_VTPM_PROXY) += tpm_vtpm_proxy.o
obj-$(CONFIG_TCG_FTPM_TEE) += tpm_ftpm_tee.o
obj-$(CONFIG_TCG_HYGON) += tpm_hygon.o
obj-$(CONFIG_TCM_HYGON) += tcm_hygon.o
+243 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * The Hygon TCM2.0 device driver.
 *
 * Copyright (C) 2023 Hygon Info Technologies Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/psp-hygon.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/tpm.h>
#include <linux/security.h>
#include "tpm.h"

#define TCM2PSP_CMD(id)			(0x100 | (id))
#define MAX_TCM_BUF_LEN			4096

struct tcm_hygon_priv {
	u8 priv_buf[MAX_TCM_BUF_LEN];
};

struct tcm_header_t {
	__be16	tag;
	__be32	length;
	union {
		__be32 ordinal;
		__be32 return_code;
	};
} __packed;

static int tcm_c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
	int ret = 0;
	struct tcm_hygon_priv *priv = dev_get_drvdata(&chip->dev);
	struct tcm_header_t *header = (void *)(priv->priv_buf + sizeof(u32) + sizeof(u32));
	u32 len = be32_to_cpu(header->length);

	if (len > count) {
		ret = -E2BIG;
		goto out;
	}

	if (len > 0)
		memmove(buf, (u8 *)header, len);

	ret = len;

out:
	return ret;
}

static int tcm_c_send(struct tpm_chip *chip, u8 *buf, size_t count)
{
	int ret, error;
	struct tcm_hygon_priv *priv = dev_get_drvdata(&chip->dev);
	u32 buf_size = sizeof(priv->priv_buf);
	u32 cmd_size = (u32)count;
	u8 *p = priv->priv_buf;

	if (buf_size - sizeof(u32) - sizeof(u32) < count) {
		ret = -E2BIG;
		goto out;
	}

	*(u32 *)p = cpu_to_be32(buf_size);
	p += sizeof(buf_size);
	*(u32 *)p = cpu_to_be32(cmd_size);
	p += sizeof(cmd_size);
	memmove(p, buf, count);

	ret = psp_do_cmd(TCM2PSP_CMD(0), priv->priv_buf, &error);
	if (ret) {
		pr_err("%s: psp do cmd error, %d\n", __func__, error);
		ret = -EIO;
	}

out:
	return ret;
}

static const struct tpm_class_ops tcm_c_ops = {
	.flags = TPM_OPS_AUTO_STARTUP,
	.recv = tcm_c_recv,
	.send = tcm_c_send,
};

static void tcm_bios_log_teardown(struct tpm_chip *chip)
{
	int i;
	struct inode *inode;

	/* securityfs_remove currently doesn't take care of handling sync
	 * between removal and opening of pseudo files. To handle this, a
	 * workaround is added by making i_private = NULL here during removal
	 * and to check it during open(), both within inode_lock()/unlock().
	 * This design ensures that open() either safely gets kref or fails.
	 */
	for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) {
		if (chip->bios_dir[i]) {
			inode = d_inode(chip->bios_dir[i]);
			inode_lock(inode);
			inode->i_private = NULL;
			inode_unlock(inode);
			securityfs_remove(chip->bios_dir[i]);
		}
	}
}

static void tcm_chip_unregister(struct tpm_chip *chip)
{
	if (IS_ENABLED(CONFIG_HW_RANDOM_TPM))
		hwrng_unregister(&chip->hwrng);
	tcm_bios_log_teardown(chip);
	cdev_del(&chip->cdevs);
	put_device(&chip->devs);
	cdev_device_del(&chip->cdev, &chip->dev);
}

static int hygon_tcm2_acpi_add(struct acpi_device *device)
{
	int ret;
	struct tpm_chip *chip;
	struct tcm_hygon_priv *priv;
	struct device *dev = &device->dev;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		ret = -ENOMEM;
		goto err;
	}

	chip = tpmm_chip_alloc(dev, &tcm_c_ops);
	if (IS_ERR(chip)) {
		pr_err("tcmm_chip_alloc fail\n");
		ret = PTR_ERR(chip);
		goto err;
	}

	ret = dev_set_name(&chip->dev, "tcm%d", chip->dev_num);
	if (ret) {
		pr_err("tcm device set name fail\n");
		goto err;
	}

	dev_set_drvdata(&chip->dev, priv);

	chip->flags |= TPM_CHIP_FLAG_TPM2;
	chip->flags |= TPM_CHIP_FLAG_IRQ;

	ret = tpm_chip_register(chip);
	if (ret) {
		pr_err("tcm chip_register fail\n");
		goto err;
	}

	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
		device_del(&chip->devs);
		ret = dev_set_name(&chip->devs, "tcmrm%d", chip->dev_num);
		if (ret) {
			pr_err("tcmrm device set name fail\n");
			goto err_dev;
		}
		ret = device_add(&chip->devs);
		if (ret) {
			pr_err("devs add fail\n");
			goto err_dev;
		}
	}

	pr_info("Hygon TCM2 detected\n");

	return 0;

err_dev:
	tcm_chip_unregister(chip);

err:
	return ret;
}

static void hygon_tcm2_acpi_remove(struct acpi_device *device)
{
	struct device *dev = &device->dev;
	struct tpm_chip *chip = dev_get_drvdata(dev);

	tpm_chip_unregister(chip);

	pr_info("Hygon TCM2 removed\n");
}

static SIMPLE_DEV_PM_OPS(tcm_hygon_pm, tpm_pm_suspend, tpm_pm_resume);

static const struct acpi_device_id hygon_tcm2_device_ids[] = {
	{"HYGT0201", 0},
	{"", 0},
};

MODULE_DEVICE_TABLE(acpi, hygon_tcm2_device_ids);

static struct acpi_driver hygon_tcm2_acpi_driver = {
	.name = "tcm_hygon",
	.ids = hygon_tcm2_device_ids,
	.ops = {
		.add = hygon_tcm2_acpi_add,
		.remove = hygon_tcm2_acpi_remove,
	},
	.drv = {
		.pm = &tcm_hygon_pm,
	},
};

static int __init hygon_tcm2_init(void)
{
	return acpi_bus_register_driver(&hygon_tcm2_acpi_driver);
}

static void __exit hygon_tcm2_exit(void)
{
	acpi_bus_unregister_driver(&hygon_tcm2_acpi_driver);
}

/*
 * hygon_tcm2_init must be done after ccp module init, but before
 * ima module init. That's why we use a device_initcall_sync which is
 * called after all the device_initcall(includes ccp) but before the
 * late_initcall(includes ima).
 */
device_initcall_sync(hygon_tcm2_init);
module_exit(hygon_tcm2_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("mayuanchen (mayuanchen@hygon.cn)");
MODULE_DESCRIPTION("TCM2 device driver for Hygon PSP");
+186 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * The Hygon TPM2.0 device driver.
 *
 * Copyright (C) 2020 Hygon Info Technologies Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/psp-hygon.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/tpm.h>
#include "tpm.h"

#define TPM2PSP_CMD(id)			(0x100 | (id))
#define MAX_TPM_BUF_LEN			4096
#define MAX_CMD_BUF_LEN			(MAX_TPM_BUF_LEN + sizeof(u32) + sizeof(u32))

struct tpm_hygon_priv {
	u8 priv_buf[MAX_CMD_BUF_LEN];
};

/*
 * tpm header struct name is different in different kernel versions.
 * so redefine it for driver porting.
 */
struct tpm_header_t {
	__be16	tag;
	__be32	length;
	union {
		__be32 ordinal;
		__be32 return_code;
	};
} __packed;

static int tpm_c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
	int ret = 0;
	struct tpm_hygon_priv *priv = dev_get_drvdata(&chip->dev);
	struct tpm_header_t *header = (void *)(priv->priv_buf + sizeof(u32) + sizeof(u32));
	u32 len = be32_to_cpu(header->length);

	if (len > count) {
		ret = -E2BIG;
		goto out;
	}

	if (len > 0)
		memmove(buf, (u8 *)header, len);

	ret = len;

out:
	return ret;
}

static int tpm_c_send(struct tpm_chip *chip, u8 *buf, size_t count)
{
	int ret, error;
	struct tpm_hygon_priv *priv = dev_get_drvdata(&chip->dev);
	u32 buf_size = cpu_to_be32(sizeof(priv->priv_buf));
	u32 cmd_size = cpu_to_be32((u32)count);
	u8 *p = priv->priv_buf;

	*(u32 *)p = buf_size;
	p += sizeof(buf_size);
	*(u32 *)p = cmd_size;
	p += sizeof(cmd_size);
	memmove(p, buf, count);

	ret = psp_do_cmd(TPM2PSP_CMD(0), priv->priv_buf, &error);
	if (ret) {
		pr_err("%s: sev do cmd error, %d\n", __func__, error);
		ret = -EIO;
	}

	return ret;
}

static const struct tpm_class_ops tpm_c_ops = {
	.flags = TPM_OPS_AUTO_STARTUP,
	.recv = tpm_c_recv,
	.send = tpm_c_send,
};

static int hygon_tpm2_acpi_add(struct acpi_device *device)
{
	int ret;
	struct tpm_chip *chip;
	struct tpm_hygon_priv *priv;
	struct device *dev = &device->dev;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		ret = -ENOMEM;
		goto err;
	}

	chip = tpmm_chip_alloc(dev, &tpm_c_ops);
	if (IS_ERR(chip)) {
		pr_err("tpmm_chip_alloc fail\n");
		ret = PTR_ERR(chip);
		goto err;
	}

	dev_set_drvdata(&chip->dev, priv);

	chip->flags |= TPM_CHIP_FLAG_TPM2;
	chip->flags |= TPM_CHIP_FLAG_IRQ;

	ret = tpm_chip_register(chip);
	if (ret) {
		pr_err("tpm_chip_register fail\n");
		goto err;
	}

	pr_info("Hygon TPM2 detected\n");

	return 0;

err:
	return ret;
}

static void hygon_tpm2_acpi_remove(struct acpi_device *device)
{
	struct device *dev = &device->dev;
	struct tpm_chip *chip = dev_get_drvdata(dev);

	tpm_chip_unregister(chip);

	pr_info("Hygon TPM2 removed\n");
}

static SIMPLE_DEV_PM_OPS(tpm_hygon_pm, tpm_pm_suspend, tpm_pm_resume);

static const struct acpi_device_id hygon_tpm2_device_ids[] = {
	{"HYGT0101", 0},
	{"", 0},
};

MODULE_DEVICE_TABLE(acpi, hygon_tpm2_device_ids);

static struct acpi_driver hygon_tpm2_acpi_driver = {
	.name = "tpm_hygon",
	.ids = hygon_tpm2_device_ids,
	.ops = {
		.add = hygon_tpm2_acpi_add,
		.remove = hygon_tpm2_acpi_remove,
	},
	.drv = {
		.pm = &tpm_hygon_pm,
	},
};

static int __init hygon_tpm2_init(void)
{
	return acpi_bus_register_driver(&hygon_tpm2_acpi_driver);
}

static void __exit hygon_tpm2_exit(void)
{
	acpi_bus_unregister_driver(&hygon_tpm2_acpi_driver);
}

/*
 * hygon_tpm2_init must be done after ccp module init, but before
 * ima module init. That's why we use a device_initcall_sync which is
 * called after all the device_initcall(includes ccp) but before the
 * late_initcall(includes ima).
 */
device_initcall_sync(hygon_tpm2_init);
module_exit(hygon_tpm2_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("mayuanchen (mayuanchen@hygon.cn)");
MODULE_DESCRIPTION("TPM2 device driver for Hygon PSP");
Loading