diff --git a/sys/dev/vmware/vmci/vmci_defs.h b/sys/dev/vmware/vmci/vmci_defs.h index cfa302ad11aa..466712c41cee 100644 --- a/sys/dev/vmware/vmci/vmci_defs.h +++ b/sys/dev/vmware/vmci/vmci_defs.h @@ -1,714 +1,714 @@ /*- * Copyright (c) 2018 VMware, Inc. * * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0) */ #ifndef _VMCI_DEFS_H_ #define _VMCI_DEFS_H_ #include #include #include "vmci_kernel_defs.h" #pragma GCC diagnostic ignored "-Wcast-qual" /* Register offsets. */ #define VMCI_STATUS_ADDR 0x00 #define VMCI_CONTROL_ADDR 0x04 #define VMCI_ICR_ADDR 0x08 #define VMCI_IMR_ADDR 0x0c #define VMCI_DATA_OUT_ADDR 0x10 #define VMCI_DATA_IN_ADDR 0x14 #define VMCI_CAPS_ADDR 0x18 #define VMCI_RESULT_LOW_ADDR 0x1c #define VMCI_RESULT_HIGH_ADDR 0x20 /* Status register bits. */ #define VMCI_STATUS_INT_ON 0x1 /* Control register bits. */ #define VMCI_CONTROL_RESET 0x1 #define VMCI_CONTROL_INT_ENABLE 0x2 #define VMCI_CONTROL_INT_DISABLE 0x4 /* Capabilities register bits. */ #define VMCI_CAPS_HYPERCALL 0x1 #define VMCI_CAPS_GUESTCALL 0x2 #define VMCI_CAPS_DATAGRAM 0x4 #define VMCI_CAPS_NOTIFICATIONS 0x8 /* Interrupt Cause register bits. */ #define VMCI_ICR_DATAGRAM 0x1 #define VMCI_ICR_NOTIFICATION 0x2 /* Interrupt Mask register bits. */ #define VMCI_IMR_DATAGRAM 0x1 #define VMCI_IMR_NOTIFICATION 0x2 /* Interrupt type. */ typedef enum vmci_intr_type { VMCI_INTR_TYPE_INTX = 0, VMCI_INTR_TYPE_MSI = 1, VMCI_INTR_TYPE_MSIX = 2 } vmci_intr_type; /* * Maximum MSI/MSI-X interrupt vectors in the device. */ #define VMCI_MAX_INTRS 2 /* * Supported interrupt vectors. There is one for each ICR value above, * but here they indicate the position in the vector array/message ID. */ #define VMCI_INTR_DATAGRAM 0 #define VMCI_INTR_NOTIFICATION 1 /* * A single VMCI device has an upper limit of 128 MiB on the amount of * memory that can be used for queue pairs. */ #define VMCI_MAX_GUEST_QP_MEMORY (128 * 1024 * 1024) /* * We have a fixed set of resource IDs available in the VMX. * This allows us to have a very simple implementation since we statically * know how many will create datagram handles. If a new caller arrives and * we have run out of slots we can manually increment the maximum size of * available resource IDs. */ typedef uint32_t vmci_resource; /* VMCI reserved hypervisor datagram resource IDs. */ #define VMCI_RESOURCES_QUERY 0 #define VMCI_GET_CONTEXT_ID 1 #define VMCI_SET_NOTIFY_BITMAP 2 #define VMCI_DOORBELL_LINK 3 #define VMCI_DOORBELL_UNLINK 4 #define VMCI_DOORBELL_NOTIFY 5 /* * VMCI_DATAGRAM_REQUEST_MAP and VMCI_DATAGRAM_REMOVE_MAP are * obsoleted by the removal of VM to VM communication. */ #define VMCI_DATAGRAM_REQUEST_MAP 6 #define VMCI_DATAGRAM_REMOVE_MAP 7 #define VMCI_EVENT_SUBSCRIBE 8 #define VMCI_EVENT_UNSUBSCRIBE 9 #define VMCI_QUEUEPAIR_ALLOC 10 #define VMCI_QUEUEPAIR_DETACH 11 /* * VMCI_VSOCK_VMX_LOOKUP was assigned to 12 for Fusion 3.0/3.1, * WS 7.0/7.1 and ESX 4.1 */ #define VMCI_HGFS_TRANSPORT 13 #define VMCI_UNITY_PBRPC_REGISTER 14 /* * This resource is used for VMCI socket control packets sent to the * hypervisor (CID 0) because RID 1 is already reserved. */ #define VSOCK_PACKET_HYPERVISOR_RID 15 #define VMCI_RESOURCE_MAX 16 /* * The core VMCI device functionality only requires the resource IDs of * VMCI_QUEUEPAIR_DETACH and below. */ #define VMCI_CORE_DEVICE_RESOURCE_MAX VMCI_QUEUEPAIR_DETACH /* * VMCI reserved host datagram resource IDs. * vsock control channel has resource id 1. */ #define VMCI_DVFILTER_DATA_PATH_DATAGRAM 2 /* VMCI Ids. */ typedef uint32_t vmci_id; struct vmci_id_range { int8_t action; /* VMCI_FA_X, for use in filters. */ vmci_id begin; /* Beginning of range. */ vmci_id end; /* End of range. */ }; struct vmci_handle { vmci_id context; vmci_id resource; }; static inline struct vmci_handle VMCI_MAKE_HANDLE(vmci_id cid, vmci_id rid) { struct vmci_handle h; h.context = cid; h.resource = rid; return (h); } #define VMCI_HANDLE_TO_CONTEXT_ID(_handle) \ ((_handle).context) #define VMCI_HANDLE_TO_RESOURCE_ID(_handle) \ ((_handle).resource) #define VMCI_HANDLE_EQUAL(_h1, _h2) \ ((_h1).context == (_h2).context && (_h1).resource == (_h2).resource) #define VMCI_INVALID_ID 0xFFFFFFFF static const struct vmci_handle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID, VMCI_INVALID_ID}; #define VMCI_HANDLE_INVALID(_handle) \ VMCI_HANDLE_EQUAL((_handle), VMCI_INVALID_HANDLE) /* * The below defines can be used to send anonymous requests. * This also indicates that no response is expected. */ #define VMCI_ANON_SRC_CONTEXT_ID \ VMCI_INVALID_ID #define VMCI_ANON_SRC_RESOURCE_ID \ VMCI_INVALID_ID #define VMCI_ANON_SRC_HANDLE \ VMCI_MAKE_HANDLE(VMCI_ANON_SRC_CONTEXT_ID, \ VMCI_ANON_SRC_RESOURCE_ID) /* The lowest 16 context ids are reserved for internal use. */ #define VMCI_RESERVED_CID_LIMIT 16 /* * Hypervisor context id, used for calling into hypervisor * supplied services from the VM. */ #define VMCI_HYPERVISOR_CONTEXT_ID 0 /* * Well-known context id, a logical context that contains a set of * well-known services. This context ID is now obsolete. */ #define VMCI_WELL_KNOWN_CONTEXT_ID 1 /* * Context ID used by host endpoints. */ #define VMCI_HOST_CONTEXT_ID 2 #define VMCI_HOST_CONTEXT_INVALID_EVENT ((uintptr_t)~0) #define VMCI_CONTEXT_IS_VM(_cid) \ (VMCI_INVALID_ID != _cid && _cid > VMCI_HOST_CONTEXT_ID) /* * The VMCI_CONTEXT_RESOURCE_ID is used together with VMCI_MAKE_HANDLE to make * handles that refer to a specific context. */ #define VMCI_CONTEXT_RESOURCE_ID 0 /* *------------------------------------------------------------------------------ * * VMCI error codes. * *------------------------------------------------------------------------------ */ #define VMCI_SUCCESS_QUEUEPAIR_ATTACH 5 #define VMCI_SUCCESS_QUEUEPAIR_CREATE 4 #define VMCI_SUCCESS_LAST_DETACH 3 #define VMCI_SUCCESS_ACCESS_GRANTED 2 #define VMCI_SUCCESS_ENTRY_DEAD 1 #define VMCI_SUCCESS 0LL #define VMCI_ERROR_INVALID_RESOURCE (-1) #define VMCI_ERROR_INVALID_ARGS (-2) #define VMCI_ERROR_NO_MEM (-3) #define VMCI_ERROR_DATAGRAM_FAILED (-4) #define VMCI_ERROR_MORE_DATA (-5) #define VMCI_ERROR_NO_MORE_DATAGRAMS (-6) #define VMCI_ERROR_NO_ACCESS (-7) #define VMCI_ERROR_NO_HANDLE (-8) #define VMCI_ERROR_DUPLICATE_ENTRY (-9) #define VMCI_ERROR_DST_UNREACHABLE (-10) #define VMCI_ERROR_PAYLOAD_TOO_LARGE (-11) #define VMCI_ERROR_INVALID_PRIV (-12) #define VMCI_ERROR_GENERIC (-13) #define VMCI_ERROR_PAGE_ALREADY_SHARED (-14) #define VMCI_ERROR_CANNOT_SHARE_PAGE (-15) #define VMCI_ERROR_CANNOT_UNSHARE_PAGE (-16) #define VMCI_ERROR_NO_PROCESS (-17) #define VMCI_ERROR_NO_DATAGRAM (-18) #define VMCI_ERROR_NO_RESOURCES (-19) #define VMCI_ERROR_UNAVAILABLE (-20) #define VMCI_ERROR_NOT_FOUND (-21) #define VMCI_ERROR_ALREADY_EXISTS (-22) #define VMCI_ERROR_NOT_PAGE_ALIGNED (-23) #define VMCI_ERROR_INVALID_SIZE (-24) #define VMCI_ERROR_REGION_ALREADY_SHARED (-25) #define VMCI_ERROR_TIMEOUT (-26) #define VMCI_ERROR_DATAGRAM_INCOMPLETE (-27) #define VMCI_ERROR_INCORRECT_IRQL (-28) #define VMCI_ERROR_EVENT_UNKNOWN (-29) #define VMCI_ERROR_OBSOLETE (-30) #define VMCI_ERROR_QUEUEPAIR_MISMATCH (-31) #define VMCI_ERROR_QUEUEPAIR_NOTSET (-32) #define VMCI_ERROR_QUEUEPAIR_NOTOWNER (-33) #define VMCI_ERROR_QUEUEPAIR_NOTATTACHED (-34) #define VMCI_ERROR_QUEUEPAIR_NOSPACE (-35) #define VMCI_ERROR_QUEUEPAIR_NODATA (-36) #define VMCI_ERROR_BUSMEM_INVALIDATION (-37) #define VMCI_ERROR_MODULE_NOT_LOADED (-38) #define VMCI_ERROR_DEVICE_NOT_FOUND (-39) #define VMCI_ERROR_QUEUEPAIR_NOT_READY (-40) #define VMCI_ERROR_WOULD_BLOCK (-41) -/* VMCI clients should return error code withing this range */ +/* VMCI clients should return error code within this range */ #define VMCI_ERROR_CLIENT_MIN (-500) #define VMCI_ERROR_CLIENT_MAX (-550) /* Internal error codes. */ #define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT (-1000) #define VMCI_PATH_MAX 256 /* VMCI reserved events. */ typedef uint32_t vmci_event_type; #define VMCI_EVENT_CTX_ID_UPDATE 0 // Only applicable to guest // endpoints #define VMCI_EVENT_CTX_REMOVED 1 // Applicable to guest and host #define VMCI_EVENT_QP_RESUMED 2 // Only applicable to guest // endpoints #define VMCI_EVENT_QP_PEER_ATTACH 3 // Applicable to guest, host // and VMX #define VMCI_EVENT_QP_PEER_DETACH 4 // Applicable to guest, host // and VMX #define VMCI_EVENT_MEM_ACCESS_ON 5 // Applicable to VMX and vmk. On // vmk, this event has the // Context payload type #define VMCI_EVENT_MEM_ACCESS_OFF 6 // Applicable to VMX and vmk. // Same as above for the payload // type #define VMCI_EVENT_GUEST_PAUSED 7 // Applicable to vmk. This // event has the Context // payload type #define VMCI_EVENT_GUEST_UNPAUSED 8 // Applicable to vmk. Same as // above for the payload type. #define VMCI_EVENT_MAX 9 /* * Of the above events, a few are reserved for use in the VMX, and other * endpoints (guest and host kernel) should not use them. For the rest of the * events, we allow both host and guest endpoints to subscribe to them, to * maintain the same API for host and guest endpoints. */ #define VMCI_EVENT_VALID_VMX(_event) \ (_event == VMCI_EVENT_QP_PEER_ATTACH || \ _event == VMCI_EVENT_QP_PEER_DETACH || \ _event == VMCI_EVENT_MEM_ACCESS_ON || \ _event == VMCI_EVENT_MEM_ACCESS_OFF) #define VMCI_EVENT_VALID(_event) \ (_event < VMCI_EVENT_MAX && \ _event != VMCI_EVENT_MEM_ACCESS_ON && \ _event != VMCI_EVENT_MEM_ACCESS_OFF && \ _event != VMCI_EVENT_GUEST_PAUSED && \ _event != VMCI_EVENT_GUEST_UNPAUSED) /* Reserved guest datagram resource ids. */ #define VMCI_EVENT_HANDLER 0 /* * VMCI coarse-grained privileges (per context or host process/endpoint. An * entity with the restricted flag is only allowed to interact with the * hypervisor and trusted entities. */ typedef uint32_t vmci_privilege_flags; #define VMCI_PRIVILEGE_FLAG_RESTRICTED 0x01 #define VMCI_PRIVILEGE_FLAG_TRUSTED 0x02 #define VMCI_PRIVILEGE_ALL_FLAGS \ (VMCI_PRIVILEGE_FLAG_RESTRICTED | VMCI_PRIVILEGE_FLAG_TRUSTED) #define VMCI_NO_PRIVILEGE_FLAGS 0x00 #define VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS VMCI_NO_PRIVILEGE_FLAGS #define VMCI_LEAST_PRIVILEGE_FLAGS VMCI_PRIVILEGE_FLAG_RESTRICTED #define VMCI_MAX_PRIVILEGE_FLAGS VMCI_PRIVILEGE_FLAG_TRUSTED /* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */ #define VMCI_RESERVED_RESOURCE_ID_MAX 1023 #define VMCI_DOMAIN_NAME_MAXLEN 32 #define VMCI_LGPFX "vmci: " /* * struct vmci_queue_header * * A Queue cannot stand by itself as designed. Each Queue's header contains a * pointer into itself (the producer_tail) and into its peer (consumer_head). * The reason for the separation is one of accessibility: Each end-point can * modify two things: where the next location to enqueue is within its produce_q * (producer_tail); and where the next dequeue location is in its consume_q * (consumer_head). * * An end-point cannot modify the pointers of its peer (guest to guest; NOTE * that in the host both queue headers are mapped r/w). But, each end-point * needs read access to both Queue header structures in order to determine how * much space is used (or left) in the Queue. This is because for an end-point * to know how full its produce_q is, it needs to use the consumer_head that * points into the produce_q but -that- consumer_head is in the Queue header * for that end-points consume_q. * * Thoroughly confused? Sorry. * * producer_tail: the point to enqueue new entrants. When you approach a line * in a store, for example, you walk up to the tail. * * consumer_head: the point in the queue from which the next element is * dequeued. In other words, who is next in line is he who is at the head of * the line. * * Also, producer_tail points to an empty byte in the Queue, whereas * consumer_head points to a valid byte of data (unless producer_tail == * consumer_head in which case consumerHead does not point to a valid byte of * data). * * For a queue of buffer 'size' bytes, the tail and head pointers will be in * the range [0, size-1]. * * If produce_q_header->producer_tail == consume_q_header->consumer_head then * the produce_q is empty. */ struct vmci_queue_header { /* All fields are 64bit and aligned. */ struct vmci_handle handle; /* Identifier. */ volatile uint64_t producer_tail; /* Offset in this queue. */ volatile uint64_t consumer_head; /* Offset in peer queue. */ }; /* * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair * size to be less than 4GB, and use 32bit atomic operations on the head and * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which * is an atomic read-modify-write. This will cause traces to fire when a 32bit * consumer tries to read the producer's tail pointer, for example, because the * consumer has read-only access to the producer's tail pointer. * * We provide the following macros to invoke 32bit or 64bit atomic operations * based on the architecture the code is being compiled on. */ #ifdef __x86_64__ #define QP_MAX_QUEUE_SIZE_ARCH CONST64U(0xffffffffffffffff) #define qp_atomic_read_offset(x) atomic_load_64(x) #define qp_atomic_write_offset(x, y) atomic_store_64(x, y) #else /* __x86_64__ */ /* * Wrappers below are being used because atomic_store_ operates * on a specific . Likewise for atomic_load_ */ static inline uint32_t type_safe_atomic_read_32(void *var) { return (atomic_load_32((volatile uint32_t *)(var))); } static inline void type_safe_atomic_write_32(void *var, uint32_t val) { atomic_store_32((volatile uint32_t *)(var), (uint32_t)(val)); } #define QP_MAX_QUEUE_SIZE_ARCH CONST64U(0xffffffff) #define qp_atomic_read_offset(x) type_safe_atomic_read_32((void *)(x)) #define qp_atomic_write_offset(x, y) \ type_safe_atomic_write_32((void *)(x), (uint32_t)(y)) #endif /* __x86_64__ */ /* *------------------------------------------------------------------------------ * * qp_add_pointer -- * * Helper to add a given offset to a head or tail pointer. Wraps the value * of the pointer around the max size of the queue. * * Results: * None. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline void qp_add_pointer(volatile uint64_t *var, size_t add, uint64_t size) { uint64_t new_val = qp_atomic_read_offset(var); if (new_val >= size - add) new_val -= size; new_val += add; qp_atomic_write_offset(var, new_val); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_producer_tail -- * * Helper routine to get the Producer Tail from the supplied queue. * * Results: * The contents of the queue's producer tail. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline uint64_t vmci_queue_header_producer_tail(const struct vmci_queue_header *q_header) { struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header; return (qp_atomic_read_offset(&qh->producer_tail)); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_consumer_head -- * * Helper routine to get the Consumer Head from the supplied queue. * * Results: * The contents of the queue's consumer tail. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline uint64_t vmci_queue_header_consumer_head(const struct vmci_queue_header *q_header) { struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header; return (qp_atomic_read_offset(&qh->consumer_head)); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_add_producer_tail -- * * Helper routine to increment the Producer Tail. Fundamentally, * qp_add_pointer() is used to manipulate the tail itself. * * Results: * None. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline void vmci_queue_header_add_producer_tail(struct vmci_queue_header *q_header, size_t add, uint64_t queue_size) { qp_add_pointer(&q_header->producer_tail, add, queue_size); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_add_consumer_head -- * * Helper routine to increment the Consumer Head. Fundamentally, * qp_add_pointer() is used to manipulate the head itself. * * Results: * None. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline void vmci_queue_header_add_consumer_head(struct vmci_queue_header *q_header, size_t add, uint64_t queue_size) { qp_add_pointer(&q_header->consumer_head, add, queue_size); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_get_pointers -- * * Helper routine for getting the head and the tail pointer for a queue. * Both the VMCIQueues are needed to get both the pointers for one queue. * * Results: * None. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline void vmci_queue_header_get_pointers(const struct vmci_queue_header *produce_q_header, const struct vmci_queue_header *consume_q_header, uint64_t *producer_tail, uint64_t *consumer_head) { if (producer_tail) *producer_tail = vmci_queue_header_producer_tail(produce_q_header); if (consumer_head) *consumer_head = vmci_queue_header_consumer_head(consume_q_header); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_reset_pointers -- * * Reset the tail pointer (of "this" queue) and the head pointer (of "peer" * queue). * * Results: * None. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline void vmci_queue_header_reset_pointers(struct vmci_queue_header *q_header) { qp_atomic_write_offset(&q_header->producer_tail, CONST64U(0)); qp_atomic_write_offset(&q_header->consumer_head, CONST64U(0)); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_init -- * * Initializes a queue's state (head & tail pointers). * * Results: * None. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline void vmci_queue_header_init(struct vmci_queue_header *q_header, const struct vmci_handle handle) { q_header->handle = handle; vmci_queue_header_reset_pointers(q_header); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_free_space -- * * Finds available free space in a produce queue to enqueue more data or * reports an error if queue pair corruption is detected. * * Results: * Free space size in bytes or an error code. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline int64_t vmci_queue_header_free_space(const struct vmci_queue_header *produce_q_header, const struct vmci_queue_header *consume_q_header, const uint64_t produce_q_size) { uint64_t free_space; uint64_t head; uint64_t tail; tail = vmci_queue_header_producer_tail(produce_q_header); head = vmci_queue_header_consumer_head(consume_q_header); if (tail >= produce_q_size || head >= produce_q_size) return (VMCI_ERROR_INVALID_SIZE); /* * Deduct 1 to avoid tail becoming equal to head which causes ambiguity. * If head and tail are equal it means that the queue is empty. */ if (tail >= head) free_space = produce_q_size - (tail - head) - 1; else free_space = head - tail - 1; return (free_space); } /* *------------------------------------------------------------------------------ * * vmci_queue_header_buf_ready -- * * vmci_queue_header_free_space() does all the heavy lifting of determing * the number of free bytes in a Queue. This routine, then subtracts that * size from the full size of the Queue so the caller knows how many bytes * are ready to be dequeued. * * Results: * On success, available data size in bytes (up to MAX_INT64). * On failure, appropriate error code. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static inline int64_t vmci_queue_header_buf_ready(const struct vmci_queue_header *consume_q_header, const struct vmci_queue_header *produce_q_header, const uint64_t consume_q_size) { int64_t free_space; free_space = vmci_queue_header_free_space(consume_q_header, produce_q_header, consume_q_size); if (free_space < VMCI_SUCCESS) return (free_space); else return (consume_q_size - free_space - 1); } #endif /* !_VMCI_DEFS_H_ */