/* 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_ */