A "tsm" is a platform component that provides an API for securely provisioning resources for a confidential guest (TVM) to consume. "TSM" also happens to be the acronym the PCI specification uses to define the platform agent that carries out device-security operations. That platform capability is commonly called TEE I/O. It is this arrival of TEE I/O platforms that requires the "tsm" concept to grow from a low-level arch-specific detail of TVM instantiation, to a frontend interface to mediate device setup and interact with general purpose kernel subsystems outside of arch/ like the PCI core. Provide a virtual (as in /sys/devices/virtual) class device interface to front all of the aspects of a TSM and TEE I/O that are cross-architecture common. This includes mechanisms like enumerating available platform TEE I/O capabilities and provisioning connections between the platform TSM and device DSMs. It is expected to handle hardware TSMs, like AMD SEV-SNP and ARM CCA where there is a physical TEE coprocessor device running firmware, as well as software TSMs like Intel TDX and RISC-V COVE, where there is a privileged software module loaded at runtime. For now this is just the scaffolding for registering a TSM device and/or TSM-specific attribute groups. Cc: Xiaoyao Li <xiaoyao.li@xxxxxxxxx> Cc: Isaku Yamahata <isaku.yamahata@xxxxxxxxx> Cc: Alexey Kardashevskiy <aik@xxxxxxx> Cc: Wu Hao <hao.wu@xxxxxxxxx> Cc: Yilun Xu <yilun.xu@xxxxxxxxx> Cc: Tom Lendacky <thomas.lendacky@xxxxxxx> Cc: John Allen <john.allen@xxxxxxx> Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- Documentation/ABI/testing/sysfs-class-tsm | 12 +++ drivers/virt/coco/tsm/Kconfig | 7 ++ drivers/virt/coco/tsm/Makefile | 3 + drivers/virt/coco/tsm/class.c | 100 +++++++++++++++++++++++++++++ include/linux/tsm.h | 8 ++ 5 files changed, 130 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-tsm create mode 100644 drivers/virt/coco/tsm/class.c diff --git a/Documentation/ABI/testing/sysfs-class-tsm b/Documentation/ABI/testing/sysfs-class-tsm new file mode 100644 index 000000000000..304b50b53e65 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-tsm @@ -0,0 +1,12 @@ +What: /sys/class/tsm/tsm0/host +Date: January 2024 +Contact: linux-coco@xxxxxxxxxxxxxxx +Description: + (RO) For hardware TSMs represented by a device in /sys/devices, + @host is a link to that device. + Links to hardware TSM sysfs ABIs: + - Documentation/ABI/testing/sysfs-driver-ccp + + For software TSMs instantiated by a software module, @host is a + directory with attributes for that TSM, and those attributes are + documented below. diff --git a/drivers/virt/coco/tsm/Kconfig b/drivers/virt/coco/tsm/Kconfig index 69f04461c83e..595d86917462 100644 --- a/drivers/virt/coco/tsm/Kconfig +++ b/drivers/virt/coco/tsm/Kconfig @@ -5,3 +5,10 @@ config TSM_REPORTS select CONFIGFS_FS tristate + +config ARCH_HAS_TSM + bool + +config TSM + depends on ARCH_HAS_TSM && SYSFS + tristate diff --git a/drivers/virt/coco/tsm/Makefile b/drivers/virt/coco/tsm/Makefile index b48504a3ccfd..f7561169faed 100644 --- a/drivers/virt/coco/tsm/Makefile +++ b/drivers/virt/coco/tsm/Makefile @@ -4,3 +4,6 @@ obj-$(CONFIG_TSM_REPORTS) += tsm_reports.o tsm_reports-y := reports.o + +obj-$(CONFIG_TSM) += tsm.o +tsm-y := class.o diff --git a/drivers/virt/coco/tsm/class.c b/drivers/virt/coco/tsm/class.c new file mode 100644 index 000000000000..a569fa6b09eb --- /dev/null +++ b/drivers/virt/coco/tsm/class.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2024 Intel Corporation. All rights reserved. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/tsm.h> +#include <linux/rwsem.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/cleanup.h> + +static DECLARE_RWSEM(tsm_core_rwsem); +struct class *tsm_class; +struct tsm_subsys { + struct device dev; + const struct tsm_info *info; +} *tsm_subsys; + +int tsm_register(const struct tsm_info *info) +{ + struct device *dev __free(put_device) = NULL; + struct tsm_subsys *subsys; + int rc; + + guard(rwsem_write)(&tsm_core_rwsem); + if (tsm_subsys) { + pr_warn("failed to register: \"%s\", \"%s\" already registered\n", + info->name, tsm_subsys->info->name); + return -EBUSY; + } + + subsys = kzalloc(sizeof(*subsys), GFP_KERNEL); + if (!subsys) + return -ENOMEM; + + subsys->info = info; + dev = &subsys->dev; + dev->class = tsm_class; + dev->groups = info->groups; + dev_set_name(dev, "tsm0"); + rc = device_register(dev); + if (rc) + return rc; + + if (info->host) { + rc = sysfs_create_link(&dev->kobj, &info->host->kobj, "host"); + if (rc) + return rc; + } + + /* don't auto-free @dev */ + dev = NULL; + tsm_subsys = subsys; + + return 0; +} +EXPORT_SYMBOL_GPL(tsm_register); + +void tsm_unregister(const struct tsm_info *info) +{ + guard(rwsem_write)(&tsm_core_rwsem); + if (!tsm_subsys || info != tsm_subsys->info) { + pr_warn("failed to unregister: \"%s\", not currently registered\n", + info->name); + return; + } + + if (info->host) + sysfs_remove_link(&tsm_subsys->dev.kobj, "host"); + device_unregister(&tsm_subsys->dev); + tsm_subsys = NULL; +} +EXPORT_SYMBOL_GPL(tsm_unregister); + +static void tsm_release(struct device *dev) +{ + struct tsm_subsys *subsys = container_of(dev, typeof(*subsys), dev); + + kfree(subsys); +} + +static int __init tsm_init(void) +{ + tsm_class = class_create("tsm"); + if (IS_ERR(tsm_class)) + return PTR_ERR(tsm_class); + + tsm_class->dev_release = tsm_release; + return 0; +} +module_init(tsm_init) + +static void __exit tsm_exit(void) +{ + class_destroy(tsm_class); +} +module_exit(tsm_exit) + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Trusted Security Module core device model"); diff --git a/include/linux/tsm.h b/include/linux/tsm.h index 28753608fcf5..8cb8a661ba41 100644 --- a/include/linux/tsm.h +++ b/include/linux/tsm.h @@ -5,6 +5,12 @@ #include <linux/sizes.h> #include <linux/types.h> +struct tsm_info { + const char *name; + struct device *host; + const struct attribute_group **groups; +}; + #define TSM_REPORT_INBLOB_MAX 64 #define TSM_REPORT_OUTBLOB_MAX SZ_32K @@ -66,4 +72,6 @@ extern const struct config_item_type tsm_report_extra_type; int tsm_report_register(const struct tsm_report_ops *ops, void *priv, const struct config_item_type *type); int tsm_report_unregister(const struct tsm_report_ops *ops); +int tsm_register(const struct tsm_info *info); +void tsm_unregister(const struct tsm_info *info); #endif /* __TSM_H */