| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Copyright 2020-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| */ |
| |
| #ifndef _NE_PCI_DEV_H_ |
| #define _NE_PCI_DEV_H_ |
| |
| #include <linux/atomic.h> |
| #include <linux/list.h> |
| #include <linux/mutex.h> |
| #include <linux/pci.h> |
| #include <linux/pci_ids.h> |
| #include <linux/wait.h> |
| |
| /** |
| * DOC: Nitro Enclaves (NE) PCI device |
| */ |
| |
| /** |
| * PCI_DEVICE_ID_NE - Nitro Enclaves PCI device id. |
| */ |
| #define PCI_DEVICE_ID_NE (0xe4c1) |
| /** |
| * PCI_BAR_NE - Nitro Enclaves PCI device MMIO BAR. |
| */ |
| #define PCI_BAR_NE (0x03) |
| |
| /** |
| * DOC: Device registers in the NE PCI device MMIO BAR |
| */ |
| |
| /** |
| * NE_ENABLE - (1 byte) Register to notify the device that the driver is using |
| * it (Read/Write). |
| */ |
| #define NE_ENABLE (0x0000) |
| #define NE_ENABLE_OFF (0x00) |
| #define NE_ENABLE_ON (0x01) |
| |
| /** |
| * NE_VERSION - (2 bytes) Register to select the device run-time version |
| * (Read/Write). |
| */ |
| #define NE_VERSION (0x0002) |
| #define NE_VERSION_MAX (0x0001) |
| |
| /** |
| * NE_COMMAND - (4 bytes) Register to notify the device what command was |
| * requested (Write-Only). |
| */ |
| #define NE_COMMAND (0x0004) |
| |
| /** |
| * NE_EVTCNT - (4 bytes) Register to notify the driver that a reply or a device |
| * event is available (Read-Only): |
| * - Lower half - command reply counter |
| * - Higher half - out-of-band device event counter |
| */ |
| #define NE_EVTCNT (0x000c) |
| #define NE_EVTCNT_REPLY_SHIFT (0) |
| #define NE_EVTCNT_REPLY_MASK (0x0000ffff) |
| #define NE_EVTCNT_REPLY(cnt) (((cnt) & NE_EVTCNT_REPLY_MASK) >> \ |
| NE_EVTCNT_REPLY_SHIFT) |
| #define NE_EVTCNT_EVENT_SHIFT (16) |
| #define NE_EVTCNT_EVENT_MASK (0xffff0000) |
| #define NE_EVTCNT_EVENT(cnt) (((cnt) & NE_EVTCNT_EVENT_MASK) >> \ |
| NE_EVTCNT_EVENT_SHIFT) |
| |
| /** |
| * NE_SEND_DATA - (240 bytes) Buffer for sending the command request payload |
| * (Read/Write). |
| */ |
| #define NE_SEND_DATA (0x0010) |
| |
| /** |
| * NE_RECV_DATA - (240 bytes) Buffer for receiving the command reply payload |
| * (Read-Only). |
| */ |
| #define NE_RECV_DATA (0x0100) |
| |
| /** |
| * DOC: Device MMIO buffer sizes |
| */ |
| |
| /** |
| * NE_SEND_DATA_SIZE - Size of the send buffer, in bytes. |
| */ |
| #define NE_SEND_DATA_SIZE (240) |
| |
| /** |
| * NE_RECV_DATA_SIZE - Size of the receive buffer, in bytes. |
| */ |
| #define NE_RECV_DATA_SIZE (240) |
| |
| /** |
| * DOC: MSI-X interrupt vectors |
| */ |
| |
| /** |
| * NE_VEC_REPLY - MSI-X vector used for command reply notification. |
| */ |
| #define NE_VEC_REPLY (0) |
| |
| /** |
| * NE_VEC_EVENT - MSI-X vector used for out-of-band events e.g. enclave crash. |
| */ |
| #define NE_VEC_EVENT (1) |
| |
| /** |
| * enum ne_pci_dev_cmd_type - Device command types. |
| * @INVALID_CMD: Invalid command. |
| * @ENCLAVE_START: Start an enclave, after setting its resources. |
| * @ENCLAVE_GET_SLOT: Get the slot uid of an enclave. |
| * @ENCLAVE_STOP: Terminate an enclave. |
| * @SLOT_ALLOC : Allocate a slot for an enclave. |
| * @SLOT_FREE: Free the slot allocated for an enclave |
| * @SLOT_ADD_MEM: Add a memory region to an enclave slot. |
| * @SLOT_ADD_VCPU: Add a vCPU to an enclave slot. |
| * @SLOT_COUNT : Get the number of allocated slots. |
| * @NEXT_SLOT: Get the next slot in the list of allocated slots. |
| * @SLOT_INFO: Get the info for a slot e.g. slot uid, vCPUs count. |
| * @SLOT_ADD_BULK_VCPUS: Add a number of vCPUs, not providing CPU ids. |
| * @MAX_CMD: A gatekeeper for max possible command type. |
| */ |
| enum ne_pci_dev_cmd_type { |
| INVALID_CMD = 0, |
| ENCLAVE_START = 1, |
| ENCLAVE_GET_SLOT = 2, |
| ENCLAVE_STOP = 3, |
| SLOT_ALLOC = 4, |
| SLOT_FREE = 5, |
| SLOT_ADD_MEM = 6, |
| SLOT_ADD_VCPU = 7, |
| SLOT_COUNT = 8, |
| NEXT_SLOT = 9, |
| SLOT_INFO = 10, |
| SLOT_ADD_BULK_VCPUS = 11, |
| MAX_CMD, |
| }; |
| |
| /** |
| * DOC: Device commands - payload structure for requests and replies. |
| */ |
| |
| /** |
| * struct enclave_start_req - ENCLAVE_START request. |
| * @slot_uid: Slot unique id mapped to the enclave to start. |
| * @enclave_cid: Context ID (CID) for the enclave vsock device. |
| * If 0, CID is autogenerated. |
| * @flags: Flags for the enclave to start with (e.g. debug mode). |
| */ |
| struct enclave_start_req { |
| u64 slot_uid; |
| u64 enclave_cid; |
| u64 flags; |
| }; |
| |
| /** |
| * struct enclave_get_slot_req - ENCLAVE_GET_SLOT request. |
| * @enclave_cid: Context ID (CID) for the enclave vsock device. |
| */ |
| struct enclave_get_slot_req { |
| u64 enclave_cid; |
| }; |
| |
| /** |
| * struct enclave_stop_req - ENCLAVE_STOP request. |
| * @slot_uid: Slot unique id mapped to the enclave to stop. |
| */ |
| struct enclave_stop_req { |
| u64 slot_uid; |
| }; |
| |
| /** |
| * struct slot_alloc_req - SLOT_ALLOC request. |
| * @unused: In order to avoid weird sizeof edge cases. |
| */ |
| struct slot_alloc_req { |
| u8 unused; |
| }; |
| |
| /** |
| * struct slot_free_req - SLOT_FREE request. |
| * @slot_uid: Slot unique id mapped to the slot to free. |
| */ |
| struct slot_free_req { |
| u64 slot_uid; |
| }; |
| |
| /* TODO: Add flags field to the request to add memory region. */ |
| /** |
| * struct slot_add_mem_req - SLOT_ADD_MEM request. |
| * @slot_uid: Slot unique id mapped to the slot to add the memory region to. |
| * @paddr: Physical address of the memory region to add to the slot. |
| * @size: Memory size, in bytes, of the memory region to add to the slot. |
| */ |
| struct slot_add_mem_req { |
| u64 slot_uid; |
| u64 paddr; |
| u64 size; |
| }; |
| |
| /** |
| * struct slot_add_vcpu_req - SLOT_ADD_VCPU request. |
| * @slot_uid: Slot unique id mapped to the slot to add the vCPU to. |
| * @vcpu_id: vCPU ID of the CPU to add to the enclave. |
| * @padding: Padding for the overall data structure. |
| */ |
| struct slot_add_vcpu_req { |
| u64 slot_uid; |
| u32 vcpu_id; |
| u8 padding[4]; |
| }; |
| |
| /** |
| * struct slot_count_req - SLOT_COUNT request. |
| * @unused: In order to avoid weird sizeof edge cases. |
| */ |
| struct slot_count_req { |
| u8 unused; |
| }; |
| |
| /** |
| * struct next_slot_req - NEXT_SLOT request. |
| * @slot_uid: Slot unique id of the next slot in the iteration. |
| */ |
| struct next_slot_req { |
| u64 slot_uid; |
| }; |
| |
| /** |
| * struct slot_info_req - SLOT_INFO request. |
| * @slot_uid: Slot unique id mapped to the slot to get information about. |
| */ |
| struct slot_info_req { |
| u64 slot_uid; |
| }; |
| |
| /** |
| * struct slot_add_bulk_vcpus_req - SLOT_ADD_BULK_VCPUS request. |
| * @slot_uid: Slot unique id mapped to the slot to add vCPUs to. |
| * @nr_vcpus: Number of vCPUs to add to the slot. |
| */ |
| struct slot_add_bulk_vcpus_req { |
| u64 slot_uid; |
| u64 nr_vcpus; |
| }; |
| |
| /** |
| * struct ne_pci_dev_cmd_reply - NE PCI device command reply. |
| * @rc : Return code of the logic that processed the request. |
| * @padding0: Padding for the overall data structure. |
| * @slot_uid: Valid for all commands except SLOT_COUNT. |
| * @enclave_cid: Valid for ENCLAVE_START command. |
| * @slot_count : Valid for SLOT_COUNT command. |
| * @mem_regions: Valid for SLOT_ALLOC and SLOT_INFO commands. |
| * @mem_size: Valid for SLOT_INFO command. |
| * @nr_vcpus: Valid for SLOT_INFO command. |
| * @flags: Valid for SLOT_INFO command. |
| * @state: Valid for SLOT_INFO command. |
| * @padding1: Padding for the overall data structure. |
| */ |
| struct ne_pci_dev_cmd_reply { |
| s32 rc; |
| u8 padding0[4]; |
| u64 slot_uid; |
| u64 enclave_cid; |
| u64 slot_count; |
| u64 mem_regions; |
| u64 mem_size; |
| u64 nr_vcpus; |
| u64 flags; |
| u16 state; |
| u8 padding1[6]; |
| }; |
| |
| /** |
| * struct ne_pci_dev - Nitro Enclaves (NE) PCI device. |
| * @cmd_reply_avail: Variable set if a reply has been sent by the |
| * PCI device. |
| * @cmd_reply_wait_q: Wait queue for handling command reply from the |
| * PCI device. |
| * @enclaves_list: List of the enclaves managed by the PCI device. |
| * @enclaves_list_mutex: Mutex for accessing the list of enclaves. |
| * @event_wq: Work queue for handling out-of-band events |
| * triggered by the Nitro Hypervisor which require |
| * enclave state scanning and propagation to the |
| * enclave process. |
| * @iomem_base : MMIO region of the PCI device. |
| * @notify_work: Work item for every received out-of-band event. |
| * @pci_dev_mutex: Mutex for accessing the PCI device MMIO space. |
| * @pdev: PCI device data structure. |
| */ |
| struct ne_pci_dev { |
| atomic_t cmd_reply_avail; |
| wait_queue_head_t cmd_reply_wait_q; |
| struct list_head enclaves_list; |
| struct mutex enclaves_list_mutex; |
| struct workqueue_struct *event_wq; |
| void __iomem *iomem_base; |
| struct work_struct notify_work; |
| struct mutex pci_dev_mutex; |
| struct pci_dev *pdev; |
| }; |
| |
| /** |
| * ne_do_request() - Submit command request to the PCI device based on the command |
| * type and retrieve the associated reply. |
| * @pdev: PCI device to send the command to and receive the reply from. |
| * @cmd_type: Command type of the request sent to the PCI device. |
| * @cmd_request: Command request payload. |
| * @cmd_request_size: Size of the command request payload. |
| * @cmd_reply: Command reply payload. |
| * @cmd_reply_size: Size of the command reply payload. |
| * |
| * Context: Process context. This function uses the ne_pci_dev mutex to handle |
| * one command at a time. |
| * Return: |
| * * 0 on success. |
| * * Negative return value on failure. |
| */ |
| int ne_do_request(struct pci_dev *pdev, enum ne_pci_dev_cmd_type cmd_type, |
| void *cmd_request, size_t cmd_request_size, |
| struct ne_pci_dev_cmd_reply *cmd_reply, |
| size_t cmd_reply_size); |
| |
| /* Nitro Enclaves (NE) PCI device driver */ |
| extern struct pci_driver ne_pci_driver; |
| |
| #endif /* _NE_PCI_DEV_H_ */ |