xref: /freebsd/sys/dev/vmware/vmci/vmci_defs.h (revision 8a272653d9fbd9fc37691c9aad6a05089b4ecb4d)
1 /*-
2  * Copyright (c) 2018 VMware, Inc.
3  *
4  * SPDX-License-Identifier: (BSD-2-Clause OR 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  * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
391  * size to be less than 4GB, and use 32bit atomic operations on the head and
392  * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
393  * is an atomic read-modify-write. This will cause traces to fire when a 32bit
394  * consumer tries to read the producer's tail pointer, for example, because the
395  * consumer has read-only access to the producer's tail pointer.
396  *
397  * We provide the following macros to invoke 32bit or 64bit atomic operations
398  * based on the architecture the code is being compiled on.
399  */
400 
401 #ifdef __x86_64__
402 #define QP_MAX_QUEUE_SIZE_ARCH		CONST64U(0xffffffffffffffff)
403 #define qp_atomic_read_offset(x)	atomic_load_64(x)
404 #define qp_atomic_write_offset(x, y)	atomic_store_64(x, y)
405 #else /* __x86_64__ */
406 	/*
407 	 * Wrappers below are being used because atomic_store_<type> operates
408 	 * on a specific <type>. Likewise for atomic_load_<type>
409 	 */
410 
411 	static inline uint32_t
412 	type_safe_atomic_read_32(void *var)
413 	{
414 		return (atomic_load_32((volatile uint32_t *)(var)));
415 	}
416 
417 	static inline void
418 	type_safe_atomic_write_32(void *var, uint32_t val)
419 	{
420 		atomic_store_32((volatile uint32_t *)(var), (uint32_t)(val));
421 	}
422 
423 #define QP_MAX_QUEUE_SIZE_ARCH		CONST64U(0xffffffff)
424 #define qp_atomic_read_offset(x)	type_safe_atomic_read_32((void *)(x))
425 #define qp_atomic_write_offset(x, y)					\
426 	type_safe_atomic_write_32((void *)(x), (uint32_t)(y))
427 #endif /* __x86_64__ */
428 
429 /*
430  *------------------------------------------------------------------------------
431  *
432  * qp_add_pointer --
433  *
434  *     Helper to add a given offset to a head or tail pointer. Wraps the value
435  *     of the pointer around the max size of the queue.
436  *
437  * Results:
438  *     None.
439  *
440  * Side effects:
441  *     None.
442  *
443  *------------------------------------------------------------------------------
444  */
445 
446 static inline void
447 qp_add_pointer(volatile uint64_t *var, size_t add, uint64_t size)
448 {
449 	uint64_t new_val = qp_atomic_read_offset(var);
450 
451 	if (new_val >= size - add)
452 		new_val -= size;
453 
454 	new_val += add;
455 	qp_atomic_write_offset(var, new_val);
456 }
457 
458 /*
459  *------------------------------------------------------------------------------
460  *
461  * vmci_queue_header_producer_tail --
462  *
463  *     Helper routine to get the Producer Tail from the supplied queue.
464  *
465  * Results:
466  *     The contents of the queue's producer tail.
467  *
468  * Side effects:
469  *     None.
470  *
471  *------------------------------------------------------------------------------
472  */
473 
474 static inline uint64_t
475 vmci_queue_header_producer_tail(const struct vmci_queue_header *q_header)
476 {
477 	struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header;
478 	return (qp_atomic_read_offset(&qh->producer_tail));
479 }
480 
481 /*
482  *------------------------------------------------------------------------------
483  *
484  * vmci_queue_header_consumer_head --
485  *
486  *     Helper routine to get the Consumer Head from the supplied queue.
487  *
488  * Results:
489  *     The contents of the queue's consumer tail.
490  *
491  * Side effects:
492  *     None.
493  *
494  *------------------------------------------------------------------------------
495  */
496 
497 static inline uint64_t
498 vmci_queue_header_consumer_head(const struct vmci_queue_header *q_header)
499 {
500 	struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header;
501 	return (qp_atomic_read_offset(&qh->consumer_head));
502 }
503 
504 /*
505  *------------------------------------------------------------------------------
506  *
507  * vmci_queue_header_add_producer_tail --
508  *
509  *     Helper routine to increment the Producer Tail. Fundamentally,
510  *     qp_add_pointer() is used to manipulate the tail itself.
511  *
512  * Results:
513  *     None.
514  *
515  * Side effects:
516  *     None.
517  *
518  *------------------------------------------------------------------------------
519  */
520 
521 static inline void
522 vmci_queue_header_add_producer_tail(struct vmci_queue_header *q_header,
523     size_t add, uint64_t queue_size)
524 {
525 
526 	qp_add_pointer(&q_header->producer_tail, add, queue_size);
527 }
528 
529 /*
530  *------------------------------------------------------------------------------
531  *
532  * vmci_queue_header_add_consumer_head --
533  *
534  *     Helper routine to increment the Consumer Head. Fundamentally,
535  *     qp_add_pointer() is used to manipulate the head itself.
536  *
537  * Results:
538  *     None.
539  *
540  * Side effects:
541  *     None.
542  *
543  *------------------------------------------------------------------------------
544  */
545 
546 static inline void
547 vmci_queue_header_add_consumer_head(struct vmci_queue_header *q_header,
548     size_t add, uint64_t queue_size)
549 {
550 
551 	qp_add_pointer(&q_header->consumer_head, add, queue_size);
552 }
553 
554 /*
555  *------------------------------------------------------------------------------
556  *
557  * vmci_queue_header_get_pointers --
558  *
559  *     Helper routine for getting the head and the tail pointer for a queue.
560  *     Both the VMCIQueues are needed to get both the pointers for one queue.
561  *
562  * Results:
563  *     None.
564  *
565  * Side effects:
566  *     None.
567  *
568  *------------------------------------------------------------------------------
569  */
570 
571 static inline void
572 vmci_queue_header_get_pointers(const struct vmci_queue_header *produce_q_header,
573     const struct vmci_queue_header *consume_q_header, uint64_t *producer_tail,
574     uint64_t *consumer_head)
575 {
576 
577 	if (producer_tail)
578 		*producer_tail =
579 		    vmci_queue_header_producer_tail(produce_q_header);
580 
581 	if (consumer_head)
582 		*consumer_head =
583 		    vmci_queue_header_consumer_head(consume_q_header);
584 }
585 
586 /*
587  *------------------------------------------------------------------------------
588  *
589  * vmci_queue_header_reset_pointers --
590  *
591  *     Reset the tail pointer (of "this" queue) and the head pointer (of "peer"
592  *     queue).
593  *
594  * Results:
595  *     None.
596  *
597  * Side effects:
598  *     None.
599  *
600  *------------------------------------------------------------------------------
601  */
602 
603 static inline void
604 vmci_queue_header_reset_pointers(struct vmci_queue_header *q_header)
605 {
606 
607 	qp_atomic_write_offset(&q_header->producer_tail, CONST64U(0));
608 	qp_atomic_write_offset(&q_header->consumer_head, CONST64U(0));
609 }
610 
611 /*
612  *------------------------------------------------------------------------------
613  *
614  * vmci_queue_header_init --
615  *
616  *     Initializes a queue's state (head & tail pointers).
617  *
618  * Results:
619  *     None.
620  *
621  * Side effects:
622  *     None.
623  *
624  *------------------------------------------------------------------------------
625  */
626 
627 static inline void
628 vmci_queue_header_init(struct vmci_queue_header *q_header,
629     const struct vmci_handle handle)
630 {
631 
632 	q_header->handle = handle;
633 	vmci_queue_header_reset_pointers(q_header);
634 }
635 
636 /*
637  *------------------------------------------------------------------------------
638  *
639  * vmci_queue_header_free_space --
640  *
641  *     Finds available free space in a produce queue to enqueue more data or
642  *     reports an error if queue pair corruption is detected.
643  *
644  * Results:
645  *     Free space size in bytes or an error code.
646  *
647  * Side effects:
648  *     None.
649  *
650  *------------------------------------------------------------------------------
651  */
652 
653 static inline int64_t
654 vmci_queue_header_free_space(const struct vmci_queue_header *produce_q_header,
655     const struct vmci_queue_header *consume_q_header,
656     const uint64_t produce_q_size)
657 {
658 	uint64_t free_space;
659 	uint64_t head;
660 	uint64_t tail;
661 
662 	tail = vmci_queue_header_producer_tail(produce_q_header);
663 	head = vmci_queue_header_consumer_head(consume_q_header);
664 
665 	if (tail >= produce_q_size || head >= produce_q_size)
666 		return (VMCI_ERROR_INVALID_SIZE);
667 
668 	/*
669 	 * Deduct 1 to avoid tail becoming equal to head which causes ambiguity.
670 	 * If head and tail are equal it means that the queue is empty.
671 	 */
672 
673 	if (tail >= head)
674 		free_space = produce_q_size - (tail - head) - 1;
675 	else
676 		free_space = head - tail - 1;
677 
678 	return (free_space);
679 }
680 
681 /*
682  *------------------------------------------------------------------------------
683  *
684  * vmci_queue_header_buf_ready --
685  *
686  *     vmci_queue_header_free_space() does all the heavy lifting of determing
687  *     the number of free bytes in a Queue. This routine, then subtracts that
688  *     size from the full size of the Queue so the caller knows how many bytes
689  *     are ready to be dequeued.
690  *
691  * Results:
692  *     On success, available data size in bytes (up to MAX_INT64).
693  *     On failure, appropriate error code.
694  *
695  * Side effects:
696  *     None.
697  *
698  *------------------------------------------------------------------------------
699  */
700 
701 static inline int64_t
702 vmci_queue_header_buf_ready(const struct vmci_queue_header *consume_q_header,
703     const struct vmci_queue_header *produce_q_header,
704     const uint64_t consume_q_size)
705 {
706 	int64_t free_space;
707 
708 	free_space = vmci_queue_header_free_space(consume_q_header,
709 	    produce_q_header, consume_q_size);
710 	if (free_space < VMCI_SUCCESS)
711 		return (free_space);
712 	else
713 		return (consume_q_size - free_space - 1);
714 }
715 
716 #endif /* !_VMCI_DEFS_H_ */
717