328 lines
8.7 KiB
C
328 lines
8.7 KiB
C
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
/*
|
||
|
* Copyright 2020 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 / NE_RECV_DATA_SIZE - 240 bytes for send / recv buffer.
|
||
|
*/
|
||
|
#define NE_SEND_DATA_SIZE (240)
|
||
|
#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_ */
|