@@ -7,3 +7,10 @@ config TSM
config TDX_TSM_BUS
bool
+
+config TDX_TSM
+ depends on INTEL_TDX_HOST
+ select TDX_TSM_BUS
+ select PCI_TSM
+ select TSM
+ tristate "TDX TEE Security Manager Driver"
@@ -6,3 +6,4 @@ obj-$(CONFIG_TSM) += tsm.o
tsm-y := tsm-core.o
obj-$(CONFIG_TDX_TSM_BUS) += tdx_tsm_bus.o
+obj-$(CONFIG_TDX_TSM) += tdx_tsm.o
new file mode 100644
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2024 Intel Corporation. All rights reserved. */
+#include <linux/bitfield.h>
+#include <linux/pci.h>
+#include <linux/pci-tsm.h>
+#include <linux/tdx_tsm_bus.h>
+#include <linux/tsm.h>
+#include <asm/tdx.h>
+
+#define TDISP_FUNC_ID GENMASK(15, 0)
+#define TDISP_FUNC_ID_SEGMENT GENMASK(23, 16)
+#define TDISP_FUNC_ID_SEG_VALID BIT(24)
+
+static inline u32 tdisp_func_id(struct pci_dev *pdev)
+{
+ u32 func_id;
+
+ func_id = FIELD_PREP(TDISP_FUNC_ID_SEGMENT, pci_domain_nr(pdev->bus));
+ if (func_id)
+ func_id |= TDISP_FUNC_ID_SEG_VALID;
+ func_id |= FIELD_PREP(TDISP_FUNC_ID,
+ PCI_DEVID(pdev->bus->number, pdev->devfn));
+
+ return func_id;
+}
+
+struct tdx_tsm {
+ struct pci_tsm_pf0 pci;
+ u32 func_id;
+};
+
+static struct tdx_tsm *to_tdx_tsm(struct pci_tsm *tsm)
+{
+ return container_of(tsm, struct tdx_tsm, pci.tsm);
+}
+
+struct tdx_tdi {
+ struct pci_tdi tdi;
+ u32 func_id;
+};
+
+static struct tdx_tdi *to_tdx_tdi(struct pci_tdi *tdi)
+{
+ return container_of(tdi, struct tdx_tdi, tdi);
+}
+
+static struct pci_tdi *tdx_tsm_bind(struct pci_dev *pdev,
+ struct pci_dev *dsm_dev,
+ struct kvm *kvm, u64 tdi_id)
+{
+ struct tdx_tdi *ttdi __free(kfree) =
+ kzalloc(sizeof(*ttdi), GFP_KERNEL);
+ if (!ttdi)
+ return NULL;
+
+ ttdi->func_id = tdisp_func_id(pdev);
+ ttdi->tdi.pdev = pdev;
+ ttdi->tdi.dsm_dev = pci_dev_get(dsm_dev);
+ ttdi->tdi.kvm = kvm;
+
+ /*TODO: TDX Module required operations */
+
+ return &no_free_ptr(ttdi)->tdi;
+}
+
+static void tdx_tsm_unbind(struct pci_tdi *tdi)
+{
+ struct tdx_tdi *ttdi = to_tdx_tdi(tdi);
+
+ /*TODO: TDX Module required operations */
+
+ pci_dev_put(ttdi->tdi.dsm_dev);
+ kfree(ttdi);
+}
+
+static int tdx_tsm_guest_req(struct pci_dev *pdev,
+ struct pci_tsm_guest_req_info *info)
+{
+ return -ENXIO;
+}
+
+static int tdx_tsm_connect(struct pci_dev *pdev)
+{
+ return -ENXIO;
+}
+
+static void tdx_tsm_disconnect(struct pci_dev *pdev)
+{
+}
+
+static struct pci_tsm *tdx_tsm_pci_probe(struct pci_dev *pdev)
+{
+ if (is_pci_tsm_pf0(pdev)) {
+ int rc;
+
+ struct tdx_tsm *ttsm __free(kfree) =
+ kzalloc(sizeof(*ttsm), GFP_KERNEL);
+ if (!ttsm)
+ return NULL;
+
+ rc = pci_tsm_pf0_initialize(pdev, &ttsm->pci);
+ if (rc)
+ return NULL;
+
+ ttsm->func_id = tdisp_func_id(pdev);
+
+ pci_info(pdev, "PF tsm enabled\n");
+ return &no_free_ptr(ttsm)->pci.tsm;
+ }
+
+ /* for VF and MFD */
+ struct pci_tsm *pci_tsm __free(kfree) =
+ kzalloc(sizeof(*pci_tsm), GFP_KERNEL);
+ if (!pci_tsm)
+ return NULL;
+
+ pci_tsm_initialize(pdev, pci_tsm);
+
+ pci_info(pdev, "VF/MFD tsm enabled\n");
+ return no_free_ptr(pci_tsm);
+}
+
+static void tdx_tsm_pci_remove(struct pci_tsm *tsm)
+{
+ if (is_pci_tsm_pf0(tsm->pdev)) {
+ struct tdx_tsm *ttsm = to_tdx_tsm(tsm);
+
+ pci_info(tsm->pdev, "PF tsm disabled\n");
+ kfree(ttsm);
+
+ return;
+ }
+
+ /* for VF and MFD */
+ kfree(tsm);
+}
+
+static const struct pci_tsm_ops tdx_pci_tsm_ops = {
+ .probe = tdx_tsm_pci_probe,
+ .remove = tdx_tsm_pci_remove,
+ .connect = tdx_tsm_connect,
+ .disconnect = tdx_tsm_disconnect,
+ .bind = tdx_tsm_bind,
+ .unbind = tdx_tsm_unbind,
+ .guest_req = tdx_tsm_guest_req,
+};
+
+static void unregister_tsm(void *tsm_core)
+{
+ tsm_unregister(tsm_core);
+}
+
+static int tdx_tsm_probe(struct device *dev)
+{
+ struct tsm_core_dev *tsm_core;
+
+ tsm_core = tsm_register(dev, NULL, &tdx_pci_tsm_ops);
+ if (IS_ERR(tsm_core)) {
+ dev_err(dev, "failed to register TSM: (%pe)\n", tsm_core);
+ return PTR_ERR(tsm_core);
+ }
+
+ return devm_add_action_or_reset(dev, unregister_tsm, tsm_core);
+}
+
+static struct device_driver tdx_tsm_driver = {
+ .probe = tdx_tsm_probe,
+ .bus = &tdx_subsys,
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .mod_name = KBUILD_MODNAME,
+};
+
+static int __init tdx_tsm_init(void)
+{
+ return driver_register(&tdx_tsm_driver);
+}
+module_init(tdx_tsm_init);
+
+static void __exit tdx_tsm_exit(void)
+{
+ driver_unregister(&tdx_tsm_driver);
+}
+module_exit(tdx_tsm_exit);
+
+MODULE_IMPORT_NS("TDX");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("tdx_tsm");
+MODULE_DESCRIPTION("TDX TEE Security Manager");