1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * Copyright 2020-2021 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 - Size of the send buffer, in bytes. |
88 | */ |
89 | #define NE_SEND_DATA_SIZE (240) |
90 | |
91 | /** |
92 | * NE_RECV_DATA_SIZE - Size of the receive buffer, in bytes. |
93 | */ |
94 | #define NE_RECV_DATA_SIZE (240) |
95 | |
96 | /** |
97 | * DOC: MSI-X interrupt vectors |
98 | */ |
99 | |
100 | /** |
101 | * NE_VEC_REPLY - MSI-X vector used for command reply notification. |
102 | */ |
103 | #define NE_VEC_REPLY (0) |
104 | |
105 | /** |
106 | * NE_VEC_EVENT - MSI-X vector used for out-of-band events e.g. enclave crash. |
107 | */ |
108 | #define NE_VEC_EVENT (1) |
109 | |
110 | /** |
111 | * enum ne_pci_dev_cmd_type - Device command types. |
112 | * @INVALID_CMD: Invalid command. |
113 | * @ENCLAVE_START: Start an enclave, after setting its resources. |
114 | * @ENCLAVE_GET_SLOT: Get the slot uid of an enclave. |
115 | * @ENCLAVE_STOP: Terminate an enclave. |
116 | * @SLOT_ALLOC : Allocate a slot for an enclave. |
117 | * @SLOT_FREE: Free the slot allocated for an enclave |
118 | * @SLOT_ADD_MEM: Add a memory region to an enclave slot. |
119 | * @SLOT_ADD_VCPU: Add a vCPU to an enclave slot. |
120 | * @SLOT_COUNT : Get the number of allocated slots. |
121 | * @NEXT_SLOT: Get the next slot in the list of allocated slots. |
122 | * @SLOT_INFO: Get the info for a slot e.g. slot uid, vCPUs count. |
123 | * @SLOT_ADD_BULK_VCPUS: Add a number of vCPUs, not providing CPU ids. |
124 | * @MAX_CMD: A gatekeeper for max possible command type. |
125 | */ |
126 | enum ne_pci_dev_cmd_type { |
127 | INVALID_CMD = 0, |
128 | ENCLAVE_START = 1, |
129 | ENCLAVE_GET_SLOT = 2, |
130 | ENCLAVE_STOP = 3, |
131 | SLOT_ALLOC = 4, |
132 | SLOT_FREE = 5, |
133 | SLOT_ADD_MEM = 6, |
134 | SLOT_ADD_VCPU = 7, |
135 | SLOT_COUNT = 8, |
136 | NEXT_SLOT = 9, |
137 | SLOT_INFO = 10, |
138 | SLOT_ADD_BULK_VCPUS = 11, |
139 | MAX_CMD, |
140 | }; |
141 | |
142 | /** |
143 | * DOC: Device commands - payload structure for requests and replies. |
144 | */ |
145 | |
146 | /** |
147 | * struct enclave_start_req - ENCLAVE_START request. |
148 | * @slot_uid: Slot unique id mapped to the enclave to start. |
149 | * @enclave_cid: Context ID (CID) for the enclave vsock device. |
150 | * If 0, CID is autogenerated. |
151 | * @flags: Flags for the enclave to start with (e.g. debug mode). |
152 | */ |
153 | struct enclave_start_req { |
154 | u64 slot_uid; |
155 | u64 enclave_cid; |
156 | u64 flags; |
157 | }; |
158 | |
159 | /** |
160 | * struct enclave_get_slot_req - ENCLAVE_GET_SLOT request. |
161 | * @enclave_cid: Context ID (CID) for the enclave vsock device. |
162 | */ |
163 | struct enclave_get_slot_req { |
164 | u64 enclave_cid; |
165 | }; |
166 | |
167 | /** |
168 | * struct enclave_stop_req - ENCLAVE_STOP request. |
169 | * @slot_uid: Slot unique id mapped to the enclave to stop. |
170 | */ |
171 | struct enclave_stop_req { |
172 | u64 slot_uid; |
173 | }; |
174 | |
175 | /** |
176 | * struct slot_alloc_req - SLOT_ALLOC request. |
177 | * @unused: In order to avoid weird sizeof edge cases. |
178 | */ |
179 | struct slot_alloc_req { |
180 | u8 unused; |
181 | }; |
182 | |
183 | /** |
184 | * struct slot_free_req - SLOT_FREE request. |
185 | * @slot_uid: Slot unique id mapped to the slot to free. |
186 | */ |
187 | struct slot_free_req { |
188 | u64 slot_uid; |
189 | }; |
190 | |
191 | /* TODO: Add flags field to the request to add memory region. */ |
192 | /** |
193 | * struct slot_add_mem_req - SLOT_ADD_MEM request. |
194 | * @slot_uid: Slot unique id mapped to the slot to add the memory region to. |
195 | * @paddr: Physical address of the memory region to add to the slot. |
196 | * @size: Memory size, in bytes, of the memory region to add to the slot. |
197 | */ |
198 | struct slot_add_mem_req { |
199 | u64 slot_uid; |
200 | u64 paddr; |
201 | u64 size; |
202 | }; |
203 | |
204 | /** |
205 | * struct slot_add_vcpu_req - SLOT_ADD_VCPU request. |
206 | * @slot_uid: Slot unique id mapped to the slot to add the vCPU to. |
207 | * @vcpu_id: vCPU ID of the CPU to add to the enclave. |
208 | * @padding: Padding for the overall data structure. |
209 | */ |
210 | struct slot_add_vcpu_req { |
211 | u64 slot_uid; |
212 | u32 vcpu_id; |
213 | u8 padding[4]; |
214 | }; |
215 | |
216 | /** |
217 | * struct slot_count_req - SLOT_COUNT request. |
218 | * @unused: In order to avoid weird sizeof edge cases. |
219 | */ |
220 | struct slot_count_req { |
221 | u8 unused; |
222 | }; |
223 | |
224 | /** |
225 | * struct next_slot_req - NEXT_SLOT request. |
226 | * @slot_uid: Slot unique id of the next slot in the iteration. |
227 | */ |
228 | struct next_slot_req { |
229 | u64 slot_uid; |
230 | }; |
231 | |
232 | /** |
233 | * struct slot_info_req - SLOT_INFO request. |
234 | * @slot_uid: Slot unique id mapped to the slot to get information about. |
235 | */ |
236 | struct slot_info_req { |
237 | u64 slot_uid; |
238 | }; |
239 | |
240 | /** |
241 | * struct slot_add_bulk_vcpus_req - SLOT_ADD_BULK_VCPUS request. |
242 | * @slot_uid: Slot unique id mapped to the slot to add vCPUs to. |
243 | * @nr_vcpus: Number of vCPUs to add to the slot. |
244 | */ |
245 | struct slot_add_bulk_vcpus_req { |
246 | u64 slot_uid; |
247 | u64 nr_vcpus; |
248 | }; |
249 | |
250 | /** |
251 | * struct ne_pci_dev_cmd_reply - NE PCI device command reply. |
252 | * @rc : Return code of the logic that processed the request. |
253 | * @padding0: Padding for the overall data structure. |
254 | * @slot_uid: Valid for all commands except SLOT_COUNT. |
255 | * @enclave_cid: Valid for ENCLAVE_START command. |
256 | * @slot_count : Valid for SLOT_COUNT command. |
257 | * @mem_regions: Valid for SLOT_ALLOC and SLOT_INFO commands. |
258 | * @mem_size: Valid for SLOT_INFO command. |
259 | * @nr_vcpus: Valid for SLOT_INFO command. |
260 | * @flags: Valid for SLOT_INFO command. |
261 | * @state: Valid for SLOT_INFO command. |
262 | * @padding1: Padding for the overall data structure. |
263 | */ |
264 | struct ne_pci_dev_cmd_reply { |
265 | s32 rc; |
266 | u8 padding0[4]; |
267 | u64 slot_uid; |
268 | u64 enclave_cid; |
269 | u64 slot_count; |
270 | u64 mem_regions; |
271 | u64 mem_size; |
272 | u64 nr_vcpus; |
273 | u64 flags; |
274 | u16 state; |
275 | u8 padding1[6]; |
276 | }; |
277 | |
278 | /** |
279 | * struct ne_pci_dev - Nitro Enclaves (NE) PCI device. |
280 | * @cmd_reply_avail: Variable set if a reply has been sent by the |
281 | * PCI device. |
282 | * @cmd_reply_wait_q: Wait queue for handling command reply from the |
283 | * PCI device. |
284 | * @enclaves_list: List of the enclaves managed by the PCI device. |
285 | * @enclaves_list_mutex: Mutex for accessing the list of enclaves. |
286 | * @event_wq: Work queue for handling out-of-band events |
287 | * triggered by the Nitro Hypervisor which require |
288 | * enclave state scanning and propagation to the |
289 | * enclave process. |
290 | * @iomem_base : MMIO region of the PCI device. |
291 | * @notify_work: Work item for every received out-of-band event. |
292 | * @pci_dev_mutex: Mutex for accessing the PCI device MMIO space. |
293 | * @pdev: PCI device data structure. |
294 | */ |
295 | struct ne_pci_dev { |
296 | atomic_t cmd_reply_avail; |
297 | wait_queue_head_t cmd_reply_wait_q; |
298 | struct list_head enclaves_list; |
299 | struct mutex enclaves_list_mutex; |
300 | struct workqueue_struct *event_wq; |
301 | void __iomem *iomem_base; |
302 | struct work_struct notify_work; |
303 | struct mutex pci_dev_mutex; |
304 | struct pci_dev *pdev; |
305 | }; |
306 | |
307 | /** |
308 | * ne_do_request() - Submit command request to the PCI device based on the command |
309 | * type and retrieve the associated reply. |
310 | * @pdev: PCI device to send the command to and receive the reply from. |
311 | * @cmd_type: Command type of the request sent to the PCI device. |
312 | * @cmd_request: Command request payload. |
313 | * @cmd_request_size: Size of the command request payload. |
314 | * @cmd_reply: Command reply payload. |
315 | * @cmd_reply_size: Size of the command reply payload. |
316 | * |
317 | * Context: Process context. This function uses the ne_pci_dev mutex to handle |
318 | * one command at a time. |
319 | * Return: |
320 | * * 0 on success. |
321 | * * Negative return value on failure. |
322 | */ |
323 | int ne_do_request(struct pci_dev *pdev, enum ne_pci_dev_cmd_type cmd_type, |
324 | void *cmd_request, size_t cmd_request_size, |
325 | struct ne_pci_dev_cmd_reply *cmd_reply, |
326 | size_t cmd_reply_size); |
327 | |
328 | /* Nitro Enclaves (NE) PCI device driver */ |
329 | extern struct pci_driver ne_pci_driver; |
330 | |
331 | #endif /* _NE_PCI_DEV_H_ */ |
332 | |