|
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | +/* |
| 3 | + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 4 | + */ |
| 5 | + |
| 6 | +#ifndef _NE_PCI_DEV_H_ |
| 7 | +#define _NE_PCI_DEV_H_ |
| 8 | + |
| 9 | +#include <linux/atomic.h> |
| 10 | +#include <linux/list.h> |
| 11 | +#include <linux/mutex.h> |
| 12 | +#include <linux/pci.h> |
| 13 | +#include <linux/pci_ids.h> |
| 14 | +#include <linux/wait.h> |
| 15 | + |
| 16 | +/** |
| 17 | + * DOC: Nitro Enclaves (NE) PCI device |
| 18 | + */ |
| 19 | + |
| 20 | +/** |
| 21 | + * PCI_DEVICE_ID_NE - Nitro Enclaves PCI device id. |
| 22 | + */ |
| 23 | +#define PCI_DEVICE_ID_NE (0xe4c1) |
| 24 | +/** |
| 25 | + * PCI_BAR_NE - Nitro Enclaves PCI device MMIO BAR. |
| 26 | + */ |
| 27 | +#define PCI_BAR_NE (0x03) |
| 28 | + |
| 29 | +/** |
| 30 | + * DOC: Device registers in the NE PCI device MMIO BAR |
| 31 | + */ |
| 32 | + |
| 33 | +/** |
| 34 | + * NE_ENABLE - (1 byte) Register to notify the device that the driver is using |
| 35 | + * it (Read/Write). |
| 36 | + */ |
| 37 | +#define NE_ENABLE (0x0000) |
| 38 | +#define NE_ENABLE_OFF (0x00) |
| 39 | +#define NE_ENABLE_ON (0x01) |
| 40 | + |
| 41 | +/** |
| 42 | + * NE_VERSION - (2 bytes) Register to select the device run-time version |
| 43 | + * (Read/Write). |
| 44 | + */ |
| 45 | +#define NE_VERSION (0x0002) |
| 46 | +#define NE_VERSION_MAX (0x0001) |
| 47 | + |
| 48 | +/** |
| 49 | + * NE_COMMAND - (4 bytes) Register to notify the device what command was |
| 50 | + * requested (Write-Only). |
| 51 | + */ |
| 52 | +#define NE_COMMAND (0x0004) |
| 53 | + |
| 54 | +/** |
| 55 | + * NE_EVTCNT - (4 bytes) Register to notify the driver that a reply or a device |
| 56 | + * event is available (Read-Only): |
| 57 | + * - Lower half - command reply counter |
| 58 | + * - Higher half - out-of-band device event counter |
| 59 | + */ |
| 60 | +#define NE_EVTCNT (0x000c) |
| 61 | +#define NE_EVTCNT_REPLY_SHIFT (0) |
| 62 | +#define NE_EVTCNT_REPLY_MASK (0x0000ffff) |
| 63 | +#define NE_EVTCNT_REPLY(cnt) (((cnt) & NE_EVTCNT_REPLY_MASK) >> \ |
| 64 | + NE_EVTCNT_REPLY_SHIFT) |
| 65 | +#define NE_EVTCNT_EVENT_SHIFT (16) |
| 66 | +#define NE_EVTCNT_EVENT_MASK (0xffff0000) |
| 67 | +#define NE_EVTCNT_EVENT(cnt) (((cnt) & NE_EVTCNT_EVENT_MASK) >> \ |
| 68 | + NE_EVTCNT_EVENT_SHIFT) |
| 69 | + |
| 70 | +/** |
| 71 | + * NE_SEND_DATA - (240 bytes) Buffer for sending the command request payload |
| 72 | + * (Read/Write). |
| 73 | + */ |
| 74 | +#define NE_SEND_DATA (0x0010) |
| 75 | + |
| 76 | +/** |
| 77 | + * NE_RECV_DATA - (240 bytes) Buffer for receiving the command reply payload |
| 78 | + * (Read-Only). |
| 79 | + */ |
| 80 | +#define NE_RECV_DATA (0x0100) |
| 81 | + |
| 82 | +/** |
| 83 | + * DOC: Device MMIO buffer sizes |
| 84 | + */ |
| 85 | + |
| 86 | +/** |
| 87 | + * NE_SEND_DATA_SIZE / NE_RECV_DATA_SIZE - 240 bytes for send / recv buffer. |
| 88 | + */ |
| 89 | +#define NE_SEND_DATA_SIZE (240) |
| 90 | +#define NE_RECV_DATA_SIZE (240) |
| 91 | + |
| 92 | +/** |
| 93 | + * DOC: MSI-X interrupt vectors |
| 94 | + */ |
| 95 | + |
| 96 | +/** |
| 97 | + * NE_VEC_REPLY - MSI-X vector used for command reply notification. |
| 98 | + */ |
| 99 | +#define NE_VEC_REPLY (0) |
| 100 | + |
| 101 | +/** |
| 102 | + * NE_VEC_EVENT - MSI-X vector used for out-of-band events e.g. enclave crash. |
| 103 | + */ |
| 104 | +#define NE_VEC_EVENT (1) |
| 105 | + |
| 106 | +/** |
| 107 | + * enum ne_pci_dev_cmd_type - Device command types. |
| 108 | + * @INVALID_CMD: Invalid command. |
| 109 | + * @ENCLAVE_START: Start an enclave, after setting its resources. |
| 110 | + * @ENCLAVE_GET_SLOT: Get the slot uid of an enclave. |
| 111 | + * @ENCLAVE_STOP: Terminate an enclave. |
| 112 | + * @SLOT_ALLOC : Allocate a slot for an enclave. |
| 113 | + * @SLOT_FREE: Free the slot allocated for an enclave |
| 114 | + * @SLOT_ADD_MEM: Add a memory region to an enclave slot. |
| 115 | + * @SLOT_ADD_VCPU: Add a vCPU to an enclave slot. |
| 116 | + * @SLOT_COUNT : Get the number of allocated slots. |
| 117 | + * @NEXT_SLOT: Get the next slot in the list of allocated slots. |
| 118 | + * @SLOT_INFO: Get the info for a slot e.g. slot uid, vCPUs count. |
| 119 | + * @SLOT_ADD_BULK_VCPUS: Add a number of vCPUs, not providing CPU ids. |
| 120 | + * @MAX_CMD: A gatekeeper for max possible command type. |
| 121 | + */ |
| 122 | +enum ne_pci_dev_cmd_type { |
| 123 | + INVALID_CMD = 0, |
| 124 | + ENCLAVE_START = 1, |
| 125 | + ENCLAVE_GET_SLOT = 2, |
| 126 | + ENCLAVE_STOP = 3, |
| 127 | + SLOT_ALLOC = 4, |
| 128 | + SLOT_FREE = 5, |
| 129 | + SLOT_ADD_MEM = 6, |
| 130 | + SLOT_ADD_VCPU = 7, |
| 131 | + SLOT_COUNT = 8, |
| 132 | + NEXT_SLOT = 9, |
| 133 | + SLOT_INFO = 10, |
| 134 | + SLOT_ADD_BULK_VCPUS = 11, |
| 135 | + MAX_CMD, |
| 136 | +}; |
| 137 | + |
| 138 | +/** |
| 139 | + * DOC: Device commands - payload structure for requests and replies. |
| 140 | + */ |
| 141 | + |
| 142 | +/** |
| 143 | + * struct enclave_start_req - ENCLAVE_START request. |
| 144 | + * @slot_uid: Slot unique id mapped to the enclave to start. |
| 145 | + * @enclave_cid: Context ID (CID) for the enclave vsock device. |
| 146 | + * If 0, CID is autogenerated. |
| 147 | + * @flags: Flags for the enclave to start with (e.g. debug mode). |
| 148 | + */ |
| 149 | +struct enclave_start_req { |
| 150 | + u64 slot_uid; |
| 151 | + u64 enclave_cid; |
| 152 | + u64 flags; |
| 153 | +}; |
| 154 | + |
| 155 | +/** |
| 156 | + * struct enclave_get_slot_req - ENCLAVE_GET_SLOT request. |
| 157 | + * @enclave_cid: Context ID (CID) for the enclave vsock device. |
| 158 | + */ |
| 159 | +struct enclave_get_slot_req { |
| 160 | + u64 enclave_cid; |
| 161 | +}; |
| 162 | + |
| 163 | +/** |
| 164 | + * struct enclave_stop_req - ENCLAVE_STOP request. |
| 165 | + * @slot_uid: Slot unique id mapped to the enclave to stop. |
| 166 | + */ |
| 167 | +struct enclave_stop_req { |
| 168 | + u64 slot_uid; |
| 169 | +}; |
| 170 | + |
| 171 | +/** |
| 172 | + * struct slot_alloc_req - SLOT_ALLOC request. |
| 173 | + * @unused: In order to avoid weird sizeof edge cases. |
| 174 | + */ |
| 175 | +struct slot_alloc_req { |
| 176 | + u8 unused; |
| 177 | +}; |
| 178 | + |
| 179 | +/** |
| 180 | + * struct slot_free_req - SLOT_FREE request. |
| 181 | + * @slot_uid: Slot unique id mapped to the slot to free. |
| 182 | + */ |
| 183 | +struct slot_free_req { |
| 184 | + u64 slot_uid; |
| 185 | +}; |
| 186 | + |
| 187 | +/* TODO: Add flags field to the request to add memory region. */ |
| 188 | +/** |
| 189 | + * struct slot_add_mem_req - SLOT_ADD_MEM request. |
| 190 | + * @slot_uid: Slot unique id mapped to the slot to add the memory region to. |
| 191 | + * @paddr: Physical address of the memory region to add to the slot. |
| 192 | + * @size: Memory size, in bytes, of the memory region to add to the slot. |
| 193 | + */ |
| 194 | +struct slot_add_mem_req { |
| 195 | + u64 slot_uid; |
| 196 | + u64 paddr; |
| 197 | + u64 size; |
| 198 | +}; |
| 199 | + |
| 200 | +/** |
| 201 | + * struct slot_add_vcpu_req - SLOT_ADD_VCPU request. |
| 202 | + * @slot_uid: Slot unique id mapped to the slot to add the vCPU to. |
| 203 | + * @vcpu_id: vCPU ID of the CPU to add to the enclave. |
| 204 | + * @padding: Padding for the overall data structure. |
| 205 | + */ |
| 206 | +struct slot_add_vcpu_req { |
| 207 | + u64 slot_uid; |
| 208 | + u32 vcpu_id; |
| 209 | + u8 padding[4]; |
| 210 | +}; |
| 211 | + |
| 212 | +/** |
| 213 | + * struct slot_count_req - SLOT_COUNT request. |
| 214 | + * @unused: In order to avoid weird sizeof edge cases. |
| 215 | + */ |
| 216 | +struct slot_count_req { |
| 217 | + u8 unused; |
| 218 | +}; |
| 219 | + |
| 220 | +/** |
| 221 | + * struct next_slot_req - NEXT_SLOT request. |
| 222 | + * @slot_uid: Slot unique id of the next slot in the iteration. |
| 223 | + */ |
| 224 | +struct next_slot_req { |
| 225 | + u64 slot_uid; |
| 226 | +}; |
| 227 | + |
| 228 | +/** |
| 229 | + * struct slot_info_req - SLOT_INFO request. |
| 230 | + * @slot_uid: Slot unique id mapped to the slot to get information about. |
| 231 | + */ |
| 232 | +struct slot_info_req { |
| 233 | + u64 slot_uid; |
| 234 | +}; |
| 235 | + |
| 236 | +/** |
| 237 | + * struct slot_add_bulk_vcpus_req - SLOT_ADD_BULK_VCPUS request. |
| 238 | + * @slot_uid: Slot unique id mapped to the slot to add vCPUs to. |
| 239 | + * @nr_vcpus: Number of vCPUs to add to the slot. |
| 240 | + */ |
| 241 | +struct slot_add_bulk_vcpus_req { |
| 242 | + u64 slot_uid; |
| 243 | + u64 nr_vcpus; |
| 244 | +}; |
| 245 | + |
| 246 | +/** |
| 247 | + * struct ne_pci_dev_cmd_reply - NE PCI device command reply. |
| 248 | + * @rc : Return code of the logic that processed the request. |
| 249 | + * @padding0: Padding for the overall data structure. |
| 250 | + * @slot_uid: Valid for all commands except SLOT_COUNT. |
| 251 | + * @enclave_cid: Valid for ENCLAVE_START command. |
| 252 | + * @slot_count : Valid for SLOT_COUNT command. |
| 253 | + * @mem_regions: Valid for SLOT_ALLOC and SLOT_INFO commands. |
| 254 | + * @mem_size: Valid for SLOT_INFO command. |
| 255 | + * @nr_vcpus: Valid for SLOT_INFO command. |
| 256 | + * @flags: Valid for SLOT_INFO command. |
| 257 | + * @state: Valid for SLOT_INFO command. |
| 258 | + * @padding1: Padding for the overall data structure. |
| 259 | + */ |
| 260 | +struct ne_pci_dev_cmd_reply { |
| 261 | + s32 rc; |
| 262 | + u8 padding0[4]; |
| 263 | + u64 slot_uid; |
| 264 | + u64 enclave_cid; |
| 265 | + u64 slot_count; |
| 266 | + u64 mem_regions; |
| 267 | + u64 mem_size; |
| 268 | + u64 nr_vcpus; |
| 269 | + u64 flags; |
| 270 | + u16 state; |
| 271 | + u8 padding1[6]; |
| 272 | +}; |
| 273 | + |
| 274 | +/** |
| 275 | + * struct ne_pci_dev - Nitro Enclaves (NE) PCI device. |
| 276 | + * @cmd_reply_avail: Variable set if a reply has been sent by the |
| 277 | + * PCI device. |
| 278 | + * @cmd_reply_wait_q: Wait queue for handling command reply from the |
| 279 | + * PCI device. |
| 280 | + * @enclaves_list: List of the enclaves managed by the PCI device. |
| 281 | + * @enclaves_list_mutex: Mutex for accessing the list of enclaves. |
| 282 | + * @event_wq: Work queue for handling out-of-band events |
| 283 | + * triggered by the Nitro Hypervisor which require |
| 284 | + * enclave state scanning and propagation to the |
| 285 | + * enclave process. |
| 286 | + * @iomem_base : MMIO region of the PCI device. |
| 287 | + * @notify_work: Work item for every received out-of-band event. |
| 288 | + * @pci_dev_mutex: Mutex for accessing the PCI device MMIO space. |
| 289 | + * @pdev: PCI device data structure. |
| 290 | + */ |
| 291 | +struct ne_pci_dev { |
| 292 | + atomic_t cmd_reply_avail; |
| 293 | + wait_queue_head_t cmd_reply_wait_q; |
| 294 | + struct list_head enclaves_list; |
| 295 | + struct mutex enclaves_list_mutex; |
| 296 | + struct workqueue_struct *event_wq; |
| 297 | + void __iomem *iomem_base; |
| 298 | + struct work_struct notify_work; |
| 299 | + struct mutex pci_dev_mutex; |
| 300 | + struct pci_dev *pdev; |
| 301 | +}; |
| 302 | + |
| 303 | +/** |
| 304 | + * ne_do_request() - Submit command request to the PCI device based on the command |
| 305 | + * type and retrieve the associated reply. |
| 306 | + * @pdev: PCI device to send the command to and receive the reply from. |
| 307 | + * @cmd_type: Command type of the request sent to the PCI device. |
| 308 | + * @cmd_request: Command request payload. |
| 309 | + * @cmd_request_size: Size of the command request payload. |
| 310 | + * @cmd_reply: Command reply payload. |
| 311 | + * @cmd_reply_size: Size of the command reply payload. |
| 312 | + * |
| 313 | + * Context: Process context. This function uses the ne_pci_dev mutex to handle |
| 314 | + * one command at a time. |
| 315 | + * Return: |
| 316 | + * * 0 on success. |
| 317 | + * * Negative return value on failure. |
| 318 | + */ |
| 319 | +int ne_do_request(struct pci_dev *pdev, enum ne_pci_dev_cmd_type cmd_type, |
| 320 | + void *cmd_request, size_t cmd_request_size, |
| 321 | + struct ne_pci_dev_cmd_reply *cmd_reply, |
| 322 | + size_t cmd_reply_size); |
| 323 | + |
| 324 | +/* Nitro Enclaves (NE) PCI device driver */ |
| 325 | +extern struct pci_driver ne_pci_driver; |
| 326 | + |
| 327 | +#endif /* _NE_PCI_DEV_H_ */ |
0 commit comments