1
/*********************************************************
2
* Copyright (C) 2007 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation version 2 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
*********************************************************/
22
* Implements the VMCI QueuePair API.
26
# include "driver-config.h"
27
# include <asm/page.h>
28
# include <linux/module.h>
31
#elif defined(__APPLE__)
32
# include <IOKit/IOLib.h>
33
#endif /* __linux__ */
35
#include "vm_assert.h"
36
#include "vmci_kernel_if.h"
37
#include "vmciQueuePairInt.h"
40
#include "vmciEvent.h"
43
#define LGPFX "VMCIQueuePair: "
45
typedef struct QueuePairEntry {
59
typedef struct QueuePairList {
64
static QueuePairList queuePairList;
66
static QueuePairEntry *QueuePairList_FindEntry(VMCIHandle handle);
67
static void QueuePairList_AddEntry(QueuePairEntry *entry);
68
static void QueuePairList_RemoveEntry(QueuePairEntry *entry);
69
static QueuePairEntry *QueuePairList_GetHead(void);
70
static QueuePairEntry *QueuePairEntryCreate(VMCIHandle handle,
71
VMCIId peer, uint32 flags,
74
void *produceQ, void *consumeQ);
75
static void QueuePairEntryDestroy(QueuePairEntry *entry);
76
static int VMCIQueuePairAlloc_HyperCall(const QueuePairEntry *entry);
77
static int VMCIQueuePairAllocHelper(VMCIHandle *handle, VMCIQueue **produceQ,
78
uint64 produceSize, VMCIQueue **consumeQ,
80
VMCIId peer, uint32 flags);
81
static int VMCIQueuePairDetachHelper(VMCIHandle handle);
82
static int QueuePairNotifyPeerLocal(Bool attach, VMCIHandle handle);
86
*-----------------------------------------------------------------------------
88
* QueuePairLock_Init --
90
* Creates the lock protecting the QueuePair list.
98
*-----------------------------------------------------------------------------
102
QueuePairLock_Init(void)
104
VMCIMutex_Init(&queuePairList.mutex);
109
*-----------------------------------------------------------------------------
111
* QueuePairLock_Destroy --
113
* Destroys the lock protecting the QueuePair list.
121
*-----------------------------------------------------------------------------
125
QueuePairLock_Destroy(void)
127
VMCIMutex_Destroy(&queuePairList.mutex); /* No-op on Linux and Windows. */
132
*-----------------------------------------------------------------------------
134
* QueuePairList_Lock --
136
* Acquires the lock protecting the QueuePair list.
144
*-----------------------------------------------------------------------------
148
QueuePairList_Lock(void)
150
VMCIMutex_Acquire(&queuePairList.mutex);
155
*-----------------------------------------------------------------------------
157
* QueuePairList_Unlock --
159
* Releases the lock protecting the QueuePair list.
167
*-----------------------------------------------------------------------------
171
QueuePairList_Unlock(void)
173
VMCIMutex_Release(&queuePairList.mutex);
178
*-----------------------------------------------------------------------------
180
* VMCIQueuePair_Init --
182
* Initalizes QueuePair data structure state.
190
*-----------------------------------------------------------------------------
194
VMCIQueuePair_Init(void)
196
queuePairList.head = NULL;
197
QueuePairLock_Init();
202
*-----------------------------------------------------------------------------
204
* VMCIQueuePair_Exit --
206
* Destroys all QueuePairs. Makes hypercalls to detach from QueuePairs.
214
*-----------------------------------------------------------------------------
218
VMCIQueuePair_Exit(void)
220
QueuePairEntry *entry;
222
QueuePairList_Lock();
224
while ((entry = QueuePairList_GetHead())) {
226
* Don't make a hypercall for local QueuePairs.
228
if (!(entry->flags & VMCI_QPFLAG_LOCAL)) {
229
VMCIQueuePairDetachMsg detachMsg;
231
detachMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
232
VMCI_QUEUEPAIR_DETACH);
233
detachMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
234
detachMsg.hdr.payloadSize = sizeof entry->handle;
235
detachMsg.handle = entry->handle;
237
(void)VMCI_SendDatagram((VMCIDatagram *)&detachMsg);
240
* We cannot fail the exit, so let's reset refCount.
243
QueuePairList_RemoveEntry(entry);
244
QueuePairEntryDestroy(entry);
247
QueuePairList_Unlock();
248
QueuePairLock_Destroy();
253
*-----------------------------------------------------------------------------
255
* QueuePairList_FindEntry --
257
* Searches the list of QueuePairs to find if an entry already exists.
258
* Assumes that the lock on the list is held.
261
* Pointer to the entry if it exists, NULL otherwise.
266
*-----------------------------------------------------------------------------
269
static QueuePairEntry *
270
QueuePairList_FindEntry(VMCIHandle handle) // IN:
274
if (VMCI_HANDLE_INVALID(handle)) {
278
LIST_SCAN(next, queuePairList.head) {
279
QueuePairEntry *entry = LIST_CONTAINER(next, QueuePairEntry, listItem);
281
if (VMCI_HANDLE_EQUAL(entry->handle, handle)) {
291
*-----------------------------------------------------------------------------
293
* QueuePairList_AddEntry --
295
* Appends a QueuePair entry to the list. Assumes that the lock on the
304
*-----------------------------------------------------------------------------
308
QueuePairList_AddEntry(QueuePairEntry *entry) // IN:
311
LIST_QUEUE(&entry->listItem, &queuePairList.head);
317
*-----------------------------------------------------------------------------
319
* QueuePairList_RemoveEntry --
321
* Removes a QueuePair entry from the list. Assumes that the lock on the
330
*-----------------------------------------------------------------------------
334
QueuePairList_RemoveEntry(QueuePairEntry *entry) // IN:
337
LIST_DEL(&entry->listItem, &queuePairList.head);
343
*-----------------------------------------------------------------------------
345
* QueuePairList_GetHead --
347
* Returns the entry from the head of the list. Assumes that the list is
356
*-----------------------------------------------------------------------------
359
static QueuePairEntry *
360
QueuePairList_GetHead(void)
362
ListItem *first = LIST_FIRST(queuePairList.head);
365
QueuePairEntry *entry = LIST_CONTAINER(first, QueuePairEntry, listItem);
374
*-----------------------------------------------------------------------------
376
* VMCIQueuePair_Alloc --
378
* Allocates a VMCI QueuePair. Only checks validity of input arguments.
379
* Real work is done in the OS-specific helper routine.
382
* Success or failure.
385
* Memory is allocated.
387
*-----------------------------------------------------------------------------
391
VMCIQueuePair_Alloc(VMCIHandle *handle, // IN/OUT:
392
VMCIQueue **produceQ, // OUT:
393
uint64 produceSize, // IN:
394
VMCIQueue **consumeQ, // OUT:
395
uint64 consumeSize, // IN:
399
ASSERT_ON_COMPILE(sizeof(VMCIQueueHeader) <= PAGE_SIZE);
401
return VMCIQueuePair_AllocPriv(handle, produceQ, produceSize, consumeQ, consumeSize, peer, flags, VMCI_NO_PRIVILEGE_FLAGS);
406
*-----------------------------------------------------------------------------
408
* VMCIQueuePair_AllocPriv --
410
* Provided for compatibility with the host API. Always returns an error
411
* since requesting privileges from the guest is not allowed. Use
412
* VMCIQueuePair_Alloc instead.
420
*-----------------------------------------------------------------------------
424
VMCIQueuePair_AllocPriv(VMCIHandle *handle, // IN/OUT:
425
VMCIQueue **produceQ, // OUT:
426
uint64 produceSize, // IN:
427
VMCIQueue **consumeQ, // OUT:
428
uint64 consumeSize, // IN:
431
VMCIPrivilegeFlags privFlags) // IN:
433
if (privFlags != VMCI_NO_PRIVILEGE_FLAGS) {
434
return VMCI_ERROR_NO_ACCESS;
437
if (!handle || !produceQ || !consumeQ || (!produceSize && !consumeSize) ||
438
(flags & ~VMCI_QP_ALL_FLAGS)) {
439
return VMCI_ERROR_INVALID_ARGS;
442
return VMCIQueuePairAllocHelper(handle, produceQ, produceSize, consumeQ,
443
consumeSize, peer, flags);
448
*-----------------------------------------------------------------------------
450
* VMCIQueuePair_Detach --
452
* Detaches from a VMCI QueuePair. Only checks validity of input argument.
453
* Real work is done in the OS-specific helper routine.
456
* Success or failure.
461
*-----------------------------------------------------------------------------
465
VMCIQueuePair_Detach(VMCIHandle handle) // IN:
467
if (VMCI_HANDLE_INVALID(handle)) {
468
return VMCI_ERROR_INVALID_ARGS;
470
return VMCIQueuePairDetachHelper(handle);
475
*-----------------------------------------------------------------------------
477
* QueuePairEntryCreate --
479
* Allocates and initializes a QueuePairEntry structure. Allocates a
480
* QueuePair rid (and handle) iff the given entry has an invalid handle.
481
* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved handles. Assumes
482
* that the QP list lock is held by the caller.
485
* Pointer to structure intialized.
490
*-----------------------------------------------------------------------------
494
QueuePairEntryCreate(VMCIHandle handle, // IN:
497
uint64 produceSize, // IN:
498
uint64 consumeSize, // IN:
499
void *produceQ, // IN:
500
void *consumeQ) // IN:
502
static VMCIId queuePairRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
503
QueuePairEntry *entry;
504
const uint64 numPPNs = CEILING(produceSize, PAGE_SIZE) +
505
CEILING(consumeSize, PAGE_SIZE) +
506
2; /* One page each for the queue headers. */
508
ASSERT((produceSize || consumeSize) && produceQ && consumeQ);
510
if (VMCI_HANDLE_INVALID(handle)) {
511
VMCIId contextID = VMCI_GetContextID();
512
VMCIId oldRID = queuePairRID;
515
* Generate a unique QueuePair rid. Keep on trying until we wrap around
518
ASSERT(oldRID > VMCI_RESERVED_RESOURCE_ID_MAX);
520
handle = VMCI_MAKE_HANDLE(contextID, queuePairRID);
521
entry = QueuePairList_FindEntry(handle);
523
if (UNLIKELY(!queuePairRID)) {
525
* Skip the reserved rids.
527
queuePairRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
529
} while (entry && queuePairRID != oldRID);
531
if (UNLIKELY(entry != NULL)) {
532
ASSERT(queuePairRID == oldRID);
534
* We wrapped around --- no rids were free.
540
ASSERT(!VMCI_HANDLE_INVALID(handle) &&
541
QueuePairList_FindEntry(handle) == NULL);
542
entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NORMAL);
544
entry->handle = handle;
546
entry->flags = flags;
547
entry->produceSize = produceSize;
548
entry->consumeSize = consumeSize;
549
entry->numPPNs = numPPNs;
550
memset(&entry->ppnSet, 0, sizeof entry->ppnSet);
551
entry->produceQ = produceQ;
552
entry->consumeQ = consumeQ;
554
INIT_LIST_ITEM(&entry->listItem);
561
*-----------------------------------------------------------------------------
563
* QueuePairEntryDestroy --
565
* Frees a QueuePairEntry structure.
573
*-----------------------------------------------------------------------------
577
QueuePairEntryDestroy(QueuePairEntry *entry) // IN:
580
ASSERT(entry->refCount == 0);
582
VMCI_FreePPNSet(&entry->ppnSet);
583
VMCI_FreeQueue(entry->produceQ, entry->produceSize);
584
VMCI_FreeQueue(entry->consumeQ, entry->consumeSize);
585
VMCI_FreeKernelMem(entry, sizeof *entry);
590
*-----------------------------------------------------------------------------
592
* VMCIQueuePairAlloc_HyperCall --
594
* Helper to make a QueuePairAlloc hypercall.
597
* Result of the hypercall.
600
* Memory is allocated & freed.
602
*-----------------------------------------------------------------------------
606
VMCIQueuePairAlloc_HyperCall(const QueuePairEntry *entry) // IN:
608
VMCIQueuePairAllocMsg *allocMsg;
612
if (!entry || entry->numPPNs <= 2) {
613
return VMCI_ERROR_INVALID_ARGS;
616
ASSERT(!(entry->flags & VMCI_QPFLAG_LOCAL));
618
msgSize = sizeof *allocMsg + (size_t)entry->numPPNs * sizeof(PPN);
619
allocMsg = VMCI_AllocKernelMem(msgSize, VMCI_MEMORY_NONPAGED);
621
return VMCI_ERROR_NO_MEM;
624
allocMsg->hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
625
VMCI_QUEUEPAIR_ALLOC);
626
allocMsg->hdr.src = VMCI_ANON_SRC_HANDLE;
627
allocMsg->hdr.payloadSize = msgSize - VMCI_DG_HEADERSIZE;
628
allocMsg->handle = entry->handle;
629
allocMsg->peer = entry->peer;
630
allocMsg->flags = entry->flags;
631
allocMsg->produceSize = entry->produceSize;
632
allocMsg->consumeSize = entry->consumeSize;
633
allocMsg->numPPNs = entry->numPPNs;
634
result = VMCI_PopulatePPNList((uint8 *)allocMsg + sizeof *allocMsg, &entry->ppnSet);
635
if (result == VMCI_SUCCESS) {
636
result = VMCI_SendDatagram((VMCIDatagram *)allocMsg);
638
VMCI_FreeKernelMem(allocMsg, msgSize);
645
*-----------------------------------------------------------------------------
647
* VMCIQueuePairAllocHelper --
649
* Helper for VMCI QueuePairAlloc. Allocates physical pages for the
650
* QueuePair. Makes OS dependent calls through generic wrappers.
653
* Success or failure.
656
* Memory is allocated.
658
*-----------------------------------------------------------------------------
662
VMCIQueuePairAllocHelper(VMCIHandle *handle, // IN/OUT:
663
VMCIQueue **produceQ, // OUT:
664
uint64 produceSize, // IN:
665
VMCIQueue **consumeQ, // OUT:
666
uint64 consumeSize, // IN:
670
const uint64 numProducePages = CEILING(produceSize, PAGE_SIZE) + 1;
671
const uint64 numConsumePages = CEILING(consumeSize, PAGE_SIZE) + 1;
672
void *myProduceQ = NULL;
673
void *myConsumeQ = NULL;
675
QueuePairEntry *queuePairEntry = NULL;
678
* XXX Check for possible overflow of 'size' arguments when passed to
679
* compat_get_order (after some arithmetic ops).
682
ASSERT(handle && produceQ && consumeQ && (produceSize || consumeSize));
684
QueuePairList_Lock();
686
if ((queuePairEntry = QueuePairList_FindEntry(*handle))) {
687
if (queuePairEntry->flags & VMCI_QPFLAG_LOCAL) {
688
/* Local attach case. */
689
if (queuePairEntry->refCount > 1) {
690
VMCI_LOG((LGPFX "Error attempting to attach more than once.\n"));
691
result = VMCI_ERROR_UNAVAILABLE;
695
if (queuePairEntry->produceSize != consumeSize ||
696
queuePairEntry->consumeSize != produceSize ||
697
queuePairEntry->flags != (flags & ~VMCI_QPFLAG_ATTACH_ONLY)) {
698
VMCI_LOG((LGPFX "Error mismatched queue pair in local attach.\n"));
699
result = VMCI_ERROR_QUEUEPAIR_MISMATCH;
704
* Do a local attach. We swap the consume and produce queues for the
705
* attacher and deliver an attach event.
707
result = QueuePairNotifyPeerLocal(TRUE, *handle);
708
if (result < VMCI_SUCCESS) {
711
myProduceQ = queuePairEntry->consumeQ;
712
myConsumeQ = queuePairEntry->produceQ;
715
result = VMCI_ERROR_ALREADY_EXISTS;
719
myProduceQ = VMCI_AllocQueue(produceSize);
721
VMCI_LOG((LGPFX "Error allocating pages for produce queue.\n"));
722
result = VMCI_ERROR_NO_MEM;
726
myConsumeQ = VMCI_AllocQueue(consumeSize);
728
VMCI_LOG((LGPFX "Error allocating pages for consume queue.\n"));
729
result = VMCI_ERROR_NO_MEM;
733
queuePairEntry = QueuePairEntryCreate(*handle, peer, flags,
734
produceSize, consumeSize,
735
myProduceQ, myConsumeQ);
736
if (!queuePairEntry) {
737
VMCI_LOG((LGPFX "Error allocating memory in %s.\n", __FUNCTION__));
738
result = VMCI_ERROR_NO_MEM;
742
result = VMCI_AllocPPNSet(myProduceQ, numProducePages, myConsumeQ,
743
numConsumePages, &queuePairEntry->ppnSet);
744
if (result < VMCI_SUCCESS) {
745
VMCI_LOG((LGPFX "VMCI_AllocPPNSet failed.\n"));
750
* It's only necessary to notify the host if this queue pair will be
751
* attached to from another context.
753
if (queuePairEntry->flags & VMCI_QPFLAG_LOCAL) {
754
/* Local create case. */
755
VMCIId contextId = VMCI_GetContextID();
758
* Enforce similar checks on local queue pairs as we do for regular ones.
759
* The handle's context must match the creator or attacher context id
760
* (here they are both the current context id) and the attach-only flag
761
* cannot exist during create. We also ensure specified peer is this
762
* context or an invalid one.
764
if (queuePairEntry->handle.context != contextId ||
765
(queuePairEntry->peer != VMCI_INVALID_ID &&
766
queuePairEntry->peer != contextId)) {
767
result = VMCI_ERROR_NO_ACCESS;
771
if (queuePairEntry->flags & VMCI_QPFLAG_ATTACH_ONLY) {
772
result = VMCI_ERROR_NOT_FOUND;
776
result = VMCIQueuePairAlloc_HyperCall(queuePairEntry);
777
if (result < VMCI_SUCCESS) {
778
VMCI_LOG((LGPFX "VMCIQueuePairAlloc_HyperCall result = %d.\n",
784
QueuePairList_AddEntry(queuePairEntry);
787
queuePairEntry->refCount++;
788
*handle = queuePairEntry->handle;
789
*produceQ = (VMCIQueue *)myProduceQ;
790
*consumeQ = (VMCIQueue *)myConsumeQ;
793
* We should initialize the queue pair header pages on a local queue pair
794
* create. For non-local queue pairs, the hypervisor initializes the header
795
* pages in the create step.
797
if ((queuePairEntry->flags & VMCI_QPFLAG_LOCAL) &&
798
queuePairEntry->refCount == 1) {
799
VMCIQueueHeader_Init((*produceQ)->qHeader, *handle);
800
VMCIQueueHeader_Init((*consumeQ)->qHeader, *handle);
803
QueuePairList_Unlock();
808
QueuePairList_Unlock();
809
if (queuePairEntry) {
810
/* The queues will be freed inside the destroy routine. */
811
QueuePairEntryDestroy(queuePairEntry);
814
VMCI_FreeQueue(myProduceQ, produceSize);
817
VMCI_FreeQueue(myConsumeQ, consumeSize);
823
/* This path should only be used when an existing entry was found. */
824
ASSERT(queuePairEntry->refCount > 0);
825
QueuePairList_Unlock();
831
*-----------------------------------------------------------------------------
833
* VMCIQueuePairDetachHelper --
835
* Helper for VMCI QueuePair detach interface on Linux. Frees the physical
836
* pages for the QueuePair.
839
* Success or failure.
842
* Memory may be freed.
844
*-----------------------------------------------------------------------------
848
VMCIQueuePairDetachHelper(VMCIHandle handle) // IN:
851
QueuePairEntry *entry;
854
ASSERT(!VMCI_HANDLE_INVALID(handle));
856
QueuePairList_Lock();
858
entry = QueuePairList_FindEntry(handle);
860
result = VMCI_ERROR_NOT_FOUND;
864
ASSERT(entry->refCount >= 1);
866
if (entry->flags & VMCI_QPFLAG_LOCAL) {
867
result = VMCI_SUCCESS;
869
if (entry->refCount > 1) {
870
result = QueuePairNotifyPeerLocal(FALSE, handle);
871
if (result < VMCI_SUCCESS) {
876
VMCIQueuePairDetachMsg detachMsg;
878
detachMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
879
VMCI_QUEUEPAIR_DETACH);
880
detachMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
881
detachMsg.hdr.payloadSize = sizeof handle;
882
detachMsg.handle = handle;
884
result = VMCI_SendDatagram((VMCIDatagram *)&detachMsg);
888
if (result >= VMCI_SUCCESS) {
891
if (entry->refCount == 0) {
892
QueuePairList_RemoveEntry(entry);
896
/* If we didn't remove the entry, this could change once we unlock. */
897
refCount = entry ? entry->refCount :
899
* Value does not matter, silence the
903
QueuePairList_Unlock();
905
if (result >= VMCI_SUCCESS && refCount == 0) {
906
QueuePairEntryDestroy(entry);
913
*----------------------------------------------------------------------------
915
* QueuePairNotifyPeerLocal --
917
* Dispatches a queue pair event message directly into the local event
921
* VMCI_SUCCESS on success, error code otherwise
926
*----------------------------------------------------------------------------
930
QueuePairNotifyPeerLocal(Bool attach, // IN: attach or detach?
931
VMCIHandle handle) // IN: queue pair handle
934
VMCIEventPayload_QP *ePayload;
935
/* buf is only 48 bytes. */
936
char buf[sizeof *eMsg + sizeof *ePayload];
939
contextId = VMCI_GetContextID();
941
eMsg = (VMCIEventMsg *)buf;
942
ePayload = VMCIEventMsgPayload(eMsg);
944
eMsg->hdr.dst = VMCI_MAKE_HANDLE(contextId, VMCI_EVENT_HANDLER);
945
eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
946
VMCI_CONTEXT_RESOURCE_ID);
947
eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *ePayload - sizeof eMsg->hdr;
948
eMsg->eventData.event = attach ? VMCI_EVENT_QP_PEER_ATTACH :
949
VMCI_EVENT_QP_PEER_DETACH;
950
ePayload->peerId = contextId;
951
ePayload->handle = handle;
953
return VMCIEvent_Dispatch((VMCIDatagram *)eMsg);