xref: /freebsd/sys/dev/vmware/vmci/vmci_defs.h (revision 63a938566d524836885917d95bd491aa4400b181)
1 /*-
2  * Copyright (c) 2018 VMware, Inc. All Rights Reserved.
3  *
4  * SPDX-License-Identifier: (BSD-2-Clause AND GPL-2.0)
5  *
6  * $FreeBSD$
7  */
8 
9 #ifndef _VMCI_DEFS_H_
10 #define _VMCI_DEFS_H_
11 
12 #include <sys/types.h>
13 #include <machine/atomic.h>
14 
15 #include "vmci_kernel_defs.h"
16 
17 #pragma GCC diagnostic ignored "-Wcast-qual"
18 
19 /* Register offsets. */
20 #define VMCI_STATUS_ADDR		0x00
21 #define VMCI_CONTROL_ADDR		0x04
22 #define VMCI_ICR_ADDR			0x08
23 #define VMCI_IMR_ADDR			0x0c
24 #define VMCI_DATA_OUT_ADDR		0x10
25 #define VMCI_DATA_IN_ADDR		0x14
26 #define VMCI_CAPS_ADDR			0x18
27 #define VMCI_RESULT_LOW_ADDR		0x1c
28 #define VMCI_RESULT_HIGH_ADDR		0x20
29 
30 /* Status register bits. */
31 #define VMCI_STATUS_INT_ON		0x1
32 
33 /* Control register bits. */
34 #define VMCI_CONTROL_RESET		0x1
35 #define VMCI_CONTROL_INT_ENABLE		0x2
36 #define VMCI_CONTROL_INT_DISABLE	0x4
37 
38 /* Capabilities register bits. */
39 #define VMCI_CAPS_HYPERCALL		0x1
40 #define VMCI_CAPS_GUESTCALL		0x2
41 #define VMCI_CAPS_DATAGRAM		0x4
42 #define VMCI_CAPS_NOTIFICATIONS		0x8
43 
44 /* Interrupt Cause register bits. */
45 #define VMCI_ICR_DATAGRAM		0x1
46 #define VMCI_ICR_NOTIFICATION		0x2
47 
48 /* Interrupt Mask register bits. */
49 #define VMCI_IMR_DATAGRAM		0x1
50 #define VMCI_IMR_NOTIFICATION		0x2
51 
52 /* Interrupt type. */
53 typedef enum vmci_intr_type {
54 	VMCI_INTR_TYPE_INTX =	0,
55 	VMCI_INTR_TYPE_MSI =	1,
56 	VMCI_INTR_TYPE_MSIX =	2
57 } vmci_intr_type;
58 
59 /*
60  * Maximum MSI/MSI-X interrupt vectors in the device.
61  */
62 #define VMCI_MAX_INTRS			2
63 
64 /*
65  * Supported interrupt vectors. There is one for each ICR value above,
66  * but here they indicate the position in the vector array/message ID.
67  */
68 #define VMCI_INTR_DATAGRAM		0
69 #define VMCI_INTR_NOTIFICATION		1
70 
71 /*
72  * A single VMCI device has an upper limit of 128 MiB on the amount of
73  * memory that can be used for queue pairs.
74  */
75 #define VMCI_MAX_GUEST_QP_MEMORY	(128 * 1024 * 1024)
76 
77 /*
78  * We have a fixed set of resource IDs available in the VMX.
79  * This allows us to have a very simple implementation since we statically
80  * know how many will create datagram handles. If a new caller arrives and
81  * we have run out of slots we can manually increment the maximum size of
82  * available resource IDs.
83  */
84 
85 typedef uint32_t vmci_resource;
86 
87 /* VMCI reserved hypervisor datagram resource IDs. */
88 #define VMCI_RESOURCES_QUERY		0
89 #define VMCI_GET_CONTEXT_ID		1
90 #define VMCI_SET_NOTIFY_BITMAP		2
91 #define VMCI_DOORBELL_LINK		3
92 #define VMCI_DOORBELL_UNLINK		4
93 #define VMCI_DOORBELL_NOTIFY		5
94 /*
95  * VMCI_DATAGRAM_REQUEST_MAP and VMCI_DATAGRAM_REMOVE_MAP are
96  * obsoleted by the removal of VM to VM communication.
97  */
98 #define VMCI_DATAGRAM_REQUEST_MAP	6
99 #define VMCI_DATAGRAM_REMOVE_MAP	7
100 #define VMCI_EVENT_SUBSCRIBE		8
101 #define VMCI_EVENT_UNSUBSCRIBE		9
102 #define VMCI_QUEUEPAIR_ALLOC		10
103 #define VMCI_QUEUEPAIR_DETACH		11
104 /*
105  * VMCI_VSOCK_VMX_LOOKUP was assigned to 12 for Fusion 3.0/3.1,
106  * WS 7.0/7.1 and ESX 4.1
107  */
108 #define VMCI_HGFS_TRANSPORT		13
109 #define VMCI_UNITY_PBRPC_REGISTER	14
110 /*
111  * This resource is used for VMCI socket control packets sent to the
112  * hypervisor (CID 0) because RID 1 is already reserved.
113  */
114 #define VSOCK_PACKET_HYPERVISOR_RID	15
115 #define VMCI_RESOURCE_MAX		16
116 /*
117  * The core VMCI device functionality only requires the resource IDs of
118  * VMCI_QUEUEPAIR_DETACH and below.
119  */
120 #define VMCI_CORE_DEVICE_RESOURCE_MAX	VMCI_QUEUEPAIR_DETACH
121 
122 /*
123  * VMCI reserved host datagram resource IDs.
124  * vsock control channel has resource id 1.
125  */
126 #define VMCI_DVFILTER_DATA_PATH_DATAGRAM	2
127 
128 /* VMCI Ids. */
129 typedef uint32_t vmci_id;
130 
131 struct vmci_id_range {
132 	int8_t	action;	/* VMCI_FA_X, for use in filters. */
133 	vmci_id	begin;	/* Beginning of range. */
134 	vmci_id	end;	/* End of range. */
135 };
136 
137 struct vmci_handle {
138 	vmci_id	context;
139 	vmci_id	resource;
140 };
141 
142 static inline struct vmci_handle
143 VMCI_MAKE_HANDLE(vmci_id cid, vmci_id rid)
144 {
145 	struct vmci_handle h;
146 
147 	h.context = cid;
148 	h.resource = rid;
149 	return (h);
150 }
151 
152 #define VMCI_HANDLE_TO_CONTEXT_ID(_handle)				\
153 	((_handle).context)
154 #define VMCI_HANDLE_TO_RESOURCE_ID(_handle)				\
155 	((_handle).resource)
156 #define VMCI_HANDLE_EQUAL(_h1, _h2)					\
157 	((_h1).context == (_h2).context && (_h1).resource == (_h2).resource)
158 
159 #define VMCI_INVALID_ID			0xFFFFFFFF
160 static const struct vmci_handle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID,
161 	    VMCI_INVALID_ID};
162 
163 #define VMCI_HANDLE_INVALID(_handle)					\
164 	VMCI_HANDLE_EQUAL((_handle), VMCI_INVALID_HANDLE)
165 
166 /*
167  * The below defines can be used to send anonymous requests.
168  * This also indicates that no response is expected.
169  */
170 #define VMCI_ANON_SRC_CONTEXT_ID					\
171 	VMCI_INVALID_ID
172 #define VMCI_ANON_SRC_RESOURCE_ID					\
173 	VMCI_INVALID_ID
174 #define VMCI_ANON_SRC_HANDLE						\
175 	VMCI_MAKE_HANDLE(VMCI_ANON_SRC_CONTEXT_ID,			\
176 	VMCI_ANON_SRC_RESOURCE_ID)
177 
178 /* The lowest 16 context ids are reserved for internal use. */
179 #define VMCI_RESERVED_CID_LIMIT		16
180 
181 /*
182  * Hypervisor context id, used for calling into hypervisor
183  * supplied services from the VM.
184  */
185 #define VMCI_HYPERVISOR_CONTEXT_ID	0
186 
187 /*
188  * Well-known context id, a logical context that contains a set of
189  * well-known services. This context ID is now obsolete.
190  */
191 #define VMCI_WELL_KNOWN_CONTEXT_ID	1
192 
193 /*
194  * Context ID used by host endpoints.
195  */
196 #define VMCI_HOST_CONTEXT_ID		2
197 #define VMCI_HOST_CONTEXT_INVALID_EVENT	((uintptr_t)~0)
198 
199 #define VMCI_CONTEXT_IS_VM(_cid)					\
200 	(VMCI_INVALID_ID != _cid && _cid > VMCI_HOST_CONTEXT_ID)
201 
202 /*
203  * The VMCI_CONTEXT_RESOURCE_ID is used together with VMCI_MAKE_HANDLE to make
204  * handles that refer to a specific context.
205  */
206 #define VMCI_CONTEXT_RESOURCE_ID	0
207 
208 /*
209  *------------------------------------------------------------------------------
210  *
211  * VMCI error codes.
212  *
213  *------------------------------------------------------------------------------
214  */
215 
216 #define VMCI_SUCCESS_QUEUEPAIR_ATTACH		5
217 #define VMCI_SUCCESS_QUEUEPAIR_CREATE		4
218 #define VMCI_SUCCESS_LAST_DETACH		3
219 #define VMCI_SUCCESS_ACCESS_GRANTED		2
220 #define VMCI_SUCCESS_ENTRY_DEAD			1
221 #define VMCI_SUCCESS				0LL
222 #define VMCI_ERROR_INVALID_RESOURCE		(-1)
223 #define VMCI_ERROR_INVALID_ARGS			(-2)
224 #define VMCI_ERROR_NO_MEM			(-3)
225 #define VMCI_ERROR_DATAGRAM_FAILED		(-4)
226 #define VMCI_ERROR_MORE_DATA			(-5)
227 #define VMCI_ERROR_NO_MORE_DATAGRAMS		(-6)
228 #define VMCI_ERROR_NO_ACCESS			(-7)
229 #define VMCI_ERROR_NO_HANDLE			(-8)
230 #define VMCI_ERROR_DUPLICATE_ENTRY		(-9)
231 #define VMCI_ERROR_DST_UNREACHABLE		(-10)
232 #define VMCI_ERROR_PAYLOAD_TOO_LARGE		(-11)
233 #define VMCI_ERROR_INVALID_PRIV			(-12)
234 #define VMCI_ERROR_GENERIC			(-13)
235 #define VMCI_ERROR_PAGE_ALREADY_SHARED		(-14)
236 #define VMCI_ERROR_CANNOT_SHARE_PAGE		(-15)
237 #define VMCI_ERROR_CANNOT_UNSHARE_PAGE		(-16)
238 #define VMCI_ERROR_NO_PROCESS			(-17)
239 #define VMCI_ERROR_NO_DATAGRAM			(-18)
240 #define VMCI_ERROR_NO_RESOURCES			(-19)
241 #define VMCI_ERROR_UNAVAILABLE			(-20)
242 #define VMCI_ERROR_NOT_FOUND			(-21)
243 #define VMCI_ERROR_ALREADY_EXISTS		(-22)
244 #define VMCI_ERROR_NOT_PAGE_ALIGNED		(-23)
245 #define VMCI_ERROR_INVALID_SIZE			(-24)
246 #define VMCI_ERROR_REGION_ALREADY_SHARED	(-25)
247 #define VMCI_ERROR_TIMEOUT			(-26)
248 #define VMCI_ERROR_DATAGRAM_INCOMPLETE		(-27)
249 #define VMCI_ERROR_INCORRECT_IRQL		(-28)
250 #define VMCI_ERROR_EVENT_UNKNOWN		(-29)
251 #define VMCI_ERROR_OBSOLETE			(-30)
252 #define VMCI_ERROR_QUEUEPAIR_MISMATCH		(-31)
253 #define VMCI_ERROR_QUEUEPAIR_NOTSET		(-32)
254 #define VMCI_ERROR_QUEUEPAIR_NOTOWNER		(-33)
255 #define VMCI_ERROR_QUEUEPAIR_NOTATTACHED	(-34)
256 #define VMCI_ERROR_QUEUEPAIR_NOSPACE		(-35)
257 #define VMCI_ERROR_QUEUEPAIR_NODATA		(-36)
258 #define VMCI_ERROR_BUSMEM_INVALIDATION		(-37)
259 #define VMCI_ERROR_MODULE_NOT_LOADED		(-38)
260 #define VMCI_ERROR_DEVICE_NOT_FOUND		(-39)
261 #define VMCI_ERROR_QUEUEPAIR_NOT_READY		(-40)
262 #define VMCI_ERROR_WOULD_BLOCK			(-41)
263 
264 /* VMCI clients should return error code withing this range */
265 #define VMCI_ERROR_CLIENT_MIN			(-500)
266 #define VMCI_ERROR_CLIENT_MAX			(-550)
267 
268 /* Internal error codes. */
269 #define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT	(-1000)
270 
271 #define VMCI_PATH_MAX				256
272 
273 /* VMCI reserved events. */
274 typedef uint32_t vmci_event_type;
275 
276 #define VMCI_EVENT_CTX_ID_UPDATE	0	// Only applicable to guest
277 						// endpoints
278 #define VMCI_EVENT_CTX_REMOVED		1	// Applicable to guest and host
279 #define VMCI_EVENT_QP_RESUMED		2	// Only applicable to guest
280 						// endpoints
281 #define VMCI_EVENT_QP_PEER_ATTACH	3	// Applicable to guest, host
282 						// and VMX
283 #define VMCI_EVENT_QP_PEER_DETACH	4	// Applicable to guest, host
284 						// and VMX
285 #define VMCI_EVENT_MEM_ACCESS_ON	5	// Applicable to VMX and vmk. On
286 						// vmk, this event has the
287 						// Context payload type
288 #define VMCI_EVENT_MEM_ACCESS_OFF	6	// Applicable to VMX and vmk.
289 						// Same as above for the payload
290 						// type
291 #define VMCI_EVENT_GUEST_PAUSED		7	// Applicable to vmk. This
292 						// event has the Context
293 						// payload type
294 #define VMCI_EVENT_GUEST_UNPAUSED	8	// Applicable to vmk. Same as
295 						// above for the payload type.
296 #define VMCI_EVENT_MAX			9
297 
298 /*
299  * Of the above events, a few are reserved for use in the VMX, and other
300  * endpoints (guest and host kernel) should not use them. For the rest of the
301  * events, we allow both host and guest endpoints to subscribe to them, to
302  * maintain the same API for host and guest endpoints.
303  */
304 
305 #define VMCI_EVENT_VALID_VMX(_event)					\
306 	(_event == VMCI_EVENT_QP_PEER_ATTACH ||				\
307 	_event == VMCI_EVENT_QP_PEER_DETACH ||				\
308 	_event == VMCI_EVENT_MEM_ACCESS_ON ||				\
309 	_event == VMCI_EVENT_MEM_ACCESS_OFF)
310 
311 #define VMCI_EVENT_VALID(_event)					\
312 	(_event < VMCI_EVENT_MAX &&					\
313 	_event != VMCI_EVENT_MEM_ACCESS_ON &&				\
314 	_event != VMCI_EVENT_MEM_ACCESS_OFF &&				\
315 	_event != VMCI_EVENT_GUEST_PAUSED &&				\
316 	_event != VMCI_EVENT_GUEST_UNPAUSED)
317 
318 /* Reserved guest datagram resource ids. */
319 #define VMCI_EVENT_HANDLER		0
320 
321 /*
322  * VMCI coarse-grained privileges (per context or host process/endpoint. An
323  * entity with the restricted flag is only allowed to interact with the
324  * hypervisor and trusted entities.
325  */
326 typedef uint32_t vmci_privilege_flags;
327 
328 #define VMCI_PRIVILEGE_FLAG_RESTRICTED		0x01
329 #define VMCI_PRIVILEGE_FLAG_TRUSTED		0x02
330 #define VMCI_PRIVILEGE_ALL_FLAGS					\
331 	(VMCI_PRIVILEGE_FLAG_RESTRICTED | VMCI_PRIVILEGE_FLAG_TRUSTED)
332 #define VMCI_NO_PRIVILEGE_FLAGS			0x00
333 #define VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS	VMCI_NO_PRIVILEGE_FLAGS
334 #define VMCI_LEAST_PRIVILEGE_FLAGS		VMCI_PRIVILEGE_FLAG_RESTRICTED
335 #define VMCI_MAX_PRIVILEGE_FLAGS		VMCI_PRIVILEGE_FLAG_TRUSTED
336 
337 /* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
338 #define VMCI_RESERVED_RESOURCE_ID_MAX		1023
339 
340 #define VMCI_DOMAIN_NAME_MAXLEN			32
341 
342 #define VMCI_LGPFX				"vmci: "
343 
344 /*
345  * struct vmci_queue_header
346  *
347  * A Queue cannot stand by itself as designed. Each Queue's header contains a
348  * pointer into itself (the producer_tail) and into its peer (consumer_head).
349  * The reason for the separation is one of accessibility: Each end-point can
350  * modify two things: where the next location to enqueue is within its produce_q
351  * (producer_tail); and where the next dequeue location is in its consume_q
352  * (consumer_head).
353  *
354  * An end-point cannot modify the pointers of its peer (guest to guest; NOTE
355  * that in the host both queue headers are mapped r/w). But, each end-point
356  * needs read access to both Queue header structures in order to determine how
357  * much space is used (or left) in the Queue. This is because for an end-point
358  * to know how full its produce_q is, it needs to use the consumer_head that
359  * points into the produce_q but -that- consumer_head is in the Queue header
360  * for that end-points consume_q.
361  *
362  * Thoroughly confused?  Sorry.
363  *
364  * producer_tail: the point to enqueue new entrants.  When you approach a line
365  * in a store, for example, you walk up to the tail.
366  *
367  * consumer_head: the point in the queue from which the next element is
368  * dequeued. In other words, who is next in line is he who is at the head of
369  * the line.
370  *
371  * Also, producer_tail points to an empty byte in the Queue, whereas
372  * consumer_head points to a valid byte of data (unless producer_tail ==
373  * consumer_head in which case consumerHead does not point to a valid byte of
374  * data).
375  *
376  * For a queue of buffer 'size' bytes, the tail and head pointers will be in
377  * the range [0, size-1].
378  *
379  * If produce_q_header->producer_tail == consume_q_header->consumer_head then
380  * the produce_q is empty.
381  */
382 struct vmci_queue_header {
383 	/* All fields are 64bit and aligned. */
384 	struct vmci_handle	handle;		/* Identifier. */
385 	volatile uint64_t	producer_tail;	/* Offset in this queue. */
386 	volatile uint64_t	consumer_head;	/* Offset in peer queue. */
387 };
388 
389 
390 /*
391  * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
392  * size to be less than 4GB, and use 32bit atomic operations on the head and
393  * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
394  * is an atomic read-modify-write. This will cause traces to fire when a 32bit
395  * consumer tries to read the producer's tail pointer, for example, because the
396  * consumer has read-only access to the producer's tail pointer.
397  *
398  * We provide the following macros to invoke 32bit or 64bit atomic operations
399  * based on the architecture the code is being compiled on.
400  */
401 
402 #ifdef __x86_64__
403 #define QP_MAX_QUEUE_SIZE_ARCH		CONST64U(0xffffffffffffffff)
404 #define qp_atomic_read_offset(x)	atomic_load_64(x)
405 #define qp_atomic_write_offset(x, y)	atomic_store_64(x, y)
406 #else /* __x86_64__ */
407 	/*
408 	 * Wrappers below are being used because atomic_store_<type> operates
409 	 * on a specific <type>. Likewise for atomic_load_<type>
410 	 */
411 
412 	static inline uint32_t
413 	type_safe_atomic_read_32(void *var)
414 	{
415 		return (atomic_load_32((volatile uint32_t *)(var)));
416 	}
417 
418 	static inline void
419 	type_safe_atomic_write_32(void *var, uint32_t val)
420 	{
421 		atomic_store_32((volatile uint32_t *)(var), (uint32_t)(val));
422 	}
423 
424 #define QP_MAX_QUEUE_SIZE_ARCH		CONST64U(0xffffffff)
425 #define qp_atomic_read_offset(x)	type_safe_atomic_read_32((void *)(x))
426 #define qp_atomic_write_offset(x, y)					\
427 	type_safe_atomic_write_32((void *)(x), (uint32_t)(y))
428 #endif /* __x86_64__ */
429 
430 /*
431  *------------------------------------------------------------------------------
432  *
433  * qp_add_pointer --
434  *
435  *     Helper to add a given offset to a head or tail pointer. Wraps the value
436  *     of the pointer around the max size of the queue.
437  *
438  * Results:
439  *     None.
440  *
441  * Side effects:
442  *     None.
443  *
444  *------------------------------------------------------------------------------
445  */
446 
447 static inline void
448 qp_add_pointer(volatile uint64_t *var, size_t add, uint64_t size)
449 {
450 	uint64_t new_val = qp_atomic_read_offset(var);
451 
452 	if (new_val >= size - add)
453 		new_val -= size;
454 
455 	new_val += add;
456 	qp_atomic_write_offset(var, new_val);
457 }
458 
459 /*
460  *------------------------------------------------------------------------------
461  *
462  * vmci_queue_header_producer_tail --
463  *
464  *     Helper routine to get the Producer Tail from the supplied queue.
465  *
466  * Results:
467  *     The contents of the queue's producer tail.
468  *
469  * Side effects:
470  *     None.
471  *
472  *------------------------------------------------------------------------------
473  */
474 
475 static inline uint64_t
476 vmci_queue_header_producer_tail(const struct vmci_queue_header *q_header)
477 {
478 	struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header;
479 	return (qp_atomic_read_offset(&qh->producer_tail));
480 }
481 
482 /*
483  *------------------------------------------------------------------------------
484  *
485  * vmci_queue_header_consumer_head --
486  *
487  *     Helper routine to get the Consumer Head from the supplied queue.
488  *
489  * Results:
490  *     The contents of the queue's consumer tail.
491  *
492  * Side effects:
493  *     None.
494  *
495  *------------------------------------------------------------------------------
496  */
497 
498 static inline uint64_t
499 vmci_queue_header_consumer_head(const struct vmci_queue_header *q_header)
500 {
501 	struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header;
502 	return (qp_atomic_read_offset(&qh->consumer_head));
503 }
504 
505 /*
506  *------------------------------------------------------------------------------
507  *
508  * vmci_queue_header_add_producer_tail --
509  *
510  *     Helper routine to increment the Producer Tail. Fundamentally,
511  *     qp_add_pointer() is used to manipulate the tail itself.
512  *
513  * Results:
514  *     None.
515  *
516  * Side effects:
517  *     None.
518  *
519  *------------------------------------------------------------------------------
520  */
521 
522 static inline void
523 vmci_queue_header_add_producer_tail(struct vmci_queue_header *q_header,
524     size_t add, uint64_t queue_size)
525 {
526 
527 	qp_add_pointer(&q_header->producer_tail, add, queue_size);
528 }
529 
530 /*
531  *------------------------------------------------------------------------------
532  *
533  * vmci_queue_header_add_consumer_head --
534  *
535  *     Helper routine to increment the Consumer Head. Fundamentally,
536  *     qp_add_pointer() is used to manipulate the head itself.
537  *
538  * Results:
539  *     None.
540  *
541  * Side effects:
542  *     None.
543  *
544  *------------------------------------------------------------------------------
545  */
546 
547 static inline void
548 vmci_queue_header_add_consumer_head(struct vmci_queue_header *q_header,
549     size_t add, uint64_t queue_size)
550 {
551 
552 	qp_add_pointer(&q_header->consumer_head, add, queue_size);
553 }
554 
555 /*
556  *------------------------------------------------------------------------------
557  *
558  * vmci_queue_header_get_pointers --
559  *
560  *     Helper routine for getting the head and the tail pointer for a queue.
561  *     Both the VMCIQueues are needed to get both the pointers for one queue.
562  *
563  * Results:
564  *     None.
565  *
566  * Side effects:
567  *     None.
568  *
569  *------------------------------------------------------------------------------
570  */
571 
572 static inline void
573 vmci_queue_header_get_pointers(const struct vmci_queue_header *produce_q_header,
574     const struct vmci_queue_header *consume_q_header, uint64_t *producer_tail,
575     uint64_t *consumer_head)
576 {
577 
578 	if (producer_tail)
579 		*producer_tail =
580 		    vmci_queue_header_producer_tail(produce_q_header);
581 
582 	if (consumer_head)
583 		*consumer_head =
584 		    vmci_queue_header_consumer_head(consume_q_header);
585 }
586 
587 /*
588  *------------------------------------------------------------------------------
589  *
590  * vmci_queue_header_reset_pointers --
591  *
592  *     Reset the tail pointer (of "this" queue) and the head pointer (of "peer"
593  *     queue).
594  *
595  * Results:
596  *     None.
597  *
598  * Side effects:
599  *     None.
600  *
601  *------------------------------------------------------------------------------
602  */
603 
604 static inline void
605 vmci_queue_header_reset_pointers(struct vmci_queue_header *q_header)
606 {
607 
608 	qp_atomic_write_offset(&q_header->producer_tail, CONST64U(0));
609 	qp_atomic_write_offset(&q_header->consumer_head, CONST64U(0));
610 }
611 
612 /*
613  *------------------------------------------------------------------------------
614  *
615  * vmci_queue_header_init --
616  *
617  *     Initializes a queue's state (head & tail pointers).
618  *
619  * Results:
620  *     None.
621  *
622  * Side effects:
623  *     None.
624  *
625  *------------------------------------------------------------------------------
626  */
627 
628 static inline void
629 vmci_queue_header_init(struct vmci_queue_header *q_header,
630     const struct vmci_handle handle)
631 {
632 
633 	q_header->handle = handle;
634 	vmci_queue_header_reset_pointers(q_header);
635 }
636 
637 /*
638  *------------------------------------------------------------------------------
639  *
640  * vmci_queue_header_free_space --
641  *
642  *     Finds available free space in a produce queue to enqueue more data or
643  *     reports an error if queue pair corruption is detected.
644  *
645  * Results:
646  *     Free space size in bytes or an error code.
647  *
648  * Side effects:
649  *     None.
650  *
651  *------------------------------------------------------------------------------
652  */
653 
654 static inline int64_t
655 vmci_queue_header_free_space(const struct vmci_queue_header *produce_q_header,
656     const struct vmci_queue_header *consume_q_header,
657     const uint64_t produce_q_size)
658 {
659 	uint64_t free_space;
660 	uint64_t head;
661 	uint64_t tail;
662 
663 	tail = vmci_queue_header_producer_tail(produce_q_header);
664 	head = vmci_queue_header_consumer_head(consume_q_header);
665 
666 	if (tail >= produce_q_size || head >= produce_q_size)
667 		return (VMCI_ERROR_INVALID_SIZE);
668 
669 	/*
670 	 * Deduct 1 to avoid tail becoming equal to head which causes ambiguity.
671 	 * If head and tail are equal it means that the queue is empty.
672 	 */
673 
674 	if (tail >= head)
675 		free_space = produce_q_size - (tail - head) - 1;
676 	else
677 		free_space = head - tail - 1;
678 
679 	return (free_space);
680 }
681 
682 /*
683  *------------------------------------------------------------------------------
684  *
685  * vmci_queue_header_buf_ready --
686  *
687  *     vmci_queue_header_free_space() does all the heavy lifting of determing
688  *     the number of free bytes in a Queue. This routine, then subtracts that
689  *     size from the full size of the Queue so the caller knows how many bytes
690  *     are ready to be dequeued.
691  *
692  * Results:
693  *     On success, available data size in bytes (up to MAX_INT64).
694  *     On failure, appropriate error code.
695  *
696  * Side effects:
697  *     None.
698  *
699  *------------------------------------------------------------------------------
700  */
701 
702 static inline int64_t
703 vmci_queue_header_buf_ready(const struct vmci_queue_header *consume_q_header,
704     const struct vmci_queue_header *produce_q_header,
705     const uint64_t consume_q_size)
706 {
707 	int64_t free_space;
708 
709 	free_space = vmci_queue_header_free_space(consume_q_header,
710 	    produce_q_header, consume_q_size);
711 	if (free_space < VMCI_SUCCESS)
712 		return (free_space);
713 	else
714 		return (consume_q_size - free_space - 1);
715 }
716 
717 #endif /* !_VMCI_DEFS_H_ */
718