Introduce module param enable_unsafe_tph to gate all TPH related features, and add VFIO_DEVICE_FEATURE_TPH_ENABLE uapi together with per-device tph_permit flag. This is a preparatory implementation: only feature framework is added for now, actual TPH_CTRL register permission control and steering tag features (TPH_CPU_ST / TPH_ST_CONFIG) will be attached in subsequent TPH capability virtualization commits. Signed-off-by: Chengwen Feng --- drivers/vfio/pci/vfio_pci.c | 13 ++++++++++++- drivers/vfio/pci/vfio_pci_config.c | 1 + drivers/vfio/pci/vfio_pci_core.c | 25 ++++++++++++++++++++++++- include/linux/vfio_pci_core.h | 4 +++- include/uapi/linux/vfio.h | 7 +++++++ 5 files changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 0c771064c0b8..6d73668459cf 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -60,6 +60,12 @@ static bool disable_denylist; module_param(disable_denylist, bool, 0444); MODULE_PARM_DESC(disable_denylist, "Disable use of device denylist. Disabling the denylist allows binding to devices with known errata that may lead to exploitable stability or security issues when accessed by untrusted users."); +#ifdef CONFIG_PCIE_TPH +static bool enable_unsafe_tph; +module_param(enable_unsafe_tph, bool, 0444); +MODULE_PARM_DESC(enable_unsafe_tph, "Enable PCIe TPH (Transaction Processing Hints) support. It may break platform isolation. If you do not know what this is for, step away. (default: false)"); +#endif + static bool vfio_pci_dev_in_denylist(struct pci_dev *pdev) { switch (pdev->vendor) { @@ -257,12 +263,17 @@ static int __init vfio_pci_init(void) { int ret; bool is_disable_vga = true; + bool is_enable_unsafe_tph = false; #ifdef CONFIG_VFIO_PCI_VGA is_disable_vga = disable_vga; #endif +#ifdef CONFIG_PCIE_TPH + is_enable_unsafe_tph = enable_unsafe_tph; +#endif - vfio_pci_core_set_params(nointxmask, is_disable_vga, disable_idle_d3); + vfio_pci_core_set_params(nointxmask, is_disable_vga, disable_idle_d3, + is_enable_unsafe_tph); /* Register and scan for devices */ ret = pci_register_driver(&vfio_pci_driver); diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 5c6ab172df6c..251d3ec7fdd4 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -1783,6 +1783,7 @@ int vfio_config_init(struct vfio_pci_core_device *vdev) goto out; vdev->bardirty = true; + vdev->tph_permit = false; /* * XXX can we just pci_load_saved_state/pci_restore_state? diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index a28f1e99362c..b0193afca875 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -41,6 +41,7 @@ static bool nointxmask; static bool disable_vga; static bool disable_idle_d3; +static bool enable_unsafe_tph; static void vfio_pci_eventfd_rcu_free(struct rcu_head *rcu) { @@ -1554,6 +1555,24 @@ static int vfio_pci_core_feature_token(struct vfio_pci_core_device *vdev, return 0; } +static int vfio_pci_core_feature_tph_enable(struct vfio_pci_core_device *vdev, + u32 flags, size_t argsz) +{ + int ret; + + if (!enable_unsafe_tph) + return -EOPNOTSUPP; + + ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_SET, 0); + if (ret <= 0) + return ret; + + if (!vdev->tph_permit) + vdev->tph_permit = 1; + + return 0; +} + int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags, void __user *arg, size_t argsz) { @@ -1572,6 +1591,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags, return vfio_pci_core_feature_token(vdev, flags, arg, argsz); case VFIO_DEVICE_FEATURE_DMA_BUF: return vfio_pci_core_feature_dma_buf(vdev, flags, arg, argsz); + case VFIO_DEVICE_FEATURE_TPH_ENABLE: + return vfio_pci_core_feature_tph_enable(vdev, flags, argsz); default: return -ENOTTY; } @@ -2615,11 +2636,13 @@ static void vfio_pci_dev_set_try_reset(struct vfio_device_set *dev_set) } void vfio_pci_core_set_params(bool is_nointxmask, bool is_disable_vga, - bool is_disable_idle_d3) + bool is_disable_idle_d3, + bool is_enable_unsafe_tph) { nointxmask = is_nointxmask; disable_vga = is_disable_vga; disable_idle_d3 = is_disable_idle_d3; + enable_unsafe_tph = is_enable_unsafe_tph; } EXPORT_SYMBOL_GPL(vfio_pci_core_set_params); diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index 5fc6ce4dd786..d551e530dd86 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -128,6 +128,7 @@ struct vfio_pci_core_device { bool pm_intx_masked:1; bool pm_runtime_engaged:1; bool sriov_active; + bool tph_permit; struct pci_saved_state *pci_saved_state; struct pci_saved_state *pm_save; int ioeventfds_nr; @@ -158,7 +159,8 @@ int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev, const struct vfio_pci_regops *ops, size_t size, u32 flags, void *data); void vfio_pci_core_set_params(bool nointxmask, bool is_disable_vga, - bool is_disable_idle_d3); + bool is_disable_idle_d3, + bool is_enable_unsafe_tph); void vfio_pci_core_close_device(struct vfio_device *core_vdev); int vfio_pci_core_init_dev(struct vfio_device *core_vdev); void vfio_pci_core_release_dev(struct vfio_device *core_vdev); diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index 5de618a3a5ee..e5a4d1d7091b 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h @@ -1534,6 +1534,13 @@ struct vfio_device_feature_dma_buf { */ #define VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2 12 +/* + * Device-level opt-in for TPH (Transaction Processing Hints) support. + * When set, allows access to TPH_CPU_ST and TPH_ST_CONFIG features. + * Requires global enable_unsafe_tph module parameter to be enabled. + */ +#define VFIO_DEVICE_FEATURE_TPH_ENABLE 13 + /* -------- API for Type1 VFIO IOMMU -------- */ /** -- 2.17.1