70
* A Queue cannot stand by itself as designed. Each Queue's header
71
* contains a pointer into itself (the producerTail) and into its peer
72
* (consumerHead). The reason for the separation is one of
73
* accessibility: Each end-point can modify two things: where the next
74
* location to enqueue is within its produceQ (producerTail); and
75
* where the next location in its consumeQ (i.e., its peer's produceQ)
76
* it can dequeue (consumerHead). The end-point cannot modify the
77
* pointers of its peer (guest to guest; NOTE that in the host both
78
* queue headers are mapped r/w). But, each end-point needs access to
79
* both Queue header structures in order to determine how much space
80
* is used (or left) in the Queue. This is because for an end-point
81
* to know how full its produceQ is, it needs to use the consumerHead
82
* that points into the produceQ but -that- consumerHead is in the
83
* Queue header for that end-points consumeQ.
85
* Thoroughly confused? Sorry.
87
* producerTail: the point to enqueue new entrants. When you approach
88
* a line in a store, for example, you walk up to the tail.
90
* consumerHead: the point in the queue from which the next element is
91
* dequeued. In other words, who is next in line is he who is at the
94
* Also, producerTail points to an empty byte in the Queue, whereas
95
* consumerHead points to a valid byte of data (unless producerTail ==
96
* consumerHead in which case consumerHead does not point to a valid
61
99
* For a queue of buffer 'size' bytes, the tail and head pointers will be in
62
100
* the range [0, size-1].
102
* If produceQ->producerTail == consumeQ->consumerHead then the
65
106
typedef struct VMCIQueueHeader {
237
278
struct page **page;
239
280
# define VMCIQueuePair_QueueIsMapped(q) ((q)->page != NULL)
240
# elif defined(__APPLE__)
281
# elif defined __APPLE__
243
285
* The VMCIQueueHeader has been created elsewhere and this
244
286
* structure (VMCIQueue) needs a pointer to that
245
287
* VMCIQueueHeader.
247
289
* Also, the queue contents are managed dynamically by
248
290
* mapping/unmapping the pages. All we need is the VA64
249
* base address of the buffer and the vm_map_t of the VMX
291
* base address of the buffer and the task_t of the VMX
250
292
* process hosting the queue file (i.e. buffer).
252
294
* Note, too, that the buffer contains one page of queue
253
295
* header information (head and tail pointers). But, that
254
* for the life of the VMCIQueue structure's life the
296
* for the life of the VMCIQueue structure the
255
297
* buffer value contains the address past the header info.
256
298
* This modification happens during FinishAttach and is
257
299
* never reversed.
259
301
typedef struct VMCIQueue {
260
VMCIQueueHeader *queueHeaderPtr;
261
ipc_port_t headerPort, contentPort;
302
VMCIQueueHeader *queueHeaderPtr;
303
IOMemoryDescriptor *pages;
264
# define VMCIQueuePair_QueueIsMapped(q) ((q)->attached != FALSE)
306
# define VMCIQueuePair_QueueIsMapped(q) ((q)->pages)
273
315
* Also, the queue contents are managed by an array of bytes
274
316
* which are managed elsewhere. So, this structure simply
275
317
* contains the address of that array of bytes.
319
* We have a mutex to protect the queue from accesses within the
320
* kernel module. NOTE: the guest may be enqueuing or dequeuing
321
* while the host has the mutex locked. However, multiple
322
* kernel processes will not access the Queue simultaneously.
324
* What the mutex is trying to protect is the moment where the
325
* guest detaches from a queue. In that moment, we will
326
* allocate memory to hold the guest's produceQ and we will
327
* change the queueHeaderPtr to point to a newly allocated (in
328
* kernel memory) structure. And, the buffer pointer will be
329
* changed to point to an in-kernel queue content (even if there
330
* isn't any data in the queue for the host to consume).
332
* Note that a VMCIQueue allocated by the host passes through
333
* three states before it's torn down. First, the queue is
334
* created by the host but doesn't point to any memory and
335
* therefore can't absorb any enqueue requests. (NOTE: On
336
* Windows this could be solved because of the mutexes, as
337
* explained above [only in reverse, if you will]. But unless
338
* we added the same mutexes [or other rules about accessing the
339
* queues] we can't can't solve this generally on other
340
* operating systems.)
342
* When the guest calls SetPageStore(), then the queue is backed
343
* by valid memory and the host can enqueue.
345
* When the guest detaches, enqueues are absorbed by /dev/null,
277
348
typedef struct VMCIQueue {
278
349
VMCIQueueHeader *queueHeaderPtr;
351
Bool enqueueToDevNull;
352
FAST_MUTEX *mutex; /* Access the mutex through this */
353
FAST_MUTEX __mutex; /* Don't touch except to init */
355
#define VMCIQueuePair_EnqueueToDevNull(q) ((q)->enqueueToDevNull)
281
356
#define VMCIQueuePair_QueueIsMapped(q) ((q)->buffer != NULL)
360
#ifndef VMCIQueuePair_EnqueueToDevNull
361
#define VMCIQueuePair_EnqueueToDevNull(q) (FALSE)
362
#endif /* default VMCIQueuePair_EnqueueToDevNull() definition */
365
*-----------------------------------------------------------------------------
367
* VMCIMemcpy{To,From}QueueFunc() prototypes. Functions of these
368
* types are passed around to enqueue and dequeue routines. Note that
369
* often the functions passed are simply wrappers around memcpy
372
*-----------------------------------------------------------------------------
374
typedef int VMCIMemcpyToQueueFunc(VMCIQueue *queue, uint64 queueOffset,
375
const void *src, size_t srcOffset,
377
typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset,
378
const VMCIQueue *queue, uint64 queueOffset,
382
* NOTE: On Windows host we have special code to access the queue
383
* contents (and QueuePair header) so that we can protect accesses
384
* during tear down of the guest that owns the mappings of the
385
* QueuePair queue contents. See
386
* bora/modules/vmcrosstalk/windows/vmciHostQueuePair.c
389
#if !defined _WIN32 || defined VMX86_TOOLS || defined VMX86_VMX
287
392
*-----------------------------------------------------------------------------
426
531
*-----------------------------------------------------------------------------
428
* VMCIMemcpy{To,From}QueueFunc() prototypes. Functions of these
429
* types are passed around to enqueue and dequeue routines. Note that
430
* often the functions passed are simply wrappers around memcpy
433
*-----------------------------------------------------------------------------
435
typedef int VMCIMemcpyToQueueFunc(VMCIQueue *queue, uint64 queueOffset,
436
const void *src, size_t srcOffset,
438
typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset,
439
const VMCIQueue *queue, uint64 queueOffset,
443
*-----------------------------------------------------------------------------
445
533
* VMCIMemcpy{To,From}Queue[v]() prototypes (and, in some cases, an
446
534
* inline version).
908
if (UNLIKELY(VMCIQueuePair_EnqueueToDevNull(produceQueue))) {
820
912
if (UNLIKELY(!VMCIQueuePair_QueueIsMapped(produceQueue) &&
821
913
!VMCIQueuePair_QueueIsMapped(consumeQueue))) {
822
914
return VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
825
freeSpace = VMCIQueue_FreeSpace(produceQueue, consumeQueue,
826
produceQSize); if (!freeSpace) {
917
freeSpace = VMCIQueue_FreeSpace(produceQueue, consumeQueue, produceQSize);
827
919
return VMCI_ERROR_QUEUEPAIR_NOSPACE;
830
921
if (freeSpace < 0) {
831
922
return (ssize_t)freeSpace;
834
written = (size_t)(freeSpace > bufSize ? bufSize : freeSpace);
925
written = MIN((size_t)freeSpace, bufSize);
835
926
tail = VMCIQueue_ProducerTail(produceQueue);
836
927
if (LIKELY(tail + written < produceQSize)) {
837
928
memcpyToQueue(produceQueue, tail, buf, 0, written);
1118
1208
return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
1119
1209
(void *)iov, iovSize, VMCIMemcpyFromQueueV, FALSE);
1211
#endif /* Systems that support struct iovec */
1213
#else /* Windows 32 Host defined below */
1215
int VMCIMemcpyToQueue(VMCIQueue *queue, uint64 queueOffset, const void *src,
1216
size_t srcOffset, size_t size);
1217
int VMCIMemcpyFromQueue(void *dest, size_t destOffset, const VMCIQueue *queue,
1218
uint64 queueOffset, size_t size);
1220
void VMCIQueue_Init(const VMCIHandle handle, VMCIQueue *queue);
1221
void VMCIQueue_GetPointers(const VMCIQueue *produceQ,
1222
const VMCIQueue *consumeQ,
1223
uint64 *producerTail,
1224
uint64 *consumerHead);
1225
int64 VMCIQueue_FreeSpace(const VMCIQueue *produceQueue,
1226
const VMCIQueue *consumeQueue,
1227
const uint64 produceQSize);
1228
int64 VMCIQueue_BufReady(const VMCIQueue *consumeQueue,
1229
const VMCIQueue *produceQueue,
1230
const uint64 consumeQSize);
1231
ssize_t VMCIQueue_Enqueue(VMCIQueue *produceQueue,
1232
const VMCIQueue *consumeQueue,
1233
const uint64 produceQSize,
1236
ssize_t VMCIQueue_Dequeue(VMCIQueue *produceQueue,
1237
const VMCIQueue *consumeQueue,
1238
const uint64 consumeQSize,
1241
ssize_t VMCIQueue_Peek(VMCIQueue *produceQueue,
1242
const VMCIQueue *consumeQueue,
1243
const uint64 consumeQSize,
1247
#endif /* defined _WIN32 && !defined VMX86_TOOLS */
1123
1249
#endif /* !_PUBLIC_VMCI_QUEUE_PAIR_H_ */