Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

PCI/TSM: Add pci_tsm_bind() helper for instantiating TDIs

After a PCIe device has established a secure link and session between a TEE
Security Manager (TSM) and its local Device Security Manager (DSM), the
device or its subfunctions are candidates to be bound to a private memory
context, a TVM. A PCIe device function interface assigned to a TVM is a TEE
Device Interface (TDI).

The pci_tsm_bind() requests the low-level TSM driver to associate the
device with private MMIO and private IOMMU context resources of a given TVM
represented by a @kvm argument. A device in the bound state corresponds to
the TDISP protocol LOCKED state and awaits validation by the TVM. It is a
'struct pci_tsm_link_ops' operation because, similar to IDE establishment,
it involves host side resource establishment and context setup on behalf of
the guest. It is also expected to be performed lazily to allow for
operation of the device in non-confidential "shared" context for pre-lock
configuration.

Co-developed-by: Xu Yilun <yilun.xu@linux.intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Link: https://patch.msgid.link/20251113021446.436830-7-dan.j.williams@intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+142 -1
+108 -1
drivers/pci/tsm.c
··· 270 270 return 0; 271 271 } 272 272 273 + /* 274 + * Note, this helper only returns an error code and takes an argument for 275 + * compatibility with the pci_walk_bus() callback prototype. pci_tsm_unbind() 276 + * always succeeds. 277 + */ 278 + static int __pci_tsm_unbind(struct pci_dev *pdev, void *data) 279 + { 280 + struct pci_tdi *tdi; 281 + struct pci_tsm_pf0 *tsm_pf0; 282 + 283 + lockdep_assert_held(&pci_tsm_rwsem); 284 + 285 + if (!pdev->tsm) 286 + return 0; 287 + 288 + tsm_pf0 = to_pci_tsm_pf0(pdev->tsm); 289 + guard(mutex)(&tsm_pf0->lock); 290 + 291 + tdi = pdev->tsm->tdi; 292 + if (!tdi) 293 + return 0; 294 + 295 + to_pci_tsm_ops(pdev->tsm)->unbind(tdi); 296 + pdev->tsm->tdi = NULL; 297 + 298 + return 0; 299 + } 300 + 301 + void pci_tsm_unbind(struct pci_dev *pdev) 302 + { 303 + guard(rwsem_read)(&pci_tsm_rwsem); 304 + __pci_tsm_unbind(pdev, NULL); 305 + } 306 + EXPORT_SYMBOL_GPL(pci_tsm_unbind); 307 + 308 + /** 309 + * pci_tsm_bind() - Bind @pdev as a TDI for @kvm 310 + * @pdev: PCI device function to bind 311 + * @kvm: Private memory attach context 312 + * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM 313 + * 314 + * Returns 0 on success, or a negative error code on failure. 315 + * 316 + * Context: Caller is responsible for constraining the bind lifetime to the 317 + * registered state of the device. For example, pci_tsm_bind() / 318 + * pci_tsm_unbind() limited to the VFIO driver bound state of the device. 319 + */ 320 + int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 tdi_id) 321 + { 322 + struct pci_tsm_pf0 *tsm_pf0; 323 + struct pci_tdi *tdi; 324 + 325 + if (!kvm) 326 + return -EINVAL; 327 + 328 + guard(rwsem_read)(&pci_tsm_rwsem); 329 + 330 + if (!pdev->tsm) 331 + return -EINVAL; 332 + 333 + if (!is_link_tsm(pdev->tsm->tsm_dev)) 334 + return -ENXIO; 335 + 336 + tsm_pf0 = to_pci_tsm_pf0(pdev->tsm); 337 + guard(mutex)(&tsm_pf0->lock); 338 + 339 + /* Resolve races to bind a TDI */ 340 + if (pdev->tsm->tdi) { 341 + if (pdev->tsm->tdi->kvm != kvm) 342 + return -EBUSY; 343 + return 0; 344 + } 345 + 346 + tdi = to_pci_tsm_ops(pdev->tsm)->bind(pdev, kvm, tdi_id); 347 + if (IS_ERR(tdi)) 348 + return PTR_ERR(tdi); 349 + 350 + pdev->tsm->tdi = tdi; 351 + 352 + return 0; 353 + } 354 + EXPORT_SYMBOL_GPL(pci_tsm_bind); 355 + 356 + static void pci_tsm_unbind_all(struct pci_dev *pdev) 357 + { 358 + pci_tsm_walk_fns_reverse(pdev, __pci_tsm_unbind, NULL); 359 + __pci_tsm_unbind(pdev, NULL); 360 + } 361 + 273 362 static void __pci_tsm_disconnect(struct pci_dev *pdev) 274 363 { 275 364 struct pci_tsm_pf0 *tsm_pf0 = to_pci_tsm_pf0(pdev->tsm); ··· 366 277 367 278 /* disconnect() mutually exclusive with subfunction pci_tsm_init() */ 368 279 lockdep_assert_held_write(&pci_tsm_rwsem); 280 + 281 + pci_tsm_unbind_all(pdev); 369 282 370 283 /* 371 284 * disconnect() is uninterruptible as it may be called for device ··· 531 440 } 532 441 533 442 /** 443 + * pci_tsm_tdi_constructor() - base 'struct pci_tdi' initialization for link TSMs 444 + * @pdev: PCI device function representing the TDI 445 + * @tdi: context to initialize 446 + * @kvm: Private memory attach context 447 + * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM 448 + */ 449 + void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi, 450 + struct kvm *kvm, u32 tdi_id) 451 + { 452 + tdi->pdev = pdev; 453 + tdi->kvm = kvm; 454 + tdi->tdi_id = tdi_id; 455 + } 456 + EXPORT_SYMBOL_GPL(pci_tsm_tdi_constructor); 457 + 458 + /** 534 459 * pci_tsm_link_constructor() - base 'struct pci_tsm' initialization for link TSMs 535 460 * @pdev: The PCI device 536 461 * @tsm: context to initialize ··· 639 532 640 533 static void pci_tsm_fn_exit(struct pci_dev *pdev) 641 534 { 642 - /* TODO: unbind the fn */ 535 + __pci_tsm_unbind(pdev, NULL); 643 536 tsm_remove(pdev->tsm); 644 537 } 645 538
+34
include/linux/pci-tsm.h
··· 6 6 7 7 struct pci_tsm; 8 8 struct tsm_dev; 9 + struct kvm; 10 + enum pci_tsm_req_scope; 9 11 10 12 /* 11 13 * struct pci_tsm_ops - manage confidential links and security state ··· 31 29 * @connect: establish / validate a secure connection (e.g. IDE) 32 30 * with the device 33 31 * @disconnect: teardown the secure link 32 + * @bind: bind a TDI in preparation for it to be accepted by a TVM 33 + * @unbind: remove a TDI from secure operation with a TVM 34 34 * 35 35 * Context: @probe, @remove, @connect, and @disconnect run under 36 36 * pci_tsm_rwsem held for write to sync with TSM unregistration and 37 37 * mutual exclusion of @connect and @disconnect. @connect and 38 38 * @disconnect additionally run under the DSM lock (struct 39 39 * pci_tsm_pf0::lock) as well as @probe and @remove of the subfunctions. 40 + * @bind and @unbind run under pci_tsm_rwsem held for read and the DSM 41 + * lock. 40 42 */ 41 43 struct_group_tagged(pci_tsm_link_ops, link_ops, 42 44 struct pci_tsm *(*probe)(struct tsm_dev *tsm_dev, ··· 48 42 void (*remove)(struct pci_tsm *tsm); 49 43 int (*connect)(struct pci_dev *pdev); 50 44 void (*disconnect)(struct pci_dev *pdev); 45 + struct pci_tdi *(*bind)(struct pci_dev *pdev, 46 + struct kvm *kvm, u32 tdi_id); 47 + void (*unbind)(struct pci_tdi *tdi); 51 48 ); 52 49 53 50 /* ··· 71 62 }; 72 63 73 64 /** 65 + * struct pci_tdi - Core TEE I/O Device Interface (TDI) context 66 + * @pdev: host side representation of guest-side TDI 67 + * @kvm: TEE VM context of bound TDI 68 + * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM 69 + */ 70 + struct pci_tdi { 71 + struct pci_dev *pdev; 72 + struct kvm *kvm; 73 + u32 tdi_id; 74 + }; 75 + 76 + /** 74 77 * struct pci_tsm - Core TSM context for a given PCIe endpoint 75 78 * @pdev: Back ref to device function, distinguishes type of pci_tsm context 76 79 * @dsm_dev: PCI Device Security Manager for link operations on @pdev 77 80 * @tsm_dev: PCI TEE Security Manager device for Link Confidentiality or Device 78 81 * Function Security operations 82 + * @tdi: TDI context established by the @bind link operation 79 83 * 80 84 * This structure is wrapped by low level TSM driver data and returned by 81 85 * probe()/lock(), it is freed by the corresponding remove()/unlock(). ··· 104 82 struct pci_dev *pdev; 105 83 struct pci_dev *dsm_dev; 106 84 struct tsm_dev *tsm_dev; 85 + struct pci_tdi *tdi; 107 86 }; 108 87 109 88 /** ··· 162 139 void pci_tsm_pf0_destructor(struct pci_tsm_pf0 *tsm); 163 140 int pci_tsm_doe_transfer(struct pci_dev *pdev, u8 type, const void *req, 164 141 size_t req_sz, void *resp, size_t resp_sz); 142 + int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 tdi_id); 143 + void pci_tsm_unbind(struct pci_dev *pdev); 144 + void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi, 145 + struct kvm *kvm, u32 tdi_id); 165 146 #else 166 147 static inline int pci_tsm_register(struct tsm_dev *tsm_dev) 167 148 { 168 149 return 0; 169 150 } 170 151 static inline void pci_tsm_unregister(struct tsm_dev *tsm_dev) 152 + { 153 + } 154 + static inline int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u64 tdi_id) 155 + { 156 + return -ENXIO; 157 + } 158 + static inline void pci_tsm_unbind(struct pci_dev *pdev) 171 159 { 172 160 } 173 161 #endif