| 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | #ifndef __PCI_TSM_H |
| 3 | #define __PCI_TSM_H |
| 4 | #include <linux/mutex.h> |
| 5 | #include <linux/pci.h> |
| 6 | #include <linux/sockptr.h> |
| 7 | |
| 8 | struct pci_tsm; |
| 9 | struct tsm_dev; |
| 10 | struct kvm; |
| 11 | enum pci_tsm_req_scope; |
| 12 | |
| 13 | /* |
| 14 | * struct pci_tsm_ops - manage confidential links and security state |
| 15 | * @link_ops: Coordinate PCIe SPDM and IDE establishment via a platform TSM. |
| 16 | * Provide a secure session transport for TDISP state management |
| 17 | * (typically bare metal physical function operations). |
| 18 | * @devsec_ops: Lock, unlock, and interrogate the security state of the |
| 19 | * function via the platform TSM (typically virtual function |
| 20 | * operations). |
| 21 | * |
| 22 | * This operations are mutually exclusive either a tsm_dev instance |
| 23 | * manages physical link properties or it manages function security |
| 24 | * states like TDISP lock/unlock. |
| 25 | */ |
| 26 | struct pci_tsm_ops { |
| 27 | /* |
| 28 | * struct pci_tsm_link_ops - Manage physical link and the TSM/DSM session |
| 29 | * @probe: establish context with the TSM (allocate / wrap 'struct |
| 30 | * pci_tsm') for follow-on link operations |
| 31 | * @remove: destroy link operations context |
| 32 | * @connect: establish / validate a secure connection (e.g. IDE) |
| 33 | * with the device |
| 34 | * @disconnect: teardown the secure link |
| 35 | * @bind: bind a TDI in preparation for it to be accepted by a TVM |
| 36 | * @unbind: remove a TDI from secure operation with a TVM |
| 37 | * @guest_req: marshal TVM information and state change requests |
| 38 | * |
| 39 | * Context: @probe, @remove, @connect, and @disconnect run under |
| 40 | * pci_tsm_rwsem held for write to sync with TSM unregistration and |
| 41 | * mutual exclusion of @connect and @disconnect. @connect and |
| 42 | * @disconnect additionally run under the DSM lock (struct |
| 43 | * pci_tsm_pf0::lock) as well as @probe and @remove of the subfunctions. |
| 44 | * @bind, @unbind, and @guest_req run under pci_tsm_rwsem held for read |
| 45 | * and the DSM lock. |
| 46 | */ |
| 47 | struct_group_tagged(pci_tsm_link_ops, link_ops, |
| 48 | struct pci_tsm *(*probe)(struct tsm_dev *tsm_dev, |
| 49 | struct pci_dev *pdev); |
| 50 | void (*remove)(struct pci_tsm *tsm); |
| 51 | int (*connect)(struct pci_dev *pdev); |
| 52 | void (*disconnect)(struct pci_dev *pdev); |
| 53 | struct pci_tdi *(*bind)(struct pci_dev *pdev, |
| 54 | struct kvm *kvm, u32 tdi_id); |
| 55 | void (*unbind)(struct pci_tdi *tdi); |
| 56 | ssize_t (*guest_req)(struct pci_tdi *tdi, |
| 57 | enum pci_tsm_req_scope scope, |
| 58 | sockptr_t req_in, size_t in_len, |
| 59 | sockptr_t req_out, size_t out_len, |
| 60 | u64 *tsm_code); |
| 61 | ); |
| 62 | |
| 63 | /* |
| 64 | * struct pci_tsm_devsec_ops - Manage the security state of the function |
| 65 | * @lock: establish context with the TSM (allocate / wrap 'struct |
| 66 | * pci_tsm') for follow-on security state transitions from the |
| 67 | * LOCKED state |
| 68 | * @unlock: destroy TSM context and return device to UNLOCKED state |
| 69 | * |
| 70 | * Context: @lock and @unlock run under pci_tsm_rwsem held for write to |
| 71 | * sync with TSM unregistration and each other |
| 72 | */ |
| 73 | struct_group_tagged(pci_tsm_devsec_ops, devsec_ops, |
| 74 | struct pci_tsm *(*lock)(struct tsm_dev *tsm_dev, |
| 75 | struct pci_dev *pdev); |
| 76 | void (*unlock)(struct pci_tsm *tsm); |
| 77 | ); |
| 78 | }; |
| 79 | |
| 80 | /** |
| 81 | * struct pci_tdi - Core TEE I/O Device Interface (TDI) context |
| 82 | * @pdev: host side representation of guest-side TDI |
| 83 | * @kvm: TEE VM context of bound TDI |
| 84 | * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM |
| 85 | */ |
| 86 | struct pci_tdi { |
| 87 | struct pci_dev *pdev; |
| 88 | struct kvm *kvm; |
| 89 | u32 tdi_id; |
| 90 | }; |
| 91 | |
| 92 | /** |
| 93 | * struct pci_tsm - Core TSM context for a given PCIe endpoint |
| 94 | * @pdev: Back ref to device function, distinguishes type of pci_tsm context |
| 95 | * @dsm_dev: PCI Device Security Manager for link operations on @pdev |
| 96 | * @tsm_dev: PCI TEE Security Manager device for Link Confidentiality or Device |
| 97 | * Function Security operations |
| 98 | * @tdi: TDI context established by the @bind link operation |
| 99 | * |
| 100 | * This structure is wrapped by low level TSM driver data and returned by |
| 101 | * probe()/lock(), it is freed by the corresponding remove()/unlock(). |
| 102 | * |
| 103 | * For link operations it serves to cache the association between a Device |
| 104 | * Security Manager (DSM) and the functions that manager can assign to a TVM. |
| 105 | * That can be "self", for assigning function0 of a TEE I/O device, a |
| 106 | * sub-function (SR-IOV virtual function, or non-function0 |
| 107 | * multifunction-device), or a downstream endpoint (PCIe upstream switch-port as |
| 108 | * DSM). |
| 109 | */ |
| 110 | struct pci_tsm { |
| 111 | struct pci_dev *pdev; |
| 112 | struct pci_dev *dsm_dev; |
| 113 | struct tsm_dev *tsm_dev; |
| 114 | struct pci_tdi *tdi; |
| 115 | }; |
| 116 | |
| 117 | /** |
| 118 | * struct pci_tsm_pf0 - Physical Function 0 TDISP link context |
| 119 | * @base_tsm: generic core "tsm" context |
| 120 | * @lock: mutual exclustion for pci_tsm_ops invocation |
| 121 | * @doe_mb: PCIe Data Object Exchange mailbox |
| 122 | */ |
| 123 | struct pci_tsm_pf0 { |
| 124 | struct pci_tsm base_tsm; |
| 125 | struct mutex lock; |
| 126 | struct pci_doe_mb *doe_mb; |
| 127 | }; |
| 128 | |
| 129 | /* physical function0 and capable of 'connect' */ |
| 130 | static inline bool is_pci_tsm_pf0(struct pci_dev *pdev) |
| 131 | { |
| 132 | if (!pdev) |
| 133 | return false; |
| 134 | |
| 135 | if (!pci_is_pcie(dev: pdev)) |
| 136 | return false; |
| 137 | |
| 138 | if (pdev->is_virtfn) |
| 139 | return false; |
| 140 | |
| 141 | /* |
| 142 | * Allow for a Device Security Manager (DSM) associated with function0 |
| 143 | * of an Endpoint to coordinate TDISP requests for other functions |
| 144 | * (physical or virtual) of the device, or allow for an Upstream Port |
| 145 | * DSM to accept TDISP requests for the Endpoints downstream of the |
| 146 | * switch. |
| 147 | */ |
| 148 | switch (pci_pcie_type(dev: pdev)) { |
| 149 | case PCI_EXP_TYPE_ENDPOINT: |
| 150 | case PCI_EXP_TYPE_UPSTREAM: |
| 151 | case PCI_EXP_TYPE_RC_END: |
| 152 | if (pdev->ide_cap || (pdev->devcap & PCI_EXP_DEVCAP_TEE)) |
| 153 | break; |
| 154 | fallthrough; |
| 155 | default: |
| 156 | return false; |
| 157 | } |
| 158 | |
| 159 | return PCI_FUNC(pdev->devfn) == 0; |
| 160 | } |
| 161 | |
| 162 | /** |
| 163 | * enum pci_tsm_req_scope - Scope of guest requests to be validated by TSM |
| 164 | * |
| 165 | * Guest requests are a transport for a TVM to communicate with a TSM + DSM for |
| 166 | * a given TDI. A TSM driver is responsible for maintaining the kernel security |
| 167 | * model and limit commands that may affect the host, or are otherwise outside |
| 168 | * the typical TDISP operational model. |
| 169 | */ |
| 170 | enum pci_tsm_req_scope { |
| 171 | /** |
| 172 | * @PCI_TSM_REQ_INFO: Read-only, without side effects, request for |
| 173 | * typical TDISP collateral information like Device Interface Reports. |
| 174 | * No device secrets are permitted, and no device state is changed. |
| 175 | */ |
| 176 | PCI_TSM_REQ_INFO = 0, |
| 177 | /** |
| 178 | * @PCI_TSM_REQ_STATE_CHANGE: Request to change the TDISP state from |
| 179 | * UNLOCKED->LOCKED, LOCKED->RUN, or other architecture specific state |
| 180 | * changes to support those transitions for a TDI. No other (unrelated |
| 181 | * to TDISP) device / host state, configuration, or data change is |
| 182 | * permitted. |
| 183 | */ |
| 184 | PCI_TSM_REQ_STATE_CHANGE = 1, |
| 185 | /** |
| 186 | * @PCI_TSM_REQ_DEBUG_READ: Read-only request for debug information |
| 187 | * |
| 188 | * A method to facilitate TVM information retrieval outside of typical |
| 189 | * TDISP operational requirements. No device secrets are permitted. |
| 190 | */ |
| 191 | PCI_TSM_REQ_DEBUG_READ = 2, |
| 192 | /** |
| 193 | * @PCI_TSM_REQ_DEBUG_WRITE: Device state changes for debug purposes |
| 194 | * |
| 195 | * The request may affect the operational state of the device outside of |
| 196 | * the TDISP operational model. If allowed, requires CAP_SYS_RAW_IO, and |
| 197 | * will taint the kernel. |
| 198 | */ |
| 199 | PCI_TSM_REQ_DEBUG_WRITE = 3, |
| 200 | }; |
| 201 | |
| 202 | #ifdef CONFIG_PCI_TSM |
| 203 | int pci_tsm_register(struct tsm_dev *tsm_dev); |
| 204 | void pci_tsm_unregister(struct tsm_dev *tsm_dev); |
| 205 | int pci_tsm_link_constructor(struct pci_dev *pdev, struct pci_tsm *tsm, |
| 206 | struct tsm_dev *tsm_dev); |
| 207 | int pci_tsm_pf0_constructor(struct pci_dev *pdev, struct pci_tsm_pf0 *tsm, |
| 208 | struct tsm_dev *tsm_dev); |
| 209 | void pci_tsm_pf0_destructor(struct pci_tsm_pf0 *tsm); |
| 210 | int pci_tsm_doe_transfer(struct pci_dev *pdev, u8 type, const void *req, |
| 211 | size_t req_sz, void *resp, size_t resp_sz); |
| 212 | int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 tdi_id); |
| 213 | void pci_tsm_unbind(struct pci_dev *pdev); |
| 214 | void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi, |
| 215 | struct kvm *kvm, u32 tdi_id); |
| 216 | ssize_t pci_tsm_guest_req(struct pci_dev *pdev, enum pci_tsm_req_scope scope, |
| 217 | sockptr_t req_in, size_t in_len, sockptr_t req_out, |
| 218 | size_t out_len, u64 *tsm_code); |
| 219 | #else |
| 220 | static inline int pci_tsm_register(struct tsm_dev *tsm_dev) |
| 221 | { |
| 222 | return 0; |
| 223 | } |
| 224 | static inline void pci_tsm_unregister(struct tsm_dev *tsm_dev) |
| 225 | { |
| 226 | } |
| 227 | static inline int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u64 tdi_id) |
| 228 | { |
| 229 | return -ENXIO; |
| 230 | } |
| 231 | static inline void pci_tsm_unbind(struct pci_dev *pdev) |
| 232 | { |
| 233 | } |
| 234 | static inline ssize_t pci_tsm_guest_req(struct pci_dev *pdev, |
| 235 | enum pci_tsm_req_scope scope, |
| 236 | sockptr_t req_in, size_t in_len, |
| 237 | sockptr_t req_out, size_t out_len, |
| 238 | u64 *tsm_code) |
| 239 | { |
| 240 | return -ENXIO; |
| 241 | } |
| 242 | #endif |
| 243 | #endif /*__PCI_TSM_H */ |
| 244 | |