1
/*********************************************************
2
* Copyright (C) 2006 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
* Platform independent routines for VMCI calls.
25
#include "vmci_kernel_if.h"
26
#include "vm_assert.h"
27
#include "vmci_defs.h"
28
#include "vmci_infrastructure.h"
29
#include "vmciCommonInt.h"
30
#include "vmciContext.h"
31
#include "vmciDatagram.h"
32
#include "vmciDoorbell.h"
33
#include "vmciDriver.h"
34
#include "vmciEvent.h"
35
#include "vmciKernelAPI.h"
36
#include "vmciQueuePair.h"
37
#include "vmciResource.h"
39
# include "vmciVmkInt.h"
41
# include "helper_ext.h"
44
#define LGPFX "VMCIContext: "
46
static void VMCIContextFreeContext(VMCIContext *context);
47
static Bool VMCIContextExists(VMCIId cid);
48
static int VMCIContextFireNotification(VMCIId contextID,
49
VMCIPrivilegeFlags privFlags,
53
* List of current VMCI contexts.
64
*----------------------------------------------------------------------
66
* VMCIContextSignalNotify --
68
* Sets the notify flag to TRUE. Assumes that the context lock is
77
*----------------------------------------------------------------------
81
VMCIContextSignalNotify(VMCIContext *context) // IN:
84
if (context->notify) {
85
*context->notify = TRUE;
92
*----------------------------------------------------------------------
94
* VMCIContextClearNotify --
96
* Sets the notify flag to FALSE. Assumes that the context lock is
105
*----------------------------------------------------------------------
109
VMCIContextClearNotify(VMCIContext *context) // IN:
112
if (context->notify) {
113
*context->notify = FALSE;
120
*----------------------------------------------------------------------
122
* VMCIContextClearNotifyAndCall --
124
* If nothing requires the attention of the guest, clears both
125
* notify flag and call.
133
*----------------------------------------------------------------------
137
VMCIContextClearNotifyAndCall(VMCIContext *context) // IN:
139
if (context->pendingDatagrams == 0 &&
140
VMCIHandleArray_GetSize(context->pendingDoorbellArray) == 0) {
141
VMCIHost_ClearCall(&context->hostContext);
142
VMCIContextClearNotify(context);
149
*----------------------------------------------------------------------
151
* VMCIContext_CheckAndSignalNotify --
153
* Sets the context's notify flag iff datagrams are pending for this
154
* context. Called from VMCISetupNotify().
162
*----------------------------------------------------------------------
166
VMCIContext_CheckAndSignalNotify(VMCIContext *context) // IN:
171
VMCI_GrabLock(&contextList.lock, &flags);
172
if (context->pendingDatagrams) {
173
VMCIContextSignalNotify(context);
175
VMCI_ReleaseLock(&contextList.lock, flags);
181
*----------------------------------------------------------------------
183
* VMCIContextGetDomainName --
185
* Internal function for retrieving a context domain name, if
186
* supported by the platform. The returned pointer can only be
187
* assumed valid while a reference count is held on the given
191
* Pointer to name if appropriate. NULL otherwise.
196
*----------------------------------------------------------------------
200
VMCIContextGetDomainName(VMCIContext *context) // IN
203
return context->domainName;
211
*----------------------------------------------------------------------
213
* VMCIContext_Init --
215
* Initializes the VMCI context module.
223
*----------------------------------------------------------------------
227
VMCIContext_Init(void)
229
VMCIList_Init(&contextList.head);
230
VMCI_InitLock(&contextList.lock, "VMCIContextListLock",
231
VMCI_LOCK_RANK_HIGHER);
232
VMCI_InitLock(&contextList.firingLock, "VMCIContextFiringLock",
233
VMCI_LOCK_RANK_MIDDLE_LOW);
240
*----------------------------------------------------------------------
242
* VMCIContext_Exit --
244
* Cleans up the contexts module.
252
*----------------------------------------------------------------------
256
VMCIContext_Exit(void)
258
VMCI_CleanupLock(&contextList.firingLock);
259
VMCI_CleanupLock(&contextList.lock);
264
*----------------------------------------------------------------------
266
* VMCIContext_InitContext --
268
* Allocates and initializes a VMCI context.
271
* Returns 0 on success, appropriate error code otherwise.
276
*----------------------------------------------------------------------
280
VMCIContext_InitContext(VMCIId cid, // IN
281
VMCIPrivilegeFlags privFlags, // IN
282
uintptr_t eventHnd, // IN
283
int userVersion, // IN: User's vers no.
284
VMCIHostUser *user, // IN
285
VMCIContext **outContext) // OUT
288
VMCIContext *context;
291
if (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
292
VMCI_DEBUG_LOG(4, (LGPFX"Invalid flag (flags=0x%x) for VMCI context.\n",
294
return VMCI_ERROR_INVALID_ARGS;
297
if (userVersion == 0) {
298
return VMCI_ERROR_INVALID_ARGS;
301
context = VMCI_AllocKernelMem(sizeof *context, VMCI_MEMORY_NONPAGED);
302
if (context == NULL) {
303
VMCI_WARNING((LGPFX"Failed to allocate memory for VMCI context.\n"));
304
return VMCI_ERROR_NO_MEM;
306
memset(context, 0, sizeof *context);
308
VMCIList_InitEntry(&context->listItem);
309
VMCIList_Init(&context->datagramQueue);
311
context->userVersion = userVersion;
313
context->wellKnownArray = VMCIHandleArray_Create(0);
314
if (context->wellKnownArray == NULL) {
315
result = VMCI_ERROR_NO_MEM;
319
context->queuePairArray = VMCIHandleArray_Create(0);
320
if (!context->queuePairArray) {
321
result = VMCI_ERROR_NO_MEM;
325
context->doorbellArray = VMCIHandleArray_Create(0);
326
if (!context->doorbellArray) {
327
result = VMCI_ERROR_NO_MEM;
331
context->pendingDoorbellArray = VMCIHandleArray_Create(0);
332
if (!context->pendingDoorbellArray) {
333
result = VMCI_ERROR_NO_MEM;
337
context->notifierArray = VMCIHandleArray_Create(0);
338
if (context->notifierArray == NULL) {
339
result = VMCI_ERROR_NO_MEM;
343
VMCI_InitLock(&context->lock,
345
VMCI_LOCK_RANK_HIGHER);
346
Atomic_Write(&context->refCount, 1);
348
/* Inititialize host-specific VMCI context. */
349
VMCIHost_InitContext(&context->hostContext, eventHnd);
351
context->privFlags = privFlags;
354
* If we collide with an existing context we generate a new and use it
355
* instead. The VMX will determine if regeneration is okay. Since there
356
* isn't 4B - 16 VMs running on a given host, the below loop will terminate.
358
VMCI_GrabLock(&contextList.lock, &flags);
359
ASSERT(cid != VMCI_INVALID_ID);
360
while (VMCIContextExists(cid)) {
363
* If the cid is below our limit and we collide we are creating duplicate
364
* contexts internally so we want to assert fail in that case.
366
ASSERT(cid >= VMCI_RESERVED_CID_LIMIT);
368
/* We reserve the lowest 16 ids for fixed contexts. */
369
cid = MAX(cid, VMCI_RESERVED_CID_LIMIT-1) + 1;
370
if (cid == VMCI_INVALID_ID) {
371
cid = VMCI_RESERVED_CID_LIMIT;
374
ASSERT(!VMCIContextExists(cid));
376
context->validUser = user != NULL;
377
if (context->validUser) {
378
context->user = *user;
380
VMCIList_Insert(&context->listItem, &contextList.head);
381
VMCI_ReleaseLock(&contextList.lock, flags);
385
* Set default domain name.
387
VMCIContext_SetDomainName(context, "");
388
VMCIContext_SetFSRState(context, FALSE, VMCI_INVALID_ID, eventHnd, FALSE);
392
context->notify = NULL;
394
context->notifyPage = NULL;
398
*outContext = context;
402
if (context->notifierArray) {
403
VMCIHandleArray_Destroy(context->notifierArray);
405
if (context->wellKnownArray) {
406
VMCIHandleArray_Destroy(context->wellKnownArray);
408
if (context->queuePairArray) {
409
VMCIHandleArray_Destroy(context->queuePairArray);
411
if (context->doorbellArray) {
412
VMCIHandleArray_Destroy(context->doorbellArray);
414
if (context->pendingDoorbellArray) {
415
VMCIHandleArray_Destroy(context->pendingDoorbellArray);
417
VMCI_FreeKernelMem(context, sizeof *context);
423
*----------------------------------------------------------------------
425
* VMCIContext_ReleaseContext --
427
* Cleans up a VMCI context.
435
*----------------------------------------------------------------------
439
VMCIContext_ReleaseContext(VMCIContext *context) // IN
443
/* Dequeue VMCI context. */
445
VMCI_GrabLock(&contextList.lock, &flags);
446
VMCIList_Remove(&context->listItem, &contextList.head);
447
VMCI_ReleaseLock(&contextList.lock, flags);
449
VMCIContext_Release(context);
454
*-----------------------------------------------------------------------------
456
* VMCIContextFreeContext --
458
* Deallocates all parts of a context datastructure. This
459
* functions doesn't lock the context, because it assumes that
460
* the caller is holding the last reference to context. As paged
461
* memory may be freed as part of the call, the function must be
462
* called without holding any spinlocks as this is not allowed on
469
* Paged memory is freed.
471
*-----------------------------------------------------------------------------
475
VMCIContextFreeContext(VMCIContext *context) // IN
479
DatagramQueueEntry *dqEntry;
480
VMCIHandle tempHandle;
482
/* Fire event to all contexts interested in knowing this context is dying. */
483
VMCIContextFireNotification(context->cid, context->privFlags,
484
VMCIContextGetDomainName(context));
487
* Cleanup all wellknown mappings owned by context. Ideally these would
488
* be removed already but we maintain this list to make sure no resources
489
* are leaked. It is updated by the VMCIDatagramAdd/RemoveWellKnownMap.
491
ASSERT(context->wellKnownArray);
492
tempHandle = VMCIHandleArray_RemoveTail(context->wellKnownArray);
493
while (!VMCI_HANDLE_EQUAL(tempHandle, VMCI_INVALID_HANDLE)) {
494
VMCIDatagramRemoveWellKnownMap(tempHandle.resource, context->cid);
495
tempHandle = VMCIHandleArray_RemoveTail(context->wellKnownArray);
500
* Cleanup all queue pair resources attached to context. If the VM dies
501
* without cleaning up, this code will make sure that no resources are
505
tempHandle = VMCIHandleArray_GetEntry(context->queuePairArray, 0);
506
while (!VMCI_HANDLE_EQUAL(tempHandle, VMCI_INVALID_HANDLE)) {
508
if (VMCIQPBroker_Detach(tempHandle, context, TRUE) < VMCI_SUCCESS) {
510
* When VMCIQPBroker_Detach() succeeds it removes the handle from the
511
* array. If detach fails, we must remove the handle ourselves.
513
VMCIHandleArray_RemoveEntry(context->queuePairArray, tempHandle);
515
VMCIQPBroker_Unlock();
516
tempHandle = VMCIHandleArray_GetEntry(context->queuePairArray, 0);
520
* On ESX, all entries in the queuePairArray have been cleaned up
521
* either by the regular VMCI device destroy path or by the world
522
* cleanup destroy path. We assert that no resources are leaked.
525
ASSERT(VMCI_HANDLE_EQUAL(VMCIHandleArray_GetEntry(context->queuePairArray, 0),
526
VMCI_INVALID_HANDLE));
527
#endif /* !VMKERNEL */
530
* It is fine to destroy this without locking the callQueue, as
531
* this is the only thread having a reference to the context.
534
VMCIList_ScanSafe(curr, next, &context->datagramQueue) {
535
dqEntry = VMCIList_Entry(curr, DatagramQueueEntry, listItem);
536
VMCIList_Remove(curr, &context->datagramQueue);
537
ASSERT(dqEntry && dqEntry->dg);
538
ASSERT(dqEntry->dgSize == VMCI_DG_SIZE(dqEntry->dg));
539
VMCI_FreeKernelMem(dqEntry->dg, dqEntry->dgSize);
540
VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry);
543
VMCIHandleArray_Destroy(context->notifierArray);
544
VMCIHandleArray_Destroy(context->wellKnownArray);
545
VMCIHandleArray_Destroy(context->queuePairArray);
546
VMCIHandleArray_Destroy(context->doorbellArray);
547
VMCIHandleArray_Destroy(context->pendingDoorbellArray);
548
VMCI_CleanupLock(&context->lock);
549
VMCIHost_ReleaseContext(&context->hostContext);
552
/* TODO Windows and Mac OS. */
553
VMCIUnsetNotify(context);
556
VMCI_FreeKernelMem(context, sizeof *context);
561
*----------------------------------------------------------------------
563
* VMCIContext_PendingDatagrams --
565
* Returns the current number of pending datagrams. The call may
566
* also serve as a synchronization point for the datagram queue,
567
* as no enqueue operations can occur concurrently.
570
* Length of datagram queue for the given context.
573
* Locks datagram queue.
575
*----------------------------------------------------------------------
579
VMCIContext_PendingDatagrams(VMCIId cid, // IN
580
uint32 *pending) // OUT
582
VMCIContext *context;
585
context = VMCIContext_Get(cid);
586
if (context == NULL) {
587
return VMCI_ERROR_INVALID_ARGS;
590
VMCI_GrabLock(&context->lock, &flags);
592
*pending = context->pendingDatagrams;
594
VMCI_ReleaseLock(&context->lock, flags);
595
VMCIContext_Release(context);
602
* We allow at least 1024 more event datagrams from the hypervisor past the
603
* normally allowed datagrams pending for a given context. We define this
604
* limit on event datagrams from the hypervisor to guard against DoS attack
605
* from a malicious VM which could repeatedly attach to and detach from a queue
606
* pair, causing events to be queued at the destination VM. However, the rate
607
* at which such events can be generated is small since it requires a VM exit
608
* and handling of queue pair attach/detach call at the hypervisor. Event
609
* datagrams may be queued up at the destination VM if it has interrupts
610
* disabled or if it is not draining events for some other reason. 1024
611
* datagrams is a grossly conservative estimate of the time for which
612
* interrupts may be disabled in the destination VM, but at the same time does
613
* not exacerbate the memory pressure problem on the host by much (size of each
614
* event datagram is small).
617
#define VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE \
618
(VMCI_MAX_DATAGRAM_QUEUE_SIZE + \
619
1024 * (sizeof(VMCIDatagram) + sizeof(VMCIEventData_Max)))
623
*----------------------------------------------------------------------
625
* VMCIContext_EnqueueDatagram --
627
* Queues a VMCI datagram for the appropriate target VM
631
* Size of enqueued data on success, appropriate error code otherwise.
636
*----------------------------------------------------------------------
640
VMCIContext_EnqueueDatagram(VMCIId cid, // IN: Target VM
641
VMCIDatagram *dg) // IN:
643
DatagramQueueEntry *dqEntry;
644
VMCIContext *context;
650
vmciDgSize = VMCI_DG_SIZE(dg);
651
ASSERT(vmciDgSize <= VMCI_MAX_DG_SIZE);
653
/* Get the target VM's VMCI context. */
654
context = VMCIContext_Get(cid);
655
if (context == NULL) {
656
VMCI_DEBUG_LOG(4, (LGPFX"Invalid context (ID=0x%x).\n", cid));
657
return VMCI_ERROR_INVALID_ARGS;
660
/* Allocate guest call entry and add it to the target VM's queue. */
661
dqEntry = VMCI_AllocKernelMem(sizeof *dqEntry, VMCI_MEMORY_NONPAGED);
662
if (dqEntry == NULL) {
663
VMCI_WARNING((LGPFX"Failed to allocate memory for datagram.\n"));
664
VMCIContext_Release(context);
665
return VMCI_ERROR_NO_MEM;
668
dqEntry->dgSize = vmciDgSize;
670
VMCIList_InitEntry(&dqEntry->listItem);
672
VMCI_GrabLock(&context->lock, &flags);
674
* We put a higher limit on datagrams from the hypervisor. If the pending
675
* datagram is not from hypervisor, then we check if enqueueing it would
676
* exceed the VMCI_MAX_DATAGRAM_QUEUE_SIZE limit on the destination. If the
677
* pending datagram is from hypervisor, we allow it to be queued at the
678
* destination side provided we don't reach the
679
* VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE limit.
681
if (context->datagramQueueSize + vmciDgSize >=
682
VMCI_MAX_DATAGRAM_QUEUE_SIZE &&
683
(!VMCI_HANDLE_EQUAL(dgSrc,
684
VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
685
VMCI_CONTEXT_RESOURCE_ID)) ||
686
context->datagramQueueSize + vmciDgSize >=
687
VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE)) {
688
VMCI_ReleaseLock(&context->lock, flags);
689
VMCIContext_Release(context);
690
VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry);
691
VMCI_DEBUG_LOG(10, (LGPFX"Context (ID=0x%x) receive queue is full.\n",
693
return VMCI_ERROR_NO_RESOURCES;
696
VMCIList_Insert(&dqEntry->listItem, &context->datagramQueue);
697
context->pendingDatagrams++;
698
context->datagramQueueSize += vmciDgSize;
699
VMCIContextSignalNotify(context);
700
VMCIHost_SignalCall(&context->hostContext);
701
VMCI_ReleaseLock(&context->lock, flags);
702
VMCIContext_Release(context);
707
#undef VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE
711
*----------------------------------------------------------------------
713
* VMCIContextExists --
715
* Internal helper to check if a context with the specified context
716
* ID exists. Assumes the contextList.lock is held.
719
* TRUE if a context exists with the given cid.
725
*----------------------------------------------------------------------
729
VMCIContextExists(VMCIId cid) // IN
731
VMCIContext *context;
735
VMCIList_Scan(next, &contextList.head) {
736
context = VMCIList_Entry(next, VMCIContext, listItem);
737
if (context->cid == cid) {
747
*----------------------------------------------------------------------
749
* VMCIContext_Exists --
751
* Verifies whether a context with the specified context ID exists.
754
* TRUE if a context exists with the given cid.
760
*----------------------------------------------------------------------
764
VMCIContext_Exists(VMCIId cid) // IN
769
VMCI_GrabLock(&contextList.lock, &flags);
770
rv = VMCIContextExists(cid);
771
VMCI_ReleaseLock(&contextList.lock, flags);
777
*----------------------------------------------------------------------
781
* Retrieves VMCI context corresponding to the given cid.
784
* VMCI context on success, NULL otherwise.
789
*----------------------------------------------------------------------
793
VMCIContext_Get(VMCIId cid) // IN
795
VMCIContext *context = NULL;
799
if (cid == VMCI_INVALID_ID) {
803
VMCI_GrabLock(&contextList.lock, &flags);
804
if (VMCIList_Empty(&contextList.head)) {
808
VMCIList_Scan(next, &contextList.head) {
809
context = VMCIList_Entry(next, VMCIContext, listItem);
810
if (context->cid == cid) {
812
* At this point, we are sure that the reference count is
813
* larger already than zero. When starting the destruction of
814
* a context, we always remove it from the context list
815
* before decreasing the reference count. As we found the
816
* context here, it hasn't been destroyed yet. This means
817
* that we are not about to increase the reference count of
818
* something that is in the process of being destroyed.
821
Atomic_Inc(&context->refCount);
827
VMCI_ReleaseLock(&contextList.lock, flags);
828
return (context && context->cid == cid) ? context : NULL;
833
*----------------------------------------------------------------------
835
* VMCIContext_Release --
837
* Releases the VMCI context. If this is the last reference to
838
* the context it will be deallocated. A context is created with
839
* a reference count of one, and on destroy, it is removed from
840
* the context list before its reference count is
841
* decremented. Thus, if we reach zero, we are sure that nobody
842
* else are about to increment it (they need the entry in the
843
* context list for that). This function musn't be called with a
850
* Paged memory may be deallocated.
852
*----------------------------------------------------------------------
856
VMCIContext_Release(VMCIContext *context) // IN
860
refCount = Atomic_FetchAndDec(&context->refCount);
862
VMCIContextFreeContext(context);
868
*----------------------------------------------------------------------
870
* VMCIContext_DequeueDatagram --
872
* Dequeues the next datagram and returns it to caller.
873
* The caller passes in a pointer to the max size datagram
874
* it can handle and the datagram is only unqueued if the
875
* size is less than maxSize. If larger maxSize is set to
876
* the size of the datagram to give the caller a chance to
877
* set up a larger buffer for the guestcall.
880
* On success: 0 if no more pending datagrams, otherwise the size of
881
* the next pending datagram.
882
* On failure: appropriate error code.
887
*----------------------------------------------------------------------
891
VMCIContext_DequeueDatagram(VMCIContext *context, // IN
892
size_t *maxSize, // IN/OUT: max size of datagram caller can handle.
893
VMCIDatagram **dg) // OUT:
895
DatagramQueueEntry *dqEntry;
896
VMCIListItem *listItem;
900
ASSERT(context && dg);
902
/* Dequeue the next datagram entry. */
903
VMCI_GrabLock(&context->lock, &flags);
904
if (context->pendingDatagrams == 0) {
905
VMCIContextClearNotifyAndCall(context);
906
VMCI_ReleaseLock(&context->lock, flags);
907
VMCI_DEBUG_LOG(4, (LGPFX"No datagrams pending.\n"));
908
return VMCI_ERROR_NO_MORE_DATAGRAMS;
911
listItem = VMCIList_First(&context->datagramQueue);
912
ASSERT (listItem != NULL);
914
dqEntry = VMCIList_Entry(listItem, DatagramQueueEntry, listItem);
917
/* Check size of caller's buffer. */
918
if (*maxSize < dqEntry->dgSize) {
919
*maxSize = dqEntry->dgSize;
920
VMCI_ReleaseLock(&context->lock, flags);
921
VMCI_DEBUG_LOG(4, (LGPFX"Caller's buffer should be at least "
922
"(size=%u bytes).\n", (uint32)*maxSize));
923
return VMCI_ERROR_NO_MEM;
926
VMCIList_Remove(listItem, &context->datagramQueue);
927
context->pendingDatagrams--;
928
context->datagramQueueSize -= dqEntry->dgSize;
929
if (context->pendingDatagrams == 0) {
930
VMCIContextClearNotifyAndCall(context);
934
* Return the size of the next datagram.
936
DatagramQueueEntry *nextEntry;
938
listItem = VMCIList_First(&context->datagramQueue);
940
nextEntry = VMCIList_Entry(listItem, DatagramQueueEntry, listItem);
941
ASSERT(nextEntry && nextEntry->dg);
943
* The following size_t -> int truncation is fine as the maximum size of
944
* a (routable) datagram is 68KB.
946
rv = (int)nextEntry->dgSize;
948
VMCI_ReleaseLock(&context->lock, flags);
950
/* Caller must free datagram. */
951
ASSERT(dqEntry->dgSize == VMCI_DG_SIZE(dqEntry->dg));
954
VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry);
962
*----------------------------------------------------------------------
964
* VMCIContext_SetFSRState --
966
* Set the states related to FSR (quiesced state, migrateCid,
967
* active event handle).
975
*----------------------------------------------------------------------
979
VMCIContext_SetFSRState(VMCIContext *context, // IN
980
Bool isQuiesced, // IN
981
VMCIId migrateCid, // IN
982
uintptr_t eventHnd, // IN
990
VMCI_GrabLock(&context->lock, &flags);
992
context->isQuiesced = isQuiesced;
993
context->migrateCid = migrateCid;
994
VMCIHost_SetActiveHnd(&context->hostContext, eventHnd);
996
VMCI_ReleaseLock(&context->lock, flags);
1002
*----------------------------------------------------------------------
1004
* VMCIContext_FindAndUpdateSrcFSR --
1006
* Find the source context for fast-suspend-resume. If found, the
1007
* source context's FSR state is changed to reflect the new active
1011
* If found, source context for fast-suspend-resume, NULL otherwise.
1014
* The source context reference count increased and the caller is
1015
* supposed to release the context once it is done using it.
1017
*----------------------------------------------------------------------
1021
VMCIContext_FindAndUpdateSrcFSR(VMCIId migrateCid, // IN
1022
uintptr_t eventHnd, // IN
1023
uintptr_t *srcEventHnd) // IN/OUT
1025
VMCIContext *contextSrc = VMCIContext_Get(migrateCid);
1028
VMCILockFlags flags;
1030
VMCI_GrabLock(&contextSrc->lock, &flags);
1031
if (contextSrc->isQuiesced && contextSrc->migrateCid == migrateCid) {
1033
*srcEventHnd = VMCIHost_GetActiveHnd(&contextSrc->hostContext);
1034
ASSERT(*srcEventHnd != VMCI_INVALID_ID);
1036
VMCIContext_SetFSRState(contextSrc, FALSE, VMCI_INVALID_ID,
1038
VMCI_ReleaseLock(&contextSrc->lock, flags);
1041
VMCI_ReleaseLock(&contextSrc->lock, flags);
1042
VMCIContext_Release(contextSrc);
1049
*----------------------------------------------------------------------
1051
* VMCIContext_IsActiveHnd --
1053
* Whether the curent event handle is the active handle.
1056
* TRUE if the event handle is active, FALSE otherwise.
1061
*----------------------------------------------------------------------
1064
VMCIContext_IsActiveHnd(VMCIContext *context, // IN
1065
uintptr_t eventHnd) // IN
1067
VMCILockFlags flags;
1071
VMCI_GrabLock(&context->lock, &flags);
1072
isActive = VMCIHost_IsActiveHnd(&context->hostContext, eventHnd);
1073
VMCI_ReleaseLock(&context->lock, flags);
1079
*----------------------------------------------------------------------
1081
* VMCIContext_SetInactiveHnd --
1083
* Set the handle to be the inactive one.
1091
*----------------------------------------------------------------------
1095
VMCIContext_SetInactiveHnd(VMCIContext *context, // IN
1096
uintptr_t eventHnd) // IN
1098
VMCILockFlags flags;
1101
VMCI_GrabLock(&context->lock, &flags);
1102
VMCIHost_SetInactiveHnd(&context->hostContext, eventHnd);
1103
VMCI_ReleaseLock(&context->lock, flags);
1108
*----------------------------------------------------------------------
1110
* VMCIContext_RemoveHnd --
1112
* Remove the event handle from host context.
1115
* Whether the handle exists and removed, also number of handles
1116
* before removal and number of handles after removal.
1119
* If this is active handle, the inactive handle becomes active.
1121
*----------------------------------------------------------------------
1125
VMCIContext_RemoveHnd(VMCIContext *context, // IN
1126
uintptr_t eventHnd, // IN
1127
uint32 *numOld, // OUT
1128
uint32 *numNew) // OUT
1130
VMCILockFlags flags;
1131
uint32 numHandleOld, numHandleNew;
1135
VMCI_GrabLock(&context->lock, &flags);
1136
numHandleOld = VMCIHost_NumHnds(&context->hostContext);
1137
ret = VMCIHost_RemoveHnd(&context->hostContext, eventHnd);
1138
numHandleNew = VMCIHost_NumHnds(&context->hostContext);
1140
* This is needed to prevent FSR to share this
1141
* context while this context is being destroyed.
1143
if (ret && numHandleOld == 1 && numHandleNew == 1) {
1144
context->migrateCid = VMCI_INVALID_ID;
1146
VMCI_ReleaseLock(&context->lock, flags);
1149
*numOld = numHandleOld;
1152
*numNew = numHandleNew;
1159
*-----------------------------------------------------------------------------
1161
* VMCIContext_ClearDatagrams --
1163
* Clear pending datagrams.
1171
*-----------------------------------------------------------------------------
1175
VMCIContext_ClearDatagrams(VMCIContext *context) // IN
1178
VMCIDatagram *dg = NULL;
1179
size_t size = VMCI_MAX_DG_SIZE;
1182
/* Drop all datagrams that are currently pending for given context. */
1183
if (context == NULL) {
1186
retval = VMCIContext_PendingDatagrams(context->cid, &pending);
1187
if (retval != VMCI_SUCCESS) {
1189
* This shouldn't happen as we already verified that the context
1198
* We drain the queue for any datagrams pending at the beginning of
1199
* the loop. As datagrams may arrive at any point in time, we
1200
* cannot guarantee that the queue is empty after this point. Only
1201
* removing a fixed number of pending datagrams prevents us from
1205
while (pending > 0 &&
1206
VMCIContext_DequeueDatagram(context, &size, &dg) >= 0) {
1208
VMCI_FreeKernelMem(dg, VMCI_DG_SIZE(dg));
1215
*----------------------------------------------------------------------
1217
* VMCIContext_SetId --
1219
* Set the cid of given VMCI context.
1227
*----------------------------------------------------------------------
1231
VMCIContext_SetId(VMCIContext *context, // IN
1234
VMCILockFlags flags;
1239
VMCI_GrabLock(&context->lock, &flags);
1241
VMCI_ReleaseLock(&context->lock, flags);
1247
*----------------------------------------------------------------------
1249
* VMCIContext_GetId --
1251
* Retrieves cid of given VMCI context.
1254
* VMCIId of context on success, VMCI_INVALID_ID otherwise.
1259
*----------------------------------------------------------------------
1263
VMCIContext_GetId(VMCIContext *context) // IN:
1266
return VMCI_INVALID_ID;
1268
ASSERT(context->cid != VMCI_INVALID_ID);
1269
return context->cid;
1274
*----------------------------------------------------------------------
1276
* VMCIContext_GetPrivFlags --
1278
* Retrieves the privilege flags of the given VMCI context ID.
1281
* Context's privilege flags.
1286
*----------------------------------------------------------------------
1289
VMCI_EXPORT_SYMBOL(VMCIContext_GetPrivFlags)
1291
VMCIContext_GetPrivFlags(VMCIId contextID) // IN
1293
if (VMCI_HostPersonalityActive()) {
1294
VMCIPrivilegeFlags flags;
1295
VMCIContext *context;
1297
context = VMCIContext_Get(contextID);
1299
return VMCI_LEAST_PRIVILEGE_FLAGS;
1301
flags = context->privFlags;
1302
VMCIContext_Release(context);
1305
return VMCI_NO_PRIVILEGE_FLAGS;
1310
*----------------------------------------------------------------------
1312
* VMCIContext_AddWellKnown --
1314
* Wrapper to call VMCIHandleArray_AppendEntry().
1317
* VMCI_SUCCESS on success, error code otherwise.
1320
* As in VMCIHandleArray_AppendEntry().
1322
*----------------------------------------------------------------------
1326
VMCIContext_AddWellKnown(VMCIId contextID, // IN:
1327
VMCIId wellKnownID) // IN:
1329
VMCILockFlags flags;
1330
VMCIHandle wkHandle;
1331
VMCIContext *context = VMCIContext_Get(contextID);
1332
if (context == NULL) {
1333
return VMCI_ERROR_NOT_FOUND;
1335
wkHandle = VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, wellKnownID);
1336
VMCI_GrabLock(&context->lock, &flags);
1337
VMCIHandleArray_AppendEntry(&context->wellKnownArray, wkHandle);
1338
VMCI_ReleaseLock(&context->lock, flags);
1339
VMCIContext_Release(context);
1341
return VMCI_SUCCESS;
1346
*----------------------------------------------------------------------
1348
* VMCIContext_RemoveWellKnown --
1350
* Wrapper to call VMCIHandleArray_RemoveEntry().
1353
* VMCI_SUCCESS if removed, error code otherwise.
1356
* As in VMCIHandleArray_RemoveEntry().
1358
*----------------------------------------------------------------------
1362
VMCIContext_RemoveWellKnown(VMCIId contextID, // IN:
1363
VMCIId wellKnownID) // IN:
1365
VMCILockFlags flags;
1366
VMCIHandle wkHandle, tmpHandle;
1367
VMCIContext *context = VMCIContext_Get(contextID);
1368
if (context == NULL) {
1369
return VMCI_ERROR_NOT_FOUND;
1371
wkHandle = VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, wellKnownID);
1372
VMCI_GrabLock(&context->lock, &flags);
1373
tmpHandle = VMCIHandleArray_RemoveEntry(context->wellKnownArray, wkHandle);
1374
VMCI_ReleaseLock(&context->lock, flags);
1375
VMCIContext_Release(context);
1377
if (VMCI_HANDLE_EQUAL(tmpHandle, VMCI_INVALID_HANDLE)) {
1378
return VMCI_ERROR_NOT_FOUND;
1380
return VMCI_SUCCESS;
1385
*----------------------------------------------------------------------
1387
* VMCIContext_AddNotification --
1389
* Add remoteCID to list of contexts current contexts wants
1390
* notifications from/about.
1393
* VMCI_SUCCESS on success, error code otherwise.
1396
* As in VMCIHandleArray_AppendEntry().
1398
*----------------------------------------------------------------------
1402
VMCIContext_AddNotification(VMCIId contextID, // IN:
1403
VMCIId remoteCID) // IN:
1405
int result = VMCI_ERROR_ALREADY_EXISTS;
1406
VMCILockFlags flags;
1407
VMCILockFlags firingFlags;
1408
VMCIHandle notifierHandle;
1409
VMCIContext *context = VMCIContext_Get(contextID);
1410
if (context == NULL) {
1411
return VMCI_ERROR_NOT_FOUND;
1414
if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
1415
result = VMCI_ERROR_NO_ACCESS;
1419
notifierHandle = VMCI_MAKE_HANDLE(remoteCID, VMCI_EVENT_HANDLER);
1420
VMCI_GrabLock(&contextList.firingLock, &firingFlags);
1421
VMCI_GrabLock(&context->lock, &flags);
1422
if (!VMCIHandleArray_HasEntry(context->notifierArray, notifierHandle)) {
1423
VMCIHandleArray_AppendEntry(&context->notifierArray, notifierHandle);
1424
result = VMCI_SUCCESS;
1426
VMCI_ReleaseLock(&context->lock, flags);
1427
VMCI_ReleaseLock(&contextList.firingLock, firingFlags);
1429
VMCIContext_Release(context);
1435
*----------------------------------------------------------------------
1437
* VMCIContext_RemoveNotification --
1439
* Remove remoteCID from current context's list of contexts it is
1440
* interested in getting notifications from/about.
1443
* VMCI_SUCCESS on success, error code otherwise.
1448
*----------------------------------------------------------------------
1452
VMCIContext_RemoveNotification(VMCIId contextID, // IN:
1453
VMCIId remoteCID) // IN:
1455
VMCILockFlags flags;
1456
VMCILockFlags firingFlags;
1457
VMCIContext *context = VMCIContext_Get(contextID);
1458
VMCIHandle tmpHandle;
1459
if (context == NULL) {
1460
return VMCI_ERROR_NOT_FOUND;
1462
VMCI_GrabLock(&contextList.firingLock, &firingFlags);
1463
VMCI_GrabLock(&context->lock, &flags);
1465
VMCIHandleArray_RemoveEntry(context->notifierArray,
1466
VMCI_MAKE_HANDLE(remoteCID,
1467
VMCI_EVENT_HANDLER));
1468
VMCI_ReleaseLock(&context->lock, flags);
1469
VMCI_ReleaseLock(&contextList.firingLock, firingFlags);
1470
VMCIContext_Release(context);
1472
if (VMCI_HANDLE_EQUAL(tmpHandle, VMCI_INVALID_HANDLE)) {
1473
return VMCI_ERROR_NOT_FOUND;
1475
return VMCI_SUCCESS;
1480
*----------------------------------------------------------------------
1482
* VMCIContextFireNotification --
1484
* Fire notification for all contexts interested in given cid.
1487
* VMCI_SUCCESS on success, error code otherwise.
1492
*----------------------------------------------------------------------
1496
VMCIContextFireNotification(VMCIId contextID, // IN
1497
VMCIPrivilegeFlags privFlags, // IN
1498
const char *domain) // IN
1500
uint32 i, arraySize;
1502
VMCILockFlags flags;
1503
VMCILockFlags firingFlags;
1504
VMCIHandleArray *subscriberArray;
1505
VMCIHandle contextHandle = VMCI_MAKE_HANDLE(contextID, VMCI_EVENT_HANDLER);
1508
* We create an array to hold the subscribers we find when scanning through
1511
subscriberArray = VMCIHandleArray_Create(0);
1512
if (subscriberArray == NULL) {
1513
return VMCI_ERROR_NO_MEM;
1517
* Scan all contexts to find who is interested in being notified about
1518
* given contextID. We have a special firingLock that we use to synchronize
1519
* across all notification operations. This avoids us having to take the
1520
* context lock for each HasEntry call and it solves a lock ranking issue.
1522
VMCI_GrabLock(&contextList.firingLock, &firingFlags);
1523
VMCI_GrabLock(&contextList.lock, &flags);
1524
VMCIList_Scan(next, &contextList.head) {
1525
VMCIContext *subCtx = VMCIList_Entry(next, VMCIContext, listItem);
1528
* We only deliver notifications of the removal of contexts, if
1529
* the two contexts are allowed to interact.
1532
if (VMCIHandleArray_HasEntry(subCtx->notifierArray, contextHandle) &&
1533
!VMCIDenyInteraction(privFlags, subCtx->privFlags, domain,
1534
VMCIContextGetDomainName(subCtx))) {
1535
VMCIHandleArray_AppendEntry(&subscriberArray,
1536
VMCI_MAKE_HANDLE(subCtx->cid,
1537
VMCI_EVENT_HANDLER));
1540
VMCI_ReleaseLock(&contextList.lock, flags);
1541
VMCI_ReleaseLock(&contextList.firingLock, firingFlags);
1543
/* Fire event to all subscribers. */
1544
arraySize = VMCIHandleArray_GetSize(subscriberArray);
1545
for (i = 0; i < arraySize; i++) {
1548
VMCIEventPayload_Context *evPayload;
1549
char buf[sizeof *eMsg + sizeof *evPayload];
1551
eMsg = (VMCIEventMsg *)buf;
1553
/* Clear out any garbage. */
1554
memset(eMsg, 0, sizeof *eMsg + sizeof *evPayload);
1555
eMsg->hdr.dst = VMCIHandleArray_GetEntry(subscriberArray, i);
1556
eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
1557
VMCI_CONTEXT_RESOURCE_ID);
1558
eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *evPayload -
1560
eMsg->eventData.event = VMCI_EVENT_CTX_REMOVED;
1561
evPayload = VMCIEventMsgPayload(eMsg);
1562
evPayload->contextID = contextID;
1564
result = VMCIDatagram_Dispatch(VMCI_HYPERVISOR_CONTEXT_ID,
1565
(VMCIDatagram *)eMsg, FALSE);
1566
if (result < VMCI_SUCCESS) {
1567
VMCI_DEBUG_LOG(4, (LGPFX"Failed to enqueue event datagram "
1568
"(type=%d) for context (ID=0x%x).\n",
1569
eMsg->eventData.event, eMsg->hdr.dst.context));
1570
/* We continue to enqueue on next subscriber. */
1573
VMCIHandleArray_Destroy(subscriberArray);
1575
return VMCI_SUCCESS;
1580
*----------------------------------------------------------------------
1582
* VMCIContext_GetCheckpointState --
1584
* Get current context's checkpoint state of given type.
1587
* VMCI_SUCCESS on success, error code otherwise.
1592
*----------------------------------------------------------------------
1596
VMCIContext_GetCheckpointState(VMCIId contextID, // IN:
1597
uint32 cptType, // IN:
1598
uint32 *bufSize, // IN/OUT:
1599
char **cptBufPtr) // OUT:
1602
VMCILockFlags flags;
1603
uint32 arraySize, cptDataSize;
1604
VMCIHandleArray *array;
1605
VMCIContext *context;
1609
ASSERT(bufSize && cptBufPtr);
1611
context = VMCIContext_Get(contextID);
1612
if (context == NULL) {
1613
return VMCI_ERROR_NOT_FOUND;
1616
VMCI_GrabLock(&context->lock, &flags);
1617
if (cptType == VMCI_NOTIFICATION_CPT_STATE) {
1618
ASSERT(context->notifierArray);
1619
array = context->notifierArray;
1620
getContextID = TRUE;
1621
} else if (cptType == VMCI_WELLKNOWN_CPT_STATE) {
1622
ASSERT(context->wellKnownArray);
1623
array = context->wellKnownArray;
1624
getContextID = FALSE;
1625
} else if (cptType == VMCI_DOORBELL_CPT_STATE) {
1626
ASSERT(context->doorbellArray);
1627
array = context->doorbellArray;
1628
getContextID = FALSE;
1630
VMCI_DEBUG_LOG(4, (LGPFX"Invalid cpt state (type=%d).\n", cptType));
1631
result = VMCI_ERROR_INVALID_ARGS;
1635
arraySize = VMCIHandleArray_GetSize(array);
1636
if (arraySize > 0) {
1637
if (cptType == VMCI_DOORBELL_CPT_STATE) {
1638
cptDataSize = arraySize * sizeof(VMCIDoorbellCptState);
1640
cptDataSize = arraySize * sizeof(VMCIId);
1642
if (*bufSize < cptDataSize) {
1643
*bufSize = cptDataSize;
1644
result = VMCI_ERROR_MORE_DATA;
1648
cptBuf = VMCI_AllocKernelMem(cptDataSize,
1649
VMCI_MEMORY_NONPAGED | VMCI_MEMORY_ATOMIC);
1650
if (cptBuf == NULL) {
1651
result = VMCI_ERROR_NO_MEM;
1655
for (i = 0; i < arraySize; i++) {
1656
VMCIHandle tmpHandle = VMCIHandleArray_GetEntry(array, i);
1657
if (cptType == VMCI_DOORBELL_CPT_STATE) {
1658
((VMCIDoorbellCptState *)cptBuf)[i].handle = tmpHandle;
1660
((VMCIId *)cptBuf)[i] =
1661
getContextID ? tmpHandle.context : tmpHandle.resource;
1664
*bufSize = cptDataSize;
1665
*cptBufPtr = cptBuf;
1670
result = VMCI_SUCCESS;
1673
VMCI_ReleaseLock(&context->lock, flags);
1674
VMCIContext_Release(context);
1681
*----------------------------------------------------------------------
1683
* VMCIContext_SetCheckpointState --
1685
* Set current context's checkpoint state of given type.
1688
* VMCI_SUCCESS on success, error code otherwise.
1693
*----------------------------------------------------------------------
1697
VMCIContext_SetCheckpointState(VMCIId contextID, // IN:
1698
uint32 cptType, // IN:
1699
uint32 bufSize, // IN:
1700
char *cptBuf) // IN:
1704
int result = VMCI_SUCCESS;
1705
uint32 numIDs = bufSize / sizeof(VMCIId);
1708
if (cptType != VMCI_NOTIFICATION_CPT_STATE &&
1709
cptType != VMCI_WELLKNOWN_CPT_STATE) {
1710
VMCI_DEBUG_LOG(4, (LGPFX"Invalid cpt state (type=%d).\n", cptType));
1711
return VMCI_ERROR_INVALID_ARGS;
1714
for (i = 0; i < numIDs && result == VMCI_SUCCESS; i++) {
1715
currentID = ((VMCIId *)cptBuf)[i];
1716
if (cptType == VMCI_NOTIFICATION_CPT_STATE) {
1717
result = VMCIContext_AddNotification(contextID, currentID);
1718
} else if (cptType == VMCI_WELLKNOWN_CPT_STATE) {
1719
result = VMCIDatagramRequestWellKnownMap(currentID, contextID,
1720
VMCIContext_GetPrivFlags(contextID));
1723
if (result != VMCI_SUCCESS) {
1724
VMCI_DEBUG_LOG(4, (LGPFX"Failed to set cpt state (type=%d) (error=%d).\n",
1732
*----------------------------------------------------------------------
1734
* VMCIContext_ReceiveNotificationsGet --
1736
* Retrieves the specified context's pending notifications in the
1737
* form of a handle array. The handle arrays returned are the
1738
* actual data - not a copy and should not be modified by the
1739
* caller. They must be released using
1740
* VMCIContext_ReceiveNotificationsRelease.
1743
* VMCI_SUCCESS on success, error code otherwise.
1748
*----------------------------------------------------------------------
1752
VMCIContext_ReceiveNotificationsGet(VMCIId contextID, // IN
1753
VMCIHandleArray **dbHandleArray, // OUT
1754
VMCIHandleArray **qpHandleArray) // OUT
1756
VMCIContext *context;
1757
VMCILockFlags flags;
1758
int result = VMCI_SUCCESS;
1760
ASSERT(dbHandleArray && qpHandleArray);
1762
context = VMCIContext_Get(contextID);
1763
if (context == NULL) {
1764
return VMCI_ERROR_NOT_FOUND;
1766
VMCI_GrabLock(&context->lock, &flags);
1768
*dbHandleArray = context->pendingDoorbellArray;
1769
context->pendingDoorbellArray = VMCIHandleArray_Create(0);
1770
if (!context->pendingDoorbellArray) {
1771
context->pendingDoorbellArray = *dbHandleArray;
1772
*dbHandleArray = NULL;
1773
result = VMCI_ERROR_NO_MEM;
1775
*qpHandleArray = NULL;
1777
VMCI_ReleaseLock(&context->lock, flags);
1778
VMCIContext_Release(context);
1785
*----------------------------------------------------------------------
1787
* VMCIContext_ReceiveNotificationsRelease --
1789
* Releases handle arrays with pending notifications previously
1790
* retrieved using VMCIContext_ReceiveNotificationsGet. If the
1791
* notifications were not successfully handed over to the guest,
1792
* success must be false.
1800
*----------------------------------------------------------------------
1804
VMCIContext_ReceiveNotificationsRelease(VMCIId contextID, // IN
1805
VMCIHandleArray *dbHandleArray, // IN
1806
VMCIHandleArray *qpHandleArray, // IN
1809
VMCIContext *context = VMCIContext_Get(contextID);
1812
VMCILockFlags flags;
1814
VMCI_GrabLock(&context->lock, &flags);
1819
* New notifications may have been added while we were not
1820
* holding the context lock, so we transfer any new pending
1821
* doorbell notifications to the old array, and reinstate the
1825
handle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray);
1826
while (!VMCI_HANDLE_INVALID(handle)) {
1827
ASSERT(VMCIHandleArray_HasEntry(context->doorbellArray, handle));
1828
if (!VMCIHandleArray_HasEntry(dbHandleArray, handle)) {
1829
VMCIHandleArray_AppendEntry(&dbHandleArray, handle);
1831
handle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray);
1833
VMCIHandleArray_Destroy(context->pendingDoorbellArray);
1834
context->pendingDoorbellArray = dbHandleArray;
1835
dbHandleArray = NULL;
1837
VMCIContextClearNotifyAndCall(context);
1839
VMCI_ReleaseLock(&context->lock, flags);
1840
VMCIContext_Release(context);
1843
* The OS driver part is holding on to the context for the
1844
* duration of the receive notification ioctl, so it should
1851
if (dbHandleArray) {
1852
VMCIHandleArray_Destroy(dbHandleArray);
1854
if (qpHandleArray) {
1855
VMCIHandleArray_Destroy(qpHandleArray);
1861
*----------------------------------------------------------------------
1863
* VMCIContext_DoorbellCreate --
1865
* Registers that a new doorbell handle has been allocated by the
1866
* context. Only doorbell handles registered can be notified.
1869
* VMCI_SUCCESS on success, appropriate error code otherewise.
1874
*----------------------------------------------------------------------
1878
VMCIContext_DoorbellCreate(VMCIId contextID, // IN
1879
VMCIHandle handle) // IN
1881
VMCIContext *context;
1882
VMCILockFlags flags;
1885
if (contextID == VMCI_INVALID_ID || VMCI_HANDLE_INVALID(handle)) {
1886
return VMCI_ERROR_INVALID_ARGS;
1889
context = VMCIContext_Get(contextID);
1890
if (context == NULL) {
1891
return VMCI_ERROR_NOT_FOUND;
1894
VMCI_GrabLock(&context->lock, &flags);
1895
if (!VMCIHandleArray_HasEntry(context->doorbellArray, handle)) {
1896
VMCIHandleArray_AppendEntry(&context->doorbellArray, handle);
1897
result = VMCI_SUCCESS;
1899
result = VMCI_ERROR_DUPLICATE_ENTRY;
1901
VMCI_ReleaseLock(&context->lock, flags);
1903
VMCIContext_Release(context);
1910
*----------------------------------------------------------------------
1912
* VMCIContext_DoorbellDestroy --
1914
* Unregisters a doorbell handle that was previously registered
1915
* with VMCIContext_DoorbellCreate.
1918
* VMCI_SUCCESS on success, appropriate error code otherewise.
1923
*----------------------------------------------------------------------
1927
VMCIContext_DoorbellDestroy(VMCIId contextID, // IN
1928
VMCIHandle handle) // IN
1930
VMCIContext *context;
1931
VMCILockFlags flags;
1932
VMCIHandle removedHandle;
1934
if (contextID == VMCI_INVALID_ID || VMCI_HANDLE_INVALID(handle)) {
1935
return VMCI_ERROR_INVALID_ARGS;
1938
context = VMCIContext_Get(contextID);
1939
if (context == NULL) {
1940
return VMCI_ERROR_NOT_FOUND;
1943
VMCI_GrabLock(&context->lock, &flags);
1944
removedHandle = VMCIHandleArray_RemoveEntry(context->doorbellArray, handle);
1945
VMCIHandleArray_RemoveEntry(context->pendingDoorbellArray, handle);
1946
VMCI_ReleaseLock(&context->lock, flags);
1948
VMCIContext_Release(context);
1950
if (VMCI_HANDLE_INVALID(removedHandle)) {
1951
return VMCI_ERROR_NOT_FOUND;
1953
return VMCI_SUCCESS;
1959
*----------------------------------------------------------------------
1961
* VMCIContext_DoorbellDestroyAll --
1963
* Unregisters all doorbell handles that were previously
1964
* registered with VMCIContext_DoorbellCreate.
1967
* VMCI_SUCCESS on success, appropriate error code otherewise.
1972
*----------------------------------------------------------------------
1976
VMCIContext_DoorbellDestroyAll(VMCIId contextID) // IN
1978
VMCIContext *context;
1979
VMCILockFlags flags;
1980
VMCIHandle removedHandle;
1982
if (contextID == VMCI_INVALID_ID) {
1983
return VMCI_ERROR_INVALID_ARGS;
1986
context = VMCIContext_Get(contextID);
1987
if (context == NULL) {
1988
return VMCI_ERROR_NOT_FOUND;
1991
VMCI_GrabLock(&context->lock, &flags);
1993
removedHandle = VMCIHandleArray_RemoveTail(context->doorbellArray);
1994
} while(!VMCI_HANDLE_INVALID(removedHandle));
1996
removedHandle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray);
1997
} while(!VMCI_HANDLE_INVALID(removedHandle));
1998
VMCI_ReleaseLock(&context->lock, flags);
2000
VMCIContext_Release(context);
2002
return VMCI_SUCCESS;
2007
*----------------------------------------------------------------------
2009
* VMCIContext_NotifyDoorbell --
2011
* Registers a notification of a doorbell handle initiated by the
2012
* specified source context. The notification of doorbells are
2013
* subject to the same isolation rules as datagram delivery. To
2014
* allow host side senders of notifications a finer granularity
2015
* of sender rights than those assigned to the sending context
2016
* itself, the host context is required to specify a different
2017
* set of privilege flags that will override the privileges of
2018
* the source context.
2021
* VMCI_SUCCESS on success, appropriate error code otherewise.
2026
*----------------------------------------------------------------------
2030
VMCIContext_NotifyDoorbell(VMCIId srcCID, // IN
2031
VMCIHandle handle, // IN
2032
VMCIPrivilegeFlags srcPrivFlags) // IN
2034
VMCIContext *dstContext;
2035
VMCILockFlags flags;
2038
if (VMCI_HANDLE_INVALID(handle)) {
2039
return VMCI_ERROR_INVALID_ARGS;
2042
/* Get the target VM's VMCI context. */
2043
dstContext = VMCIContext_Get(handle.context);
2044
if (dstContext == NULL) {
2045
VMCI_DEBUG_LOG(4, (LGPFX"Invalid context (ID=0x%x).\n", handle.context));
2046
return VMCI_ERROR_INVALID_ARGS;
2049
if (srcCID != handle.context) {
2050
VMCIPrivilegeFlags dstPrivFlags;
2051
#if !defined(VMKERNEL)
2052
char *srcDomain = NULL;
2054
char srcDomain[VMCI_DOMAIN_NAME_MAXLEN];
2056
result = VMCIContext_GetDomainName(srcCID, srcDomain, sizeof srcDomain);
2057
if (result < VMCI_SUCCESS) {
2058
VMCI_WARNING((LGPFX"Failed to get domain name for source context "
2059
"(ID=0x%x).\n", srcCID));
2063
result = VMCIDoorbellGetPrivFlags(handle, &dstPrivFlags);
2064
if (result < VMCI_SUCCESS) {
2065
VMCI_WARNING((LGPFX"Failed to get privilege flags for destination "
2066
"(handle=0x%x:0x%x).\n", handle.context,
2071
if (srcCID != VMCI_HOST_CONTEXT_ID ||
2072
srcPrivFlags == VMCI_NO_PRIVILEGE_FLAGS) {
2073
srcPrivFlags = VMCIContext_GetPrivFlags(srcCID);
2076
if (VMCIDenyInteraction(srcPrivFlags, dstPrivFlags, srcDomain,
2077
VMCIContextGetDomainName(dstContext))) {
2078
result = VMCI_ERROR_NO_ACCESS;
2083
if (handle.context == VMCI_HOST_CONTEXT_ID) {
2084
result = VMCIDoorbellHostContextNotify(srcCID, handle);
2086
VMCI_GrabLock(&dstContext->lock, &flags);
2088
if (!VMCIHandleArray_HasEntry(dstContext->doorbellArray, handle)) {
2089
result = VMCI_ERROR_NOT_FOUND;
2091
if (!VMCIHandleArray_HasEntry(dstContext->pendingDoorbellArray, handle)) {
2092
VMCIHandleArray_AppendEntry(&dstContext->pendingDoorbellArray, handle);
2094
VMCIContextSignalNotify(dstContext);
2095
#if defined(VMKERNEL)
2096
VMCIHost_SignalBitmap(&dstContext->hostContext);
2098
VMCIHost_SignalCall(&dstContext->hostContext);
2101
result = VMCI_SUCCESS;
2103
VMCI_ReleaseLock(&dstContext->lock, flags);
2107
VMCIContext_Release(dstContext);
2116
*----------------------------------------------------------------------
2118
* VMCIContext_SignalPendingDoorbells --
2120
* Signals the guest if any doorbell notifications are
2121
* pending. This is used after the VMCI device is unquiesced to
2122
* ensure that no pending notifications go unnoticed, since
2123
* signals may not be fully processed while the device is
2132
*----------------------------------------------------------------------
2136
VMCIContext_SignalPendingDoorbells(VMCIId contextID)
2138
VMCIContext *context;
2139
VMCILockFlags flags;
2142
context = VMCIContext_Get(contextID);
2148
VMCI_GrabLock(&context->lock, &flags);
2149
pending = VMCIHandleArray_GetSize(context->pendingDoorbellArray) > 0;
2150
VMCI_ReleaseLock(&context->lock, flags);
2153
VMCIHost_SignalBitmap(&context->hostContext);
2156
VMCIContext_Release(context);
2161
*----------------------------------------------------------------------
2163
* VMCIContext_SetDomainName --
2165
* Sets the domain name of the given context.
2168
* VMCI_SUCCESS on success, error code otherwise.
2173
*----------------------------------------------------------------------
2177
VMCIContext_SetDomainName(VMCIContext *context, // IN;
2178
const char *domainName) // IN:
2180
size_t domainNameLen;
2182
if (!context || !domainName) {
2183
return VMCI_ERROR_INVALID_ARGS;
2186
domainNameLen = strlen(domainName);
2187
if (domainNameLen >= sizeof context->domainName) {
2188
return VMCI_ERROR_NO_MEM;
2191
memcpy(context->domainName, domainName, domainNameLen + 1);
2193
return VMCI_SUCCESS;
2198
*----------------------------------------------------------------------
2200
* VMCIContext_GetDomainName --
2202
* Returns the domain name of the given context.
2205
* VMCI_SUCCESS on success, error code otherwise.
2210
*----------------------------------------------------------------------
2214
VMCIContext_GetDomainName(VMCIId contextID, // IN:
2215
char *domainName, // OUT:
2216
size_t domainNameBufSize) // IN:
2218
VMCIContext *context;
2219
int rv = VMCI_SUCCESS;
2220
size_t domainNameLen;
2222
if (contextID == VMCI_INVALID_ID || !domainName || !domainNameBufSize) {
2223
return VMCI_ERROR_INVALID_ARGS;
2226
context = VMCIContext_Get(contextID);
2228
return VMCI_ERROR_NOT_FOUND;
2231
domainNameLen = strlen(context->domainName);
2232
if (domainNameLen >= domainNameBufSize) {
2233
rv = VMCI_ERROR_NO_MEM;
2237
memcpy(domainName, context->domainName, domainNameLen + 1);
2240
VMCIContext_Release(context);
2245
#endif // defined(VMKERNEL)
2249
*----------------------------------------------------------------------
2251
* VMCI_ContextID2HostVmID --
2253
* Maps a context ID to the host specific (process/world) ID
2257
* VMCI_SUCCESS on success, error code otherwise.
2262
*----------------------------------------------------------------------
2265
VMCI_EXPORT_SYMBOL(VMCI_ContextID2HostVmID)
2267
VMCI_ContextID2HostVmID(VMCIId contextID, // IN
2268
void *hostVmID, // OUT
2269
size_t hostVmIDLen) // IN
2271
#if defined(VMKERNEL)
2272
VMCIContext *context;
2276
context = VMCIContext_Get(contextID);
2278
return VMCI_ERROR_NOT_FOUND;
2281
result = VMCIHost_ContextToHostVmID(&context->hostContext, &vmID);
2282
if (result == VMCI_SUCCESS) {
2283
if (sizeof vmID == hostVmIDLen) {
2284
memcpy(hostVmID, &vmID, hostVmIDLen);
2286
result = VMCI_ERROR_INVALID_ARGS;
2290
VMCIContext_Release(context);
2293
#else // !defined(VMKERNEL)
2294
return VMCI_ERROR_UNAVAILABLE;
2300
*----------------------------------------------------------------------
2302
* VMCI_IsContextOwner --
2304
* Determines whether a given host OS specific representation of
2305
* user is the owner of the VM/VMX.
2308
* VMCI_SUCCESS if the hostUser is owner, error code otherwise.
2313
*----------------------------------------------------------------------
2316
VMCI_EXPORT_SYMBOL(VMCI_IsContextOwner)
2318
VMCI_IsContextOwner(VMCIId contextID, // IN
2319
void *hostUser) // IN
2321
if (VMCI_HostPersonalityActive()) {
2322
VMCIContext *context;
2323
VMCIHostUser *user = (VMCIHostUser *)hostUser;
2327
return VMCI_ERROR_UNAVAILABLE;
2331
return VMCI_ERROR_INVALID_ARGS;
2334
context = VMCIContext_Get(contextID);
2336
return VMCI_ERROR_NOT_FOUND;
2339
if (context->validUser) {
2340
retval = VMCIHost_CompareUser(user, &context->user);
2342
retval = VMCI_ERROR_UNAVAILABLE;
2344
VMCIContext_Release(context);
2348
return VMCI_ERROR_UNAVAILABLE;
2353
*----------------------------------------------------------------------
2355
* VMCIContext_SupportsHostQP --
2357
* Can host QPs be connected to this user process. The answer is
2358
* FALSE unless a sufficient version number has previously been set
2362
* VMCI_SUCCESS on success, error code otherwise.
2367
*----------------------------------------------------------------------
2371
VMCIContext_SupportsHostQP(VMCIContext *context) // IN: Context structure
2376
if (!context || context->userVersion < VMCI_VERSION_HOSTQP) {