Skip to content

Commit 50cbec1

Browse files
committed
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>
1 parent 0791153 commit 50cbec1

2 files changed

Lines changed: 142 additions & 1 deletion

File tree

drivers/pci/tsm.c

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,95 @@ static int remove_fn(struct pci_dev *pdev, void *data)
270270
return 0;
271271
}
272272

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+
273362
static void __pci_tsm_disconnect(struct pci_dev *pdev)
274363
{
275364
struct pci_tsm_pf0 *tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
@@ -278,6 +367,8 @@ static void __pci_tsm_disconnect(struct pci_dev *pdev)
278367
/* disconnect() mutually exclusive with subfunction pci_tsm_init() */
279368
lockdep_assert_held_write(&pci_tsm_rwsem);
280369

370+
pci_tsm_unbind_all(pdev);
371+
281372
/*
282373
* disconnect() is uninterruptible as it may be called for device
283374
* teardown
@@ -439,6 +530,22 @@ static struct pci_dev *find_dsm_dev(struct pci_dev *pdev)
439530
return NULL;
440531
}
441532

533+
/**
534+
* pci_tsm_tdi_constructor() - base 'struct pci_tdi' initialization for link TSMs
535+
* @pdev: PCI device function representing the TDI
536+
* @tdi: context to initialize
537+
* @kvm: Private memory attach context
538+
* @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM
539+
*/
540+
void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi,
541+
struct kvm *kvm, u32 tdi_id)
542+
{
543+
tdi->pdev = pdev;
544+
tdi->kvm = kvm;
545+
tdi->tdi_id = tdi_id;
546+
}
547+
EXPORT_SYMBOL_GPL(pci_tsm_tdi_constructor);
548+
442549
/**
443550
* pci_tsm_link_constructor() - base 'struct pci_tsm' initialization for link TSMs
444551
* @pdev: The PCI device
@@ -532,7 +639,7 @@ int pci_tsm_register(struct tsm_dev *tsm_dev)
532639

533640
static void pci_tsm_fn_exit(struct pci_dev *pdev)
534641
{
535-
/* TODO: unbind the fn */
642+
__pci_tsm_unbind(pdev, NULL);
536643
tsm_remove(pdev->tsm);
537644
}
538645

include/linux/pci-tsm.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
struct pci_tsm;
88
struct tsm_dev;
9+
struct kvm;
10+
enum pci_tsm_req_scope;
911

1012
/*
1113
* struct pci_tsm_ops - manage confidential links and security state
@@ -29,19 +31,26 @@ struct pci_tsm_ops {
2931
* @connect: establish / validate a secure connection (e.g. IDE)
3032
* with the device
3133
* @disconnect: teardown the secure link
34+
* @bind: bind a TDI in preparation for it to be accepted by a TVM
35+
* @unbind: remove a TDI from secure operation with a TVM
3236
*
3337
* Context: @probe, @remove, @connect, and @disconnect run under
3438
* pci_tsm_rwsem held for write to sync with TSM unregistration and
3539
* mutual exclusion of @connect and @disconnect. @connect and
3640
* @disconnect additionally run under the DSM lock (struct
3741
* pci_tsm_pf0::lock) as well as @probe and @remove of the subfunctions.
42+
* @bind and @unbind run under pci_tsm_rwsem held for read and the DSM
43+
* lock.
3844
*/
3945
struct_group_tagged(pci_tsm_link_ops, link_ops,
4046
struct pci_tsm *(*probe)(struct tsm_dev *tsm_dev,
4147
struct pci_dev *pdev);
4248
void (*remove)(struct pci_tsm *tsm);
4349
int (*connect)(struct pci_dev *pdev);
4450
void (*disconnect)(struct pci_dev *pdev);
51+
struct pci_tdi *(*bind)(struct pci_dev *pdev,
52+
struct kvm *kvm, u32 tdi_id);
53+
void (*unbind)(struct pci_tdi *tdi);
4554
);
4655

4756
/*
@@ -61,12 +70,25 @@ struct pci_tsm_ops {
6170
);
6271
};
6372

73+
/**
74+
* struct pci_tdi - Core TEE I/O Device Interface (TDI) context
75+
* @pdev: host side representation of guest-side TDI
76+
* @kvm: TEE VM context of bound TDI
77+
* @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM
78+
*/
79+
struct pci_tdi {
80+
struct pci_dev *pdev;
81+
struct kvm *kvm;
82+
u32 tdi_id;
83+
};
84+
6485
/**
6586
* struct pci_tsm - Core TSM context for a given PCIe endpoint
6687
* @pdev: Back ref to device function, distinguishes type of pci_tsm context
6788
* @dsm_dev: PCI Device Security Manager for link operations on @pdev
6889
* @tsm_dev: PCI TEE Security Manager device for Link Confidentiality or Device
6990
* Function Security operations
91+
* @tdi: TDI context established by the @bind link operation
7092
*
7193
* This structure is wrapped by low level TSM driver data and returned by
7294
* probe()/lock(), it is freed by the corresponding remove()/unlock().
@@ -82,6 +104,7 @@ struct pci_tsm {
82104
struct pci_dev *pdev;
83105
struct pci_dev *dsm_dev;
84106
struct tsm_dev *tsm_dev;
107+
struct pci_tdi *tdi;
85108
};
86109

87110
/**
@@ -139,6 +162,10 @@ int pci_tsm_pf0_constructor(struct pci_dev *pdev, struct pci_tsm_pf0 *tsm,
139162
void pci_tsm_pf0_destructor(struct pci_tsm_pf0 *tsm);
140163
int pci_tsm_doe_transfer(struct pci_dev *pdev, u8 type, const void *req,
141164
size_t req_sz, void *resp, size_t resp_sz);
165+
int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 tdi_id);
166+
void pci_tsm_unbind(struct pci_dev *pdev);
167+
void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi,
168+
struct kvm *kvm, u32 tdi_id);
142169
#else
143170
static inline int pci_tsm_register(struct tsm_dev *tsm_dev)
144171
{
@@ -147,5 +174,12 @@ static inline int pci_tsm_register(struct tsm_dev *tsm_dev)
147174
static inline void pci_tsm_unregister(struct tsm_dev *tsm_dev)
148175
{
149176
}
177+
static inline int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u64 tdi_id)
178+
{
179+
return -ENXIO;
180+
}
181+
static inline void pci_tsm_unbind(struct pci_dev *pdev)
182+
{
183+
}
150184
#endif
151185
#endif /*__PCI_TSM_H */

0 commit comments

Comments
 (0)