~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to modules/linux/vmci/common/vmciContext.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2006 VMware, Inc. All rights reserved.
 
3
 *
 
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.
 
7
 *
 
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
 
11
 * for more details.
 
12
 *
 
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
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/*
 
20
 * vmciContext.c --
 
21
 *
 
22
 *     Platform independent routines for VMCI calls.
 
23
 */
 
24
 
 
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"
 
38
#if defined(VMKERNEL)
 
39
#  include "vmciVmkInt.h"
 
40
#  include "vm_libc.h"
 
41
#  include "helper_ext.h"
 
42
#endif
 
43
 
 
44
#define LGPFX "VMCIContext: "
 
45
 
 
46
static void VMCIContextFreeContext(VMCIContext *context);
 
47
static Bool VMCIContextExists(VMCIId cid);
 
48
static int VMCIContextFireNotification(VMCIId contextID,
 
49
                                       VMCIPrivilegeFlags privFlags,
 
50
                                       const char *domain);
 
51
 
 
52
/*
 
53
 * List of current VMCI contexts.
 
54
 */
 
55
 
 
56
static struct {
 
57
   VMCIList head;
 
58
   VMCILock lock;
 
59
   VMCILock firingLock;
 
60
} contextList;
 
61
 
 
62
 
 
63
/*
 
64
 *----------------------------------------------------------------------
 
65
 *
 
66
 * VMCIContextSignalNotify --
 
67
 *
 
68
 *      Sets the notify flag to TRUE.  Assumes that the context lock is
 
69
 *      held.
 
70
 *
 
71
 * Results:
 
72
 *      None.
 
73
 *
 
74
 * Side effects:
 
75
 *      None.
 
76
 *
 
77
 *----------------------------------------------------------------------
 
78
 */
 
79
 
 
80
static INLINE void
 
81
VMCIContextSignalNotify(VMCIContext *context) // IN:
 
82
{
 
83
#ifndef VMX86_SERVER
 
84
   if (context->notify) {
 
85
      *context->notify = TRUE;
 
86
   }
 
87
#endif
 
88
}
 
89
 
 
90
 
 
91
/*
 
92
 *----------------------------------------------------------------------
 
93
 *
 
94
 * VMCIContextClearNotify --
 
95
 *
 
96
 *      Sets the notify flag to FALSE.  Assumes that the context lock is
 
97
 *      held.
 
98
 *
 
99
 * Results:
 
100
 *      None.
 
101
 *
 
102
 * Side effects:
 
103
 *      None.
 
104
 *
 
105
 *----------------------------------------------------------------------
 
106
 */
 
107
 
 
108
static INLINE void
 
109
VMCIContextClearNotify(VMCIContext *context) // IN:
 
110
{
 
111
#ifndef VMX86_SERVER
 
112
   if (context->notify) {
 
113
      *context->notify = FALSE;
 
114
   }
 
115
#endif
 
116
}
 
117
 
 
118
 
 
119
/*
 
120
 *----------------------------------------------------------------------
 
121
 *
 
122
 * VMCIContextClearNotifyAndCall --
 
123
 *
 
124
 *      If nothing requires the attention of the guest, clears both
 
125
 *      notify flag and call.
 
126
 *
 
127
 * Results:
 
128
 *      None.
 
129
 *
 
130
 * Side effects:
 
131
 *      None.
 
132
 *
 
133
 *----------------------------------------------------------------------
 
134
 */
 
135
 
 
136
static INLINE void
 
137
VMCIContextClearNotifyAndCall(VMCIContext *context) // IN:
 
138
{
 
139
   if (context->pendingDatagrams == 0 &&
 
140
       VMCIHandleArray_GetSize(context->pendingDoorbellArray) == 0) {
 
141
      VMCIHost_ClearCall(&context->hostContext);
 
142
      VMCIContextClearNotify(context);
 
143
   }
 
144
}
 
145
 
 
146
 
 
147
#ifndef VMX86_SERVER
 
148
/*
 
149
 *----------------------------------------------------------------------
 
150
 *
 
151
 * VMCIContext_CheckAndSignalNotify --
 
152
 *
 
153
 *      Sets the context's notify flag iff datagrams are pending for this
 
154
 *      context.  Called from VMCISetupNotify().
 
155
 *
 
156
 * Results:
 
157
 *      None.
 
158
 *
 
159
 * Side effects:
 
160
 *      None.
 
161
 *
 
162
 *----------------------------------------------------------------------
 
163
 */
 
164
 
 
165
void
 
166
VMCIContext_CheckAndSignalNotify(VMCIContext *context) // IN:
 
167
{
 
168
   VMCILockFlags flags;
 
169
 
 
170
   ASSERT(context);
 
171
   VMCI_GrabLock(&contextList.lock, &flags);
 
172
   if (context->pendingDatagrams) {
 
173
      VMCIContextSignalNotify(context);
 
174
   }
 
175
   VMCI_ReleaseLock(&contextList.lock, flags);
 
176
}
 
177
#endif
 
178
 
 
179
 
 
180
/*
 
181
 *----------------------------------------------------------------------
 
182
 *
 
183
 * VMCIContextGetDomainName --
 
184
 *
 
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
 
188
 *      context.
 
189
 *
 
190
 * Results:
 
191
 *      Pointer to name if appropriate. NULL otherwise.
 
192
 *
 
193
 * Side effects:
 
194
 *      None.
 
195
 *
 
196
 *----------------------------------------------------------------------
 
197
 */
 
198
 
 
199
static INLINE char *
 
200
VMCIContextGetDomainName(VMCIContext *context) // IN
 
201
{
 
202
#ifdef VMKERNEL
 
203
   return context->domainName;
 
204
#else
 
205
   return NULL;
 
206
#endif
 
207
}
 
208
 
 
209
 
 
210
/*
 
211
 *----------------------------------------------------------------------
 
212
 *
 
213
 * VMCIContext_Init --
 
214
 *
 
215
 *      Initializes the VMCI context module.
 
216
 *
 
217
 * Results:
 
218
 *      None.
 
219
 *
 
220
 * Side effects:
 
221
 *      None.
 
222
 *
 
223
 *----------------------------------------------------------------------
 
224
 */
 
225
 
 
226
int
 
227
VMCIContext_Init(void)
 
228
{
 
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);
 
234
 
 
235
   return VMCI_SUCCESS;
 
236
}
 
237
 
 
238
 
 
239
/*
 
240
 *----------------------------------------------------------------------
 
241
 *
 
242
 * VMCIContext_Exit --
 
243
 *
 
244
 *      Cleans up the contexts module.
 
245
 *
 
246
 * Results:
 
247
 *      None.
 
248
 *
 
249
 * Side effects:
 
250
 *      None.
 
251
 *
 
252
 *----------------------------------------------------------------------
 
253
 */
 
254
 
 
255
void
 
256
VMCIContext_Exit(void)
 
257
{
 
258
   VMCI_CleanupLock(&contextList.firingLock);
 
259
   VMCI_CleanupLock(&contextList.lock);
 
260
}
 
261
 
 
262
 
 
263
/*
 
264
 *----------------------------------------------------------------------
 
265
 *
 
266
 * VMCIContext_InitContext --
 
267
 *
 
268
 *      Allocates and initializes a VMCI context.
 
269
 *
 
270
 * Results:
 
271
 *      Returns 0 on success, appropriate error code otherwise.
 
272
 *
 
273
 * Side effects:
 
274
 *      None.
 
275
 *
 
276
 *----------------------------------------------------------------------
 
277
 */
 
278
 
 
279
int
 
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
 
286
{
 
287
   VMCILockFlags flags;
 
288
   VMCIContext *context;
 
289
   int result;
 
290
 
 
291
   if (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
 
292
      VMCI_DEBUG_LOG(4, (LGPFX"Invalid flag (flags=0x%x) for VMCI context.\n",
 
293
                         privFlags));
 
294
      return VMCI_ERROR_INVALID_ARGS;
 
295
   }
 
296
 
 
297
   if (userVersion == 0) {
 
298
      return VMCI_ERROR_INVALID_ARGS;
 
299
   }
 
300
 
 
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;
 
305
   }
 
306
   memset(context, 0, sizeof *context);
 
307
 
 
308
   VMCIList_InitEntry(&context->listItem);
 
309
   VMCIList_Init(&context->datagramQueue);
 
310
 
 
311
   context->userVersion = userVersion;
 
312
 
 
313
   context->wellKnownArray = VMCIHandleArray_Create(0);
 
314
   if (context->wellKnownArray == NULL) {
 
315
      result = VMCI_ERROR_NO_MEM;
 
316
      goto error;
 
317
   }
 
318
 
 
319
   context->queuePairArray = VMCIHandleArray_Create(0);
 
320
   if (!context->queuePairArray) {
 
321
      result = VMCI_ERROR_NO_MEM;
 
322
      goto error;
 
323
   }
 
324
 
 
325
   context->doorbellArray = VMCIHandleArray_Create(0);
 
326
   if (!context->doorbellArray) {
 
327
      result = VMCI_ERROR_NO_MEM;
 
328
      goto error;
 
329
   }
 
330
 
 
331
   context->pendingDoorbellArray = VMCIHandleArray_Create(0);
 
332
   if (!context->pendingDoorbellArray) {
 
333
      result = VMCI_ERROR_NO_MEM;
 
334
      goto error;
 
335
   }
 
336
 
 
337
   context->notifierArray = VMCIHandleArray_Create(0);
 
338
   if (context->notifierArray == NULL) {
 
339
      result = VMCI_ERROR_NO_MEM;
 
340
      goto error;
 
341
   }
 
342
 
 
343
   VMCI_InitLock(&context->lock,
 
344
                 "VMCIContextLock",
 
345
                 VMCI_LOCK_RANK_HIGHER);
 
346
   Atomic_Write(&context->refCount, 1);
 
347
 
 
348
   /* Inititialize host-specific VMCI context. */
 
349
   VMCIHost_InitContext(&context->hostContext, eventHnd);
 
350
 
 
351
   context->privFlags = privFlags;
 
352
 
 
353
   /*
 
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.
 
357
    */
 
358
   VMCI_GrabLock(&contextList.lock, &flags);
 
359
   ASSERT(cid != VMCI_INVALID_ID);
 
360
   while (VMCIContextExists(cid)) {
 
361
 
 
362
      /*
 
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.
 
365
       */
 
366
      ASSERT(cid >= VMCI_RESERVED_CID_LIMIT);
 
367
 
 
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;
 
372
      }
 
373
   }
 
374
   ASSERT(!VMCIContextExists(cid));
 
375
   context->cid = cid;
 
376
   context->validUser = user != NULL;
 
377
   if (context->validUser) {
 
378
      context->user = *user;
 
379
   }
 
380
   VMCIList_Insert(&context->listItem, &contextList.head);
 
381
   VMCI_ReleaseLock(&contextList.lock, flags);
 
382
 
 
383
#ifdef VMKERNEL
 
384
   /*
 
385
    * Set default domain name.
 
386
    */
 
387
   VMCIContext_SetDomainName(context, "");
 
388
   VMCIContext_SetFSRState(context, FALSE, VMCI_INVALID_ID, eventHnd, FALSE);
 
389
#endif
 
390
 
 
391
#ifndef VMX86_SERVER
 
392
   context->notify = NULL;
 
393
#  ifdef __linux__
 
394
   context->notifyPage = NULL;
 
395
#  endif
 
396
#endif
 
397
 
 
398
   *outContext = context;
 
399
   return VMCI_SUCCESS;
 
400
 
 
401
error:
 
402
   if (context->notifierArray) {
 
403
      VMCIHandleArray_Destroy(context->notifierArray);
 
404
   }
 
405
   if (context->wellKnownArray) {
 
406
      VMCIHandleArray_Destroy(context->wellKnownArray);
 
407
   }
 
408
   if (context->queuePairArray) {
 
409
      VMCIHandleArray_Destroy(context->queuePairArray);
 
410
   }
 
411
   if (context->doorbellArray) {
 
412
      VMCIHandleArray_Destroy(context->doorbellArray);
 
413
   }
 
414
   if (context->pendingDoorbellArray) {
 
415
      VMCIHandleArray_Destroy(context->pendingDoorbellArray);
 
416
   }
 
417
   VMCI_FreeKernelMem(context, sizeof *context);
 
418
   return result;
 
419
}
 
420
 
 
421
 
 
422
/*
 
423
 *----------------------------------------------------------------------
 
424
 *
 
425
 * VMCIContext_ReleaseContext --
 
426
 *
 
427
 *      Cleans up a VMCI context.
 
428
 *
 
429
 * Results:
 
430
 *      None.
 
431
 *
 
432
 * Side effects:
 
433
 *      None.
 
434
 *
 
435
 *----------------------------------------------------------------------
 
436
 */
 
437
 
 
438
void
 
439
VMCIContext_ReleaseContext(VMCIContext *context)   // IN
 
440
{
 
441
   VMCILockFlags flags;
 
442
 
 
443
   /* Dequeue VMCI context. */
 
444
 
 
445
   VMCI_GrabLock(&contextList.lock, &flags);
 
446
   VMCIList_Remove(&context->listItem, &contextList.head);
 
447
   VMCI_ReleaseLock(&contextList.lock, flags);
 
448
 
 
449
   VMCIContext_Release(context);
 
450
}
 
451
 
 
452
 
 
453
/*
 
454
 *-----------------------------------------------------------------------------
 
455
 *
 
456
 * VMCIContextFreeContext --
 
457
 *
 
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
 
463
 *      Windows.
 
464
 *
 
465
 * Results:
 
466
 *      None.
 
467
 *
 
468
 * Side effects:
 
469
 *      Paged memory is freed.
 
470
 *
 
471
 *-----------------------------------------------------------------------------
 
472
 */
 
473
 
 
474
static void
 
475
VMCIContextFreeContext(VMCIContext *context)  // IN
 
476
{
 
477
   VMCIListItem *curr;
 
478
   VMCIListItem *next;
 
479
   DatagramQueueEntry *dqEntry;
 
480
   VMCIHandle tempHandle;
 
481
 
 
482
   /* Fire event to all contexts interested in knowing this context is dying. */
 
483
   VMCIContextFireNotification(context->cid, context->privFlags,
 
484
                               VMCIContextGetDomainName(context));
 
485
 
 
486
   /*
 
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.
 
490
    */
 
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);
 
496
   }
 
497
 
 
498
#ifndef VMKERNEL
 
499
   /*
 
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
 
502
    * leaked.
 
503
    */
 
504
 
 
505
   tempHandle = VMCIHandleArray_GetEntry(context->queuePairArray, 0);
 
506
   while (!VMCI_HANDLE_EQUAL(tempHandle, VMCI_INVALID_HANDLE)) {
 
507
      VMCIQPBroker_Lock();
 
508
      if (VMCIQPBroker_Detach(tempHandle, context, TRUE) < VMCI_SUCCESS) {
 
509
         /*
 
510
          * When VMCIQPBroker_Detach() succeeds it removes the handle from the
 
511
          * array.  If detach fails, we must remove the handle ourselves.
 
512
          */
 
513
         VMCIHandleArray_RemoveEntry(context->queuePairArray, tempHandle);
 
514
      }
 
515
      VMCIQPBroker_Unlock();
 
516
      tempHandle = VMCIHandleArray_GetEntry(context->queuePairArray, 0);
 
517
   }
 
518
#else
 
519
   /*
 
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.
 
523
    */
 
524
 
 
525
   ASSERT(VMCI_HANDLE_EQUAL(VMCIHandleArray_GetEntry(context->queuePairArray, 0),
 
526
                            VMCI_INVALID_HANDLE));
 
527
#endif /* !VMKERNEL */
 
528
 
 
529
   /*
 
530
    * It is fine to destroy this without locking the callQueue, as
 
531
    * this is the only thread having a reference to the context.
 
532
    */
 
533
 
 
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);
 
541
   }
 
542
 
 
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);
 
550
#ifndef VMX86_SERVER
 
551
#  ifdef __linux__
 
552
   /* TODO Windows and Mac OS. */
 
553
   VMCIUnsetNotify(context);
 
554
#  endif
 
555
#endif
 
556
   VMCI_FreeKernelMem(context, sizeof *context);
 
557
}
 
558
 
 
559
 
 
560
/*
 
561
 *----------------------------------------------------------------------
 
562
 *
 
563
 * VMCIContext_PendingDatagrams --
 
564
 *
 
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.
 
568
 *
 
569
 * Results:
 
570
 *      Length of datagram queue for the given context.
 
571
 *
 
572
 * Side effects:
 
573
 *      Locks datagram queue.
 
574
 *
 
575
 *----------------------------------------------------------------------
 
576
 */
 
577
 
 
578
int
 
579
VMCIContext_PendingDatagrams(VMCIId cid,      // IN
 
580
                             uint32 *pending) // OUT
 
581
{
 
582
   VMCIContext *context;
 
583
   VMCILockFlags flags;
 
584
 
 
585
   context = VMCIContext_Get(cid);
 
586
   if (context == NULL) {
 
587
      return VMCI_ERROR_INVALID_ARGS;
 
588
   }
 
589
 
 
590
   VMCI_GrabLock(&context->lock, &flags);
 
591
   if (pending) {
 
592
      *pending = context->pendingDatagrams;
 
593
   }
 
594
   VMCI_ReleaseLock(&context->lock, flags);
 
595
   VMCIContext_Release(context);
 
596
 
 
597
   return VMCI_SUCCESS;
 
598
}
 
599
 
 
600
 
 
601
/*
 
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).
 
615
 */
 
616
 
 
617
#define VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE \
 
618
   (VMCI_MAX_DATAGRAM_QUEUE_SIZE + \
 
619
    1024 * (sizeof(VMCIDatagram) + sizeof(VMCIEventData_Max)))
 
620
 
 
621
 
 
622
/*
 
623
 *----------------------------------------------------------------------
 
624
 *
 
625
 * VMCIContext_EnqueueDatagram --
 
626
 *
 
627
 *      Queues a VMCI datagram for the appropriate target VM
 
628
 *      context.
 
629
 *
 
630
 * Results:
 
631
 *      Size of enqueued data on success, appropriate error code otherwise.
 
632
 *
 
633
 * Side effects:
 
634
 *      None.
 
635
 *
 
636
 *----------------------------------------------------------------------
 
637
 */
 
638
 
 
639
int
 
640
VMCIContext_EnqueueDatagram(VMCIId cid,        // IN: Target VM
 
641
                            VMCIDatagram *dg)  // IN:
 
642
{
 
643
   DatagramQueueEntry *dqEntry;
 
644
   VMCIContext *context;
 
645
   VMCILockFlags flags;
 
646
   VMCIHandle dgSrc;
 
647
   size_t vmciDgSize;
 
648
 
 
649
   ASSERT(dg);
 
650
   vmciDgSize = VMCI_DG_SIZE(dg);
 
651
   ASSERT(vmciDgSize <= VMCI_MAX_DG_SIZE);
 
652
 
 
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;
 
658
   }
 
659
 
 
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;
 
666
   }
 
667
   dqEntry->dg = dg;
 
668
   dqEntry->dgSize = vmciDgSize;
 
669
   dgSrc = dg->src;
 
670
   VMCIList_InitEntry(&dqEntry->listItem);
 
671
 
 
672
   VMCI_GrabLock(&context->lock, &flags);
 
673
   /*
 
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.
 
680
    */
 
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",
 
692
                          cid));
 
693
      return VMCI_ERROR_NO_RESOURCES;
 
694
   }
 
695
 
 
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);
 
703
 
 
704
   return vmciDgSize;
 
705
}
 
706
 
 
707
#undef VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE
 
708
 
 
709
 
 
710
/*
 
711
 *----------------------------------------------------------------------
 
712
 *
 
713
 * VMCIContextExists --
 
714
 *
 
715
 *      Internal helper to check if a context with the specified context
 
716
 *      ID exists. Assumes the contextList.lock is held.
 
717
 *
 
718
 * Results:
 
719
 *      TRUE if a context exists with the given cid.
 
720
 *      FALSE otherwise
 
721
 *
 
722
 * Side effects:
 
723
 *      None.
 
724
 *
 
725
 *----------------------------------------------------------------------
 
726
 */
 
727
 
 
728
static Bool
 
729
VMCIContextExists(VMCIId cid)    // IN
 
730
{
 
731
   VMCIContext *context;
 
732
   VMCIListItem *next;
 
733
   Bool rv = FALSE;
 
734
 
 
735
   VMCIList_Scan(next, &contextList.head) {
 
736
      context = VMCIList_Entry(next, VMCIContext, listItem);
 
737
      if (context->cid == cid) {
 
738
         rv = TRUE;
 
739
         break;
 
740
      }
 
741
   }
 
742
   return rv;
 
743
}
 
744
 
 
745
 
 
746
/*
 
747
 *----------------------------------------------------------------------
 
748
 *
 
749
 * VMCIContext_Exists --
 
750
 *
 
751
 *      Verifies whether a context with the specified context ID exists.
 
752
 *
 
753
 * Results:
 
754
 *      TRUE if a context exists with the given cid.
 
755
 *      FALSE otherwise
 
756
 *
 
757
 * Side effects:
 
758
 *      None.
 
759
 *
 
760
 *----------------------------------------------------------------------
 
761
 */
 
762
 
 
763
Bool
 
764
VMCIContext_Exists(VMCIId cid)    // IN
 
765
{
 
766
   VMCILockFlags flags;
 
767
   Bool rv;
 
768
 
 
769
   VMCI_GrabLock(&contextList.lock, &flags);
 
770
   rv = VMCIContextExists(cid);
 
771
   VMCI_ReleaseLock(&contextList.lock, flags);
 
772
   return rv;
 
773
}
 
774
 
 
775
 
 
776
/*
 
777
 *----------------------------------------------------------------------
 
778
 *
 
779
 * VMCIContext_Get --
 
780
 *
 
781
 *      Retrieves VMCI context corresponding to the given cid.
 
782
 *
 
783
 * Results:
 
784
 *      VMCI context on success, NULL otherwise.
 
785
 *
 
786
 * Side effects:
 
787
 *      None.
 
788
 *
 
789
 *----------------------------------------------------------------------
 
790
 */
 
791
 
 
792
VMCIContext *
 
793
VMCIContext_Get(VMCIId cid)  // IN
 
794
{
 
795
   VMCIContext *context = NULL;
 
796
   VMCIListItem *next;
 
797
   VMCILockFlags flags;
 
798
 
 
799
   if (cid == VMCI_INVALID_ID) {
 
800
      return NULL;
 
801
   }
 
802
 
 
803
   VMCI_GrabLock(&contextList.lock, &flags);
 
804
   if (VMCIList_Empty(&contextList.head)) {
 
805
      goto out;
 
806
   }
 
807
 
 
808
   VMCIList_Scan(next, &contextList.head) {
 
809
      context = VMCIList_Entry(next, VMCIContext, listItem);
 
810
      if (context->cid == cid) {
 
811
         /*
 
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.
 
819
          */
 
820
 
 
821
         Atomic_Inc(&context->refCount);
 
822
         break;
 
823
      }
 
824
   }
 
825
 
 
826
out:
 
827
   VMCI_ReleaseLock(&contextList.lock, flags);
 
828
   return (context && context->cid == cid) ? context : NULL;
 
829
}
 
830
 
 
831
 
 
832
/*
 
833
 *----------------------------------------------------------------------
 
834
 *
 
835
 * VMCIContext_Release --
 
836
 *
 
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
 
844
 *      lock held.
 
845
 *
 
846
 * Results:
 
847
 *      None.
 
848
 *
 
849
 * Side effects:
 
850
 *      Paged memory may be deallocated.
 
851
 *
 
852
 *----------------------------------------------------------------------
 
853
 */
 
854
 
 
855
void
 
856
VMCIContext_Release(VMCIContext *context)  // IN
 
857
{
 
858
   uint32 refCount;
 
859
   ASSERT(context);
 
860
   refCount = Atomic_FetchAndDec(&context->refCount);
 
861
   if (refCount == 1) {
 
862
      VMCIContextFreeContext(context);
 
863
   }
 
864
}
 
865
 
 
866
 
 
867
/*
 
868
 *----------------------------------------------------------------------
 
869
 *
 
870
 * VMCIContext_DequeueDatagram --
 
871
 *
 
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.
 
878
 *
 
879
 * Results:
 
880
 *      On success:  0 if no more pending datagrams, otherwise the size of
 
881
 *                   the next pending datagram.
 
882
 *      On failure:  appropriate error code.
 
883
 *
 
884
 * Side effects:
 
885
 *      None.
 
886
 *
 
887
 *----------------------------------------------------------------------
 
888
 */
 
889
 
 
890
int
 
891
VMCIContext_DequeueDatagram(VMCIContext *context, // IN
 
892
                            size_t *maxSize,      // IN/OUT: max size of datagram caller can handle.
 
893
                            VMCIDatagram **dg)    // OUT:
 
894
{
 
895
   DatagramQueueEntry *dqEntry;
 
896
   VMCIListItem *listItem;
 
897
   VMCILockFlags flags;
 
898
   int rv;
 
899
 
 
900
   ASSERT(context && dg);
 
901
 
 
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;
 
909
   }
 
910
 
 
911
   listItem = VMCIList_First(&context->datagramQueue);
 
912
   ASSERT (listItem != NULL);
 
913
 
 
914
   dqEntry = VMCIList_Entry(listItem, DatagramQueueEntry, listItem);
 
915
   ASSERT(dqEntry->dg);
 
916
 
 
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;
 
924
   }
 
925
 
 
926
   VMCIList_Remove(listItem, &context->datagramQueue);
 
927
   context->pendingDatagrams--;
 
928
   context->datagramQueueSize -= dqEntry->dgSize;
 
929
   if (context->pendingDatagrams == 0) {
 
930
      VMCIContextClearNotifyAndCall(context);
 
931
      rv = VMCI_SUCCESS;
 
932
   } else {
 
933
      /*
 
934
       * Return the size of the next datagram.
 
935
       */
 
936
      DatagramQueueEntry *nextEntry;
 
937
 
 
938
      listItem = VMCIList_First(&context->datagramQueue);
 
939
      ASSERT(listItem);
 
940
      nextEntry = VMCIList_Entry(listItem, DatagramQueueEntry, listItem);
 
941
      ASSERT(nextEntry && nextEntry->dg);
 
942
      /*
 
943
       * The following size_t -> int truncation is fine as the maximum size of
 
944
       * a (routable) datagram is 68KB.
 
945
       */
 
946
      rv = (int)nextEntry->dgSize;
 
947
   }
 
948
   VMCI_ReleaseLock(&context->lock, flags);
 
949
 
 
950
   /* Caller must free datagram. */
 
951
   ASSERT(dqEntry->dgSize == VMCI_DG_SIZE(dqEntry->dg));
 
952
   *dg = dqEntry->dg;
 
953
   dqEntry->dg = NULL;
 
954
   VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry);
 
955
 
 
956
   return rv;
 
957
}
 
958
 
 
959
 
 
960
#ifdef VMKERNEL
 
961
/*
 
962
 *----------------------------------------------------------------------
 
963
 *
 
964
 * VMCIContext_SetFSRState --
 
965
 *
 
966
 *      Set the states related to FSR (quiesced state, migrateCid,
 
967
 *      active event handle).
 
968
 *
 
969
 * Results:
 
970
 *      None.
 
971
 *
 
972
 * Side effects:
 
973
 *      None.
 
974
 *
 
975
 *----------------------------------------------------------------------
 
976
 */
 
977
 
 
978
void
 
979
VMCIContext_SetFSRState(VMCIContext *context, // IN
 
980
                        Bool isQuiesced,      // IN
 
981
                        VMCIId migrateCid,    // IN
 
982
                        uintptr_t eventHnd,   // IN
 
983
                        Bool isLocked)        // IN
 
984
{
 
985
   VMCILockFlags flags;
 
986
   if (!context) {
 
987
      return;
 
988
   }
 
989
   if (!isLocked) {
 
990
      VMCI_GrabLock(&context->lock, &flags);
 
991
   }
 
992
   context->isQuiesced = isQuiesced;
 
993
   context->migrateCid = migrateCid;
 
994
   VMCIHost_SetActiveHnd(&context->hostContext, eventHnd);
 
995
   if (!isLocked) {
 
996
      VMCI_ReleaseLock(&context->lock, flags);
 
997
   }
 
998
}
 
999
 
 
1000
 
 
1001
/*
 
1002
 *----------------------------------------------------------------------
 
1003
 *
 
1004
 * VMCIContext_FindAndUpdateSrcFSR --
 
1005
 *
 
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
 
1008
 *      event handle.
 
1009
 *
 
1010
 * Results:
 
1011
 *      If found, source context for fast-suspend-resume, NULL otherwise.
 
1012
 *
 
1013
 * Side effects:
 
1014
 *      The source context reference count increased and the caller is
 
1015
 *      supposed to release the context once it is done using it.
 
1016
 *
 
1017
 *----------------------------------------------------------------------
 
1018
 */
 
1019
 
 
1020
VMCIContext *
 
1021
VMCIContext_FindAndUpdateSrcFSR(VMCIId migrateCid,      // IN
 
1022
                                uintptr_t eventHnd,     // IN
 
1023
                                uintptr_t *srcEventHnd) // IN/OUT
 
1024
{
 
1025
   VMCIContext *contextSrc = VMCIContext_Get(migrateCid);
 
1026
 
 
1027
   if (contextSrc) {
 
1028
      VMCILockFlags flags;
 
1029
 
 
1030
      VMCI_GrabLock(&contextSrc->lock, &flags);
 
1031
      if (contextSrc->isQuiesced && contextSrc->migrateCid == migrateCid) {
 
1032
         if (srcEventHnd) {
 
1033
            *srcEventHnd = VMCIHost_GetActiveHnd(&contextSrc->hostContext);
 
1034
            ASSERT(*srcEventHnd != VMCI_INVALID_ID);
 
1035
         }
 
1036
         VMCIContext_SetFSRState(contextSrc, FALSE, VMCI_INVALID_ID,
 
1037
                                 eventHnd, TRUE);
 
1038
         VMCI_ReleaseLock(&contextSrc->lock, flags);
 
1039
         return contextSrc;
 
1040
      }
 
1041
      VMCI_ReleaseLock(&contextSrc->lock, flags);
 
1042
      VMCIContext_Release(contextSrc);
 
1043
   }
 
1044
   return NULL;
 
1045
}
 
1046
 
 
1047
 
 
1048
/*
 
1049
 *----------------------------------------------------------------------
 
1050
 *
 
1051
 * VMCIContext_IsActiveHnd --
 
1052
 *
 
1053
 *      Whether the curent event handle is the active handle.
 
1054
 *
 
1055
 * Results:
 
1056
 *      TRUE if the event handle is active, FALSE otherwise.
 
1057
 *
 
1058
 * Side effects:
 
1059
 *      None.
 
1060
 *
 
1061
 *----------------------------------------------------------------------
 
1062
 */
 
1063
Bool
 
1064
VMCIContext_IsActiveHnd(VMCIContext *context, // IN
 
1065
                        uintptr_t eventHnd)   // IN
 
1066
{
 
1067
   VMCILockFlags flags;
 
1068
   Bool isActive;
 
1069
 
 
1070
   ASSERT(context);
 
1071
   VMCI_GrabLock(&context->lock, &flags);
 
1072
   isActive = VMCIHost_IsActiveHnd(&context->hostContext, eventHnd);
 
1073
   VMCI_ReleaseLock(&context->lock, flags);
 
1074
   return isActive;
 
1075
}
 
1076
 
 
1077
 
 
1078
/*
 
1079
 *----------------------------------------------------------------------
 
1080
 *
 
1081
 * VMCIContext_SetInactiveHnd --
 
1082
 *
 
1083
 *      Set the handle to be the inactive one.
 
1084
 *
 
1085
 * Results:
 
1086
 *      None.
 
1087
 *
 
1088
 * Side effects:
 
1089
 *      None.
 
1090
 *
 
1091
 *----------------------------------------------------------------------
 
1092
 */
 
1093
 
 
1094
void
 
1095
VMCIContext_SetInactiveHnd(VMCIContext *context, // IN
 
1096
                           uintptr_t eventHnd)   // IN
 
1097
{
 
1098
   VMCILockFlags flags;
 
1099
 
 
1100
   ASSERT(context);
 
1101
   VMCI_GrabLock(&context->lock, &flags);
 
1102
   VMCIHost_SetInactiveHnd(&context->hostContext, eventHnd);
 
1103
   VMCI_ReleaseLock(&context->lock, flags);
 
1104
}
 
1105
 
 
1106
 
 
1107
/*
 
1108
 *----------------------------------------------------------------------
 
1109
 *
 
1110
 * VMCIContext_RemoveHnd --
 
1111
 *
 
1112
 *      Remove the event handle from host context.
 
1113
 *
 
1114
 * Results:
 
1115
 *      Whether the handle exists and removed, also number of handles
 
1116
 *      before removal and number of handles after removal.
 
1117
 *
 
1118
 * Side effects:
 
1119
 *      If this is active handle, the inactive handle becomes active.
 
1120
 *
 
1121
 *----------------------------------------------------------------------
 
1122
 */
 
1123
 
 
1124
Bool
 
1125
VMCIContext_RemoveHnd(VMCIContext *context, // IN
 
1126
                      uintptr_t eventHnd,   // IN
 
1127
                      uint32 *numOld,       // OUT
 
1128
                      uint32 *numNew)       // OUT
 
1129
{
 
1130
   VMCILockFlags flags;
 
1131
   uint32 numHandleOld, numHandleNew;
 
1132
   Bool ret;
 
1133
 
 
1134
   ASSERT(context);
 
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);
 
1139
   /*
 
1140
    * This is needed to prevent FSR to share this
 
1141
    * context while this context is being destroyed.
 
1142
    */
 
1143
   if (ret && numHandleOld == 1 && numHandleNew == 1) {
 
1144
      context->migrateCid = VMCI_INVALID_ID;
 
1145
   }
 
1146
   VMCI_ReleaseLock(&context->lock, flags);
 
1147
 
 
1148
   if (numOld) {
 
1149
      *numOld = numHandleOld;
 
1150
   }
 
1151
   if (numNew) {
 
1152
      *numNew = numHandleNew;
 
1153
   }
 
1154
   return ret;
 
1155
}
 
1156
 
 
1157
 
 
1158
/*
 
1159
 *-----------------------------------------------------------------------------
 
1160
 *
 
1161
 * VMCIContext_ClearDatagrams --
 
1162
 *
 
1163
 *      Clear pending datagrams.
 
1164
 *
 
1165
 * Results:
 
1166
 *      None.
 
1167
 *
 
1168
 * Side effects:
 
1169
 *      None.
 
1170
 *
 
1171
 *-----------------------------------------------------------------------------
 
1172
 */
 
1173
 
 
1174
void
 
1175
VMCIContext_ClearDatagrams(VMCIContext *context) // IN
 
1176
{
 
1177
   int retval;
 
1178
   VMCIDatagram *dg = NULL;
 
1179
   size_t size = VMCI_MAX_DG_SIZE;
 
1180
   uint32 pending;
 
1181
 
 
1182
   /* Drop all datagrams that are currently pending for given context. */
 
1183
   if (context == NULL) {
 
1184
      return;
 
1185
   }
 
1186
   retval = VMCIContext_PendingDatagrams(context->cid, &pending);
 
1187
   if (retval != VMCI_SUCCESS) {
 
1188
      /*
 
1189
       * This shouldn't happen as we already verified that the context
 
1190
       * exists.
 
1191
       */
 
1192
 
 
1193
      ASSERT(FALSE);
 
1194
      return;
 
1195
   }
 
1196
 
 
1197
   /*
 
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
 
1202
    * looping forever.
 
1203
    */
 
1204
 
 
1205
   while (pending > 0 &&
 
1206
          VMCIContext_DequeueDatagram(context, &size, &dg) >= 0) {
 
1207
      ASSERT(dg);
 
1208
      VMCI_FreeKernelMem(dg, VMCI_DG_SIZE(dg));
 
1209
      --pending;
 
1210
   }
 
1211
}
 
1212
 
 
1213
 
 
1214
/*
 
1215
 *----------------------------------------------------------------------
 
1216
 *
 
1217
 * VMCIContext_SetId --
 
1218
 *
 
1219
 *      Set the cid of given VMCI context.
 
1220
 *
 
1221
 * Results:
 
1222
 *      None.
 
1223
 *
 
1224
 * Side effects:
 
1225
 *      None.
 
1226
 *
 
1227
 *----------------------------------------------------------------------
 
1228
 */
 
1229
 
 
1230
void
 
1231
VMCIContext_SetId(VMCIContext *context,         // IN
 
1232
                  VMCIId cid)                   // IN:
 
1233
{
 
1234
   VMCILockFlags flags;
 
1235
 
 
1236
   if (!context) {
 
1237
      return;
 
1238
   }
 
1239
   VMCI_GrabLock(&context->lock, &flags);
 
1240
   context->cid = cid;
 
1241
   VMCI_ReleaseLock(&context->lock, flags);
 
1242
}
 
1243
#endif
 
1244
 
 
1245
 
 
1246
/*
 
1247
 *----------------------------------------------------------------------
 
1248
 *
 
1249
 * VMCIContext_GetId --
 
1250
 *
 
1251
 *      Retrieves cid of given VMCI context.
 
1252
 *
 
1253
 * Results:
 
1254
 *      VMCIId of context on success, VMCI_INVALID_ID otherwise.
 
1255
 *
 
1256
 * Side effects:
 
1257
 *      None.
 
1258
 *
 
1259
 *----------------------------------------------------------------------
 
1260
 */
 
1261
 
 
1262
VMCIId
 
1263
VMCIContext_GetId(VMCIContext *context) // IN:
 
1264
{
 
1265
   if (!context) {
 
1266
      return VMCI_INVALID_ID;
 
1267
   }
 
1268
   ASSERT(context->cid != VMCI_INVALID_ID);
 
1269
   return context->cid;
 
1270
}
 
1271
 
 
1272
 
 
1273
/*
 
1274
 *----------------------------------------------------------------------
 
1275
 *
 
1276
 * VMCIContext_GetPrivFlags --
 
1277
 *
 
1278
 *      Retrieves the privilege flags of the given VMCI context ID.
 
1279
 *
 
1280
 * Results:
 
1281
 *     Context's privilege flags.
 
1282
 *
 
1283
 * Side effects:
 
1284
 *      None.
 
1285
 *
 
1286
 *----------------------------------------------------------------------
 
1287
 */
 
1288
 
 
1289
VMCI_EXPORT_SYMBOL(VMCIContext_GetPrivFlags)
 
1290
VMCIPrivilegeFlags
 
1291
VMCIContext_GetPrivFlags(VMCIId contextID)  // IN
 
1292
{
 
1293
   if (VMCI_HostPersonalityActive()) {
 
1294
      VMCIPrivilegeFlags flags;
 
1295
      VMCIContext *context;
 
1296
 
 
1297
      context = VMCIContext_Get(contextID);
 
1298
      if (!context) {
 
1299
         return VMCI_LEAST_PRIVILEGE_FLAGS;
 
1300
      }
 
1301
      flags = context->privFlags;
 
1302
      VMCIContext_Release(context);
 
1303
      return flags;
 
1304
   }
 
1305
   return VMCI_NO_PRIVILEGE_FLAGS;
 
1306
}
 
1307
 
 
1308
 
 
1309
/*
 
1310
 *----------------------------------------------------------------------
 
1311
 *
 
1312
 * VMCIContext_AddWellKnown --
 
1313
 *
 
1314
 *      Wrapper to call VMCIHandleArray_AppendEntry().
 
1315
 *
 
1316
 * Results:
 
1317
 *      VMCI_SUCCESS on success, error code otherwise.
 
1318
 *
 
1319
 * Side effects:
 
1320
 *      As in VMCIHandleArray_AppendEntry().
 
1321
 *
 
1322
 *----------------------------------------------------------------------
 
1323
 */
 
1324
 
 
1325
int
 
1326
VMCIContext_AddWellKnown(VMCIId contextID,    // IN:
 
1327
                         VMCIId wellKnownID)  // IN:
 
1328
{
 
1329
   VMCILockFlags flags;
 
1330
   VMCIHandle wkHandle;
 
1331
   VMCIContext *context = VMCIContext_Get(contextID);
 
1332
   if (context == NULL) {
 
1333
      return VMCI_ERROR_NOT_FOUND;
 
1334
   }
 
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);
 
1340
 
 
1341
   return VMCI_SUCCESS;
 
1342
}
 
1343
 
 
1344
 
 
1345
/*
 
1346
 *----------------------------------------------------------------------
 
1347
 *
 
1348
 * VMCIContext_RemoveWellKnown --
 
1349
 *
 
1350
 *      Wrapper to call VMCIHandleArray_RemoveEntry().
 
1351
 *
 
1352
 * Results:
 
1353
 *      VMCI_SUCCESS if removed, error code otherwise.
 
1354
 *
 
1355
 * Side effects:
 
1356
 *      As in VMCIHandleArray_RemoveEntry().
 
1357
 *
 
1358
 *----------------------------------------------------------------------
 
1359
 */
 
1360
 
 
1361
int
 
1362
VMCIContext_RemoveWellKnown(VMCIId contextID,    // IN:
 
1363
                            VMCIId wellKnownID)  // IN:
 
1364
{
 
1365
   VMCILockFlags flags;
 
1366
   VMCIHandle wkHandle, tmpHandle;
 
1367
   VMCIContext *context = VMCIContext_Get(contextID);
 
1368
   if (context == NULL) {
 
1369
      return VMCI_ERROR_NOT_FOUND;
 
1370
   }
 
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);
 
1376
 
 
1377
   if (VMCI_HANDLE_EQUAL(tmpHandle, VMCI_INVALID_HANDLE)) {
 
1378
      return VMCI_ERROR_NOT_FOUND;
 
1379
   }
 
1380
   return VMCI_SUCCESS;
 
1381
}
 
1382
 
 
1383
 
 
1384
/*
 
1385
 *----------------------------------------------------------------------
 
1386
 *
 
1387
 * VMCIContext_AddNotification --
 
1388
 *
 
1389
 *      Add remoteCID to list of contexts current contexts wants
 
1390
 *      notifications from/about.
 
1391
 *
 
1392
 * Results:
 
1393
 *      VMCI_SUCCESS on success, error code otherwise.
 
1394
 *
 
1395
 * Side effects:
 
1396
 *      As in VMCIHandleArray_AppendEntry().
 
1397
 *
 
1398
 *----------------------------------------------------------------------
 
1399
 */
 
1400
 
 
1401
int
 
1402
VMCIContext_AddNotification(VMCIId contextID,  // IN:
 
1403
                            VMCIId remoteCID)  // IN:
 
1404
{
 
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;
 
1412
   }
 
1413
 
 
1414
   if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
 
1415
      result = VMCI_ERROR_NO_ACCESS;
 
1416
      goto out;
 
1417
   }
 
1418
 
 
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;
 
1425
   }
 
1426
   VMCI_ReleaseLock(&context->lock, flags);
 
1427
   VMCI_ReleaseLock(&contextList.firingLock, firingFlags);
 
1428
out:
 
1429
   VMCIContext_Release(context);
 
1430
   return result;
 
1431
}
 
1432
 
 
1433
 
 
1434
/*
 
1435
 *----------------------------------------------------------------------
 
1436
 *
 
1437
 * VMCIContext_RemoveNotification --
 
1438
 *
 
1439
 *      Remove remoteCID from current context's list of contexts it is
 
1440
 *      interested in getting notifications from/about.
 
1441
 *
 
1442
 * Results:
 
1443
 *      VMCI_SUCCESS on success, error code otherwise.
 
1444
 *
 
1445
 * Side effects:
 
1446
 *      None.
 
1447
 *
 
1448
 *----------------------------------------------------------------------
 
1449
 */
 
1450
 
 
1451
int
 
1452
VMCIContext_RemoveNotification(VMCIId contextID,  // IN:
 
1453
                               VMCIId remoteCID)  // IN:
 
1454
{
 
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;
 
1461
   }
 
1462
   VMCI_GrabLock(&contextList.firingLock, &firingFlags);
 
1463
   VMCI_GrabLock(&context->lock, &flags);
 
1464
   tmpHandle =
 
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);
 
1471
 
 
1472
   if (VMCI_HANDLE_EQUAL(tmpHandle, VMCI_INVALID_HANDLE)) {
 
1473
      return VMCI_ERROR_NOT_FOUND;
 
1474
   }
 
1475
   return VMCI_SUCCESS;
 
1476
}
 
1477
 
 
1478
 
 
1479
/*
 
1480
 *----------------------------------------------------------------------
 
1481
 *
 
1482
 * VMCIContextFireNotification --
 
1483
 *
 
1484
 *      Fire notification for all contexts interested in given cid.
 
1485
 *
 
1486
 * Results:
 
1487
 *      VMCI_SUCCESS on success, error code otherwise.
 
1488
 *
 
1489
 * Side effects:
 
1490
 *      None.
 
1491
 *
 
1492
 *----------------------------------------------------------------------
 
1493
 */
 
1494
 
 
1495
static int
 
1496
VMCIContextFireNotification(VMCIId contextID,             // IN
 
1497
                            VMCIPrivilegeFlags privFlags, // IN
 
1498
                            const char *domain)           // IN
 
1499
{
 
1500
   uint32 i, arraySize;
 
1501
   VMCIListItem *next;
 
1502
   VMCILockFlags flags;
 
1503
   VMCILockFlags firingFlags;
 
1504
   VMCIHandleArray *subscriberArray;
 
1505
   VMCIHandle contextHandle = VMCI_MAKE_HANDLE(contextID, VMCI_EVENT_HANDLER);
 
1506
 
 
1507
   /*
 
1508
    * We create an array to hold the subscribers we find when scanning through
 
1509
    * all contexts.
 
1510
    */
 
1511
   subscriberArray = VMCIHandleArray_Create(0);
 
1512
   if (subscriberArray == NULL) {
 
1513
      return VMCI_ERROR_NO_MEM;
 
1514
   }
 
1515
 
 
1516
   /*
 
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.
 
1521
    */
 
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);
 
1526
 
 
1527
      /*
 
1528
       * We only deliver notifications of the removal of contexts, if
 
1529
       * the two contexts are allowed to interact.
 
1530
       */
 
1531
 
 
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));
 
1538
      }
 
1539
   }
 
1540
   VMCI_ReleaseLock(&contextList.lock, flags);
 
1541
   VMCI_ReleaseLock(&contextList.firingLock, firingFlags);
 
1542
 
 
1543
   /* Fire event to all subscribers. */
 
1544
   arraySize = VMCIHandleArray_GetSize(subscriberArray);
 
1545
   for (i = 0; i < arraySize; i++) {
 
1546
      int result;
 
1547
      VMCIEventMsg *eMsg;
 
1548
      VMCIEventPayload_Context *evPayload;
 
1549
      char buf[sizeof *eMsg + sizeof *evPayload];
 
1550
 
 
1551
      eMsg = (VMCIEventMsg *)buf;
 
1552
 
 
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 -
 
1559
                              sizeof eMsg->hdr;
 
1560
      eMsg->eventData.event = VMCI_EVENT_CTX_REMOVED;
 
1561
      evPayload = VMCIEventMsgPayload(eMsg);
 
1562
      evPayload->contextID = contextID;
 
1563
 
 
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. */
 
1571
      }
 
1572
   }
 
1573
   VMCIHandleArray_Destroy(subscriberArray);
 
1574
 
 
1575
   return VMCI_SUCCESS;
 
1576
}
 
1577
 
 
1578
 
 
1579
/*
 
1580
 *----------------------------------------------------------------------
 
1581
 *
 
1582
 * VMCIContext_GetCheckpointState --
 
1583
 *
 
1584
 *      Get current context's checkpoint state of given type.
 
1585
 *
 
1586
 * Results:
 
1587
 *      VMCI_SUCCESS on success, error code otherwise.
 
1588
 *
 
1589
 * Side effects:
 
1590
 *      None.
 
1591
 *
 
1592
 *----------------------------------------------------------------------
 
1593
 */
 
1594
 
 
1595
int
 
1596
VMCIContext_GetCheckpointState(VMCIId contextID,    // IN:
 
1597
                               uint32 cptType,      // IN:
 
1598
                               uint32 *bufSize,     // IN/OUT:
 
1599
                               char   **cptBufPtr)  // OUT:
 
1600
{
 
1601
   int i, result;
 
1602
   VMCILockFlags flags;
 
1603
   uint32 arraySize, cptDataSize;
 
1604
   VMCIHandleArray *array;
 
1605
   VMCIContext *context;
 
1606
   char *cptBuf;
 
1607
   Bool getContextID;
 
1608
 
 
1609
   ASSERT(bufSize && cptBufPtr);
 
1610
 
 
1611
   context = VMCIContext_Get(contextID);
 
1612
   if (context == NULL) {
 
1613
      return VMCI_ERROR_NOT_FOUND;
 
1614
   }
 
1615
 
 
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;
 
1629
   } else {
 
1630
      VMCI_DEBUG_LOG(4, (LGPFX"Invalid cpt state (type=%d).\n", cptType));
 
1631
      result = VMCI_ERROR_INVALID_ARGS;
 
1632
      goto release;
 
1633
   }
 
1634
 
 
1635
   arraySize = VMCIHandleArray_GetSize(array);
 
1636
   if (arraySize > 0) {
 
1637
      if (cptType == VMCI_DOORBELL_CPT_STATE) {
 
1638
         cptDataSize = arraySize * sizeof(VMCIDoorbellCptState);
 
1639
      } else {
 
1640
         cptDataSize = arraySize * sizeof(VMCIId);
 
1641
      }
 
1642
      if (*bufSize < cptDataSize) {
 
1643
         *bufSize = cptDataSize;
 
1644
         result = VMCI_ERROR_MORE_DATA;
 
1645
         goto release;
 
1646
      }
 
1647
 
 
1648
      cptBuf = VMCI_AllocKernelMem(cptDataSize,
 
1649
                                   VMCI_MEMORY_NONPAGED | VMCI_MEMORY_ATOMIC);
 
1650
      if (cptBuf == NULL) {
 
1651
         result = VMCI_ERROR_NO_MEM;
 
1652
         goto release;
 
1653
      }
 
1654
 
 
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;
 
1659
         } else {
 
1660
            ((VMCIId *)cptBuf)[i] =
 
1661
               getContextID ? tmpHandle.context : tmpHandle.resource;
 
1662
         }
 
1663
      }
 
1664
      *bufSize = cptDataSize;
 
1665
      *cptBufPtr = cptBuf;
 
1666
   } else {
 
1667
      *bufSize = 0;
 
1668
      *cptBufPtr = NULL;
 
1669
   }
 
1670
   result = VMCI_SUCCESS;
 
1671
 
 
1672
  release:
 
1673
   VMCI_ReleaseLock(&context->lock, flags);
 
1674
   VMCIContext_Release(context);
 
1675
 
 
1676
   return result;
 
1677
}
 
1678
 
 
1679
 
 
1680
/*
 
1681
 *----------------------------------------------------------------------
 
1682
 *
 
1683
 * VMCIContext_SetCheckpointState --
 
1684
 *
 
1685
 *      Set current context's checkpoint state of given type.
 
1686
 *
 
1687
 * Results:
 
1688
 *      VMCI_SUCCESS on success, error code otherwise.
 
1689
 *
 
1690
 * Side effects:
 
1691
 *      None.
 
1692
 *
 
1693
 *----------------------------------------------------------------------
 
1694
 */
 
1695
 
 
1696
int
 
1697
VMCIContext_SetCheckpointState(VMCIId contextID, // IN:
 
1698
                               uint32 cptType,   // IN:
 
1699
                               uint32 bufSize,   // IN:
 
1700
                               char   *cptBuf)   // IN:
 
1701
{
 
1702
   uint32 i;
 
1703
   VMCIId currentID;
 
1704
   int result = VMCI_SUCCESS;
 
1705
   uint32 numIDs = bufSize / sizeof(VMCIId);
 
1706
   ASSERT(cptBuf);
 
1707
 
 
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;
 
1712
   }
 
1713
 
 
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));
 
1721
      }
 
1722
   }
 
1723
   if (result != VMCI_SUCCESS) {
 
1724
      VMCI_DEBUG_LOG(4, (LGPFX"Failed to set cpt state (type=%d) (error=%d).\n",
 
1725
                         cptType, result));
 
1726
   }
 
1727
   return result;
 
1728
}
 
1729
 
 
1730
 
 
1731
/*
 
1732
 *----------------------------------------------------------------------
 
1733
 *
 
1734
 * VMCIContext_ReceiveNotificationsGet --
 
1735
 *
 
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.
 
1741
 *
 
1742
 * Results:
 
1743
 *      VMCI_SUCCESS on success, error code otherwise.
 
1744
 *
 
1745
 * Side effects:
 
1746
 *      None.
 
1747
 *
 
1748
 *----------------------------------------------------------------------
 
1749
 */
 
1750
 
 
1751
int
 
1752
VMCIContext_ReceiveNotificationsGet(VMCIId contextID,                // IN
 
1753
                                    VMCIHandleArray **dbHandleArray, // OUT
 
1754
                                    VMCIHandleArray **qpHandleArray) // OUT
 
1755
{
 
1756
   VMCIContext *context;
 
1757
   VMCILockFlags flags;
 
1758
   int result = VMCI_SUCCESS;
 
1759
 
 
1760
   ASSERT(dbHandleArray && qpHandleArray);
 
1761
 
 
1762
   context = VMCIContext_Get(contextID);
 
1763
   if (context == NULL) {
 
1764
      return VMCI_ERROR_NOT_FOUND;
 
1765
   }
 
1766
   VMCI_GrabLock(&context->lock, &flags);
 
1767
 
 
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;
 
1774
   }
 
1775
   *qpHandleArray = NULL;
 
1776
 
 
1777
   VMCI_ReleaseLock(&context->lock, flags);
 
1778
   VMCIContext_Release(context);
 
1779
 
 
1780
   return result;
 
1781
}
 
1782
 
 
1783
 
 
1784
/*
 
1785
 *----------------------------------------------------------------------
 
1786
 *
 
1787
 * VMCIContext_ReceiveNotificationsRelease --
 
1788
 *
 
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.
 
1793
 *
 
1794
 * Results:
 
1795
 *      None.
 
1796
 *
 
1797
 * Side effects:
 
1798
 *      None.
 
1799
 *
 
1800
 *----------------------------------------------------------------------
 
1801
 */
 
1802
 
 
1803
void
 
1804
VMCIContext_ReceiveNotificationsRelease(VMCIId contextID,               // IN
 
1805
                                        VMCIHandleArray *dbHandleArray, // IN
 
1806
                                        VMCIHandleArray *qpHandleArray, // IN
 
1807
                                        Bool success)                   // IN
 
1808
{
 
1809
   VMCIContext *context = VMCIContext_Get(contextID);
 
1810
 
 
1811
   if (context) {
 
1812
      VMCILockFlags flags;
 
1813
 
 
1814
      VMCI_GrabLock(&context->lock, &flags);
 
1815
      if (!success) {
 
1816
         VMCIHandle handle;
 
1817
 
 
1818
         /*
 
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
 
1822
          * old array.
 
1823
          */
 
1824
 
 
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);
 
1830
            }
 
1831
            handle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray);
 
1832
         }
 
1833
         VMCIHandleArray_Destroy(context->pendingDoorbellArray);
 
1834
         context->pendingDoorbellArray = dbHandleArray;
 
1835
         dbHandleArray = NULL;
 
1836
      } else {
 
1837
         VMCIContextClearNotifyAndCall(context);
 
1838
      }
 
1839
      VMCI_ReleaseLock(&context->lock, flags);
 
1840
      VMCIContext_Release(context);
 
1841
   } else {
 
1842
         /*
 
1843
          * The OS driver part is holding on to the context for the
 
1844
          * duration of the receive notification ioctl, so it should
 
1845
          * still be here.
 
1846
          */
 
1847
 
 
1848
         ASSERT(FALSE);
 
1849
   }
 
1850
 
 
1851
   if (dbHandleArray) {
 
1852
      VMCIHandleArray_Destroy(dbHandleArray);
 
1853
   }
 
1854
   if (qpHandleArray) {
 
1855
      VMCIHandleArray_Destroy(qpHandleArray);
 
1856
   }
 
1857
}
 
1858
 
 
1859
 
 
1860
/*
 
1861
 *----------------------------------------------------------------------
 
1862
 *
 
1863
 * VMCIContext_DoorbellCreate --
 
1864
 *
 
1865
 *      Registers that a new doorbell handle has been allocated by the
 
1866
 *      context. Only doorbell handles registered can be notified.
 
1867
 *
 
1868
 * Results:
 
1869
 *      VMCI_SUCCESS on success, appropriate error code otherewise.
 
1870
 *
 
1871
 * Side effects:
 
1872
 *      None.
 
1873
 *
 
1874
 *----------------------------------------------------------------------
 
1875
 */
 
1876
 
 
1877
int
 
1878
VMCIContext_DoorbellCreate(VMCIId contextID,   // IN
 
1879
                           VMCIHandle handle)  // IN
 
1880
{
 
1881
   VMCIContext *context;
 
1882
   VMCILockFlags flags;
 
1883
   int result;
 
1884
 
 
1885
   if (contextID == VMCI_INVALID_ID || VMCI_HANDLE_INVALID(handle)) {
 
1886
      return VMCI_ERROR_INVALID_ARGS;
 
1887
   }
 
1888
 
 
1889
   context = VMCIContext_Get(contextID);
 
1890
   if (context == NULL) {
 
1891
      return VMCI_ERROR_NOT_FOUND;
 
1892
   }
 
1893
 
 
1894
   VMCI_GrabLock(&context->lock, &flags);
 
1895
   if (!VMCIHandleArray_HasEntry(context->doorbellArray, handle)) {
 
1896
      VMCIHandleArray_AppendEntry(&context->doorbellArray, handle);
 
1897
      result = VMCI_SUCCESS;
 
1898
   } else {
 
1899
      result = VMCI_ERROR_DUPLICATE_ENTRY;
 
1900
   }
 
1901
   VMCI_ReleaseLock(&context->lock, flags);
 
1902
 
 
1903
   VMCIContext_Release(context);
 
1904
 
 
1905
   return result;
 
1906
}
 
1907
 
 
1908
 
 
1909
/*
 
1910
 *----------------------------------------------------------------------
 
1911
 *
 
1912
 * VMCIContext_DoorbellDestroy --
 
1913
 *
 
1914
 *      Unregisters a doorbell handle that was previously registered
 
1915
 *      with VMCIContext_DoorbellCreate.
 
1916
 *
 
1917
 * Results:
 
1918
 *      VMCI_SUCCESS on success, appropriate error code otherewise.
 
1919
 *
 
1920
 * Side effects:
 
1921
 *      None.
 
1922
 *
 
1923
 *----------------------------------------------------------------------
 
1924
 */
 
1925
 
 
1926
int
 
1927
VMCIContext_DoorbellDestroy(VMCIId contextID,   // IN
 
1928
                            VMCIHandle handle)  // IN
 
1929
{
 
1930
   VMCIContext *context;
 
1931
   VMCILockFlags flags;
 
1932
   VMCIHandle removedHandle;
 
1933
 
 
1934
   if (contextID == VMCI_INVALID_ID || VMCI_HANDLE_INVALID(handle)) {
 
1935
      return VMCI_ERROR_INVALID_ARGS;
 
1936
   }
 
1937
 
 
1938
   context = VMCIContext_Get(contextID);
 
1939
   if (context == NULL) {
 
1940
      return VMCI_ERROR_NOT_FOUND;
 
1941
   }
 
1942
 
 
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);
 
1947
 
 
1948
   VMCIContext_Release(context);
 
1949
 
 
1950
   if (VMCI_HANDLE_INVALID(removedHandle)) {
 
1951
      return VMCI_ERROR_NOT_FOUND;
 
1952
   } else {
 
1953
      return VMCI_SUCCESS;
 
1954
   }
 
1955
}
 
1956
 
 
1957
 
 
1958
/*
 
1959
 *----------------------------------------------------------------------
 
1960
 *
 
1961
 * VMCIContext_DoorbellDestroyAll --
 
1962
 *
 
1963
 *      Unregisters all doorbell handles that were previously
 
1964
 *      registered with VMCIContext_DoorbellCreate.
 
1965
 *
 
1966
 * Results:
 
1967
 *      VMCI_SUCCESS on success, appropriate error code otherewise.
 
1968
 *
 
1969
 * Side effects:
 
1970
 *      None.
 
1971
 *
 
1972
 *----------------------------------------------------------------------
 
1973
 */
 
1974
 
 
1975
int
 
1976
VMCIContext_DoorbellDestroyAll(VMCIId contextID) // IN
 
1977
{
 
1978
   VMCIContext *context;
 
1979
   VMCILockFlags flags;
 
1980
   VMCIHandle removedHandle;
 
1981
 
 
1982
   if (contextID == VMCI_INVALID_ID) {
 
1983
      return VMCI_ERROR_INVALID_ARGS;
 
1984
   }
 
1985
 
 
1986
   context = VMCIContext_Get(contextID);
 
1987
   if (context == NULL) {
 
1988
      return VMCI_ERROR_NOT_FOUND;
 
1989
   }
 
1990
 
 
1991
   VMCI_GrabLock(&context->lock, &flags);
 
1992
   do {
 
1993
      removedHandle = VMCIHandleArray_RemoveTail(context->doorbellArray);
 
1994
   } while(!VMCI_HANDLE_INVALID(removedHandle));
 
1995
   do {
 
1996
      removedHandle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray);
 
1997
   } while(!VMCI_HANDLE_INVALID(removedHandle));
 
1998
   VMCI_ReleaseLock(&context->lock, flags);
 
1999
 
 
2000
   VMCIContext_Release(context);
 
2001
 
 
2002
   return VMCI_SUCCESS;
 
2003
}
 
2004
 
 
2005
 
 
2006
/*
 
2007
 *----------------------------------------------------------------------
 
2008
 *
 
2009
 * VMCIContext_NotifyDoorbell --
 
2010
 *
 
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.
 
2019
 *
 
2020
 * Results:
 
2021
 *      VMCI_SUCCESS on success, appropriate error code otherewise.
 
2022
 *
 
2023
 * Side effects:
 
2024
 *      None.
 
2025
 *
 
2026
 *----------------------------------------------------------------------
 
2027
 */
 
2028
 
 
2029
int
 
2030
VMCIContext_NotifyDoorbell(VMCIId srcCID,                   // IN
 
2031
                           VMCIHandle handle,               // IN
 
2032
                           VMCIPrivilegeFlags srcPrivFlags) // IN
 
2033
{
 
2034
   VMCIContext *dstContext;
 
2035
   VMCILockFlags flags;
 
2036
   int result;
 
2037
 
 
2038
   if (VMCI_HANDLE_INVALID(handle)) {
 
2039
      return VMCI_ERROR_INVALID_ARGS;
 
2040
   }
 
2041
 
 
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;
 
2047
   }
 
2048
 
 
2049
   if (srcCID != handle.context) {
 
2050
      VMCIPrivilegeFlags dstPrivFlags;
 
2051
#if !defined(VMKERNEL)
 
2052
      char *srcDomain = NULL;
 
2053
#else
 
2054
      char srcDomain[VMCI_DOMAIN_NAME_MAXLEN];
 
2055
 
 
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));
 
2060
         goto out;
 
2061
      }
 
2062
#endif
 
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,
 
2067
                       handle.resource));
 
2068
         goto out;
 
2069
      }
 
2070
 
 
2071
      if (srcCID != VMCI_HOST_CONTEXT_ID ||
 
2072
          srcPrivFlags == VMCI_NO_PRIVILEGE_FLAGS) {
 
2073
         srcPrivFlags = VMCIContext_GetPrivFlags(srcCID);
 
2074
      }
 
2075
 
 
2076
      if (VMCIDenyInteraction(srcPrivFlags, dstPrivFlags, srcDomain,
 
2077
                              VMCIContextGetDomainName(dstContext))) {
 
2078
         result = VMCI_ERROR_NO_ACCESS;
 
2079
         goto out;
 
2080
      }
 
2081
   }
 
2082
 
 
2083
   if (handle.context == VMCI_HOST_CONTEXT_ID) {
 
2084
      result = VMCIDoorbellHostContextNotify(srcCID, handle);
 
2085
   } else {
 
2086
      VMCI_GrabLock(&dstContext->lock, &flags);
 
2087
 
 
2088
      if (!VMCIHandleArray_HasEntry(dstContext->doorbellArray, handle)) {
 
2089
         result = VMCI_ERROR_NOT_FOUND;
 
2090
      } else {
 
2091
         if (!VMCIHandleArray_HasEntry(dstContext->pendingDoorbellArray, handle)) {
 
2092
            VMCIHandleArray_AppendEntry(&dstContext->pendingDoorbellArray, handle);
 
2093
 
 
2094
            VMCIContextSignalNotify(dstContext);
 
2095
#if defined(VMKERNEL)
 
2096
            VMCIHost_SignalBitmap(&dstContext->hostContext);
 
2097
#else
 
2098
            VMCIHost_SignalCall(&dstContext->hostContext);
 
2099
#endif
 
2100
         }
 
2101
         result = VMCI_SUCCESS;
 
2102
      }
 
2103
      VMCI_ReleaseLock(&dstContext->lock, flags);
 
2104
   }
 
2105
 
 
2106
out:
 
2107
   VMCIContext_Release(dstContext);
 
2108
 
 
2109
   return result;
 
2110
}
 
2111
 
 
2112
 
 
2113
#ifdef VMKERNEL
 
2114
 
 
2115
/*
 
2116
 *----------------------------------------------------------------------
 
2117
 *
 
2118
 * VMCIContext_SignalPendingDoorbells --
 
2119
 *
 
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
 
2124
 *      quiesced.
 
2125
 *
 
2126
 * Results:
 
2127
 *      None.
 
2128
 *
 
2129
 * Side effects:
 
2130
 *      None.
 
2131
 *
 
2132
 *----------------------------------------------------------------------
 
2133
 */
 
2134
 
 
2135
void
 
2136
VMCIContext_SignalPendingDoorbells(VMCIId contextID)
 
2137
{
 
2138
   VMCIContext *context;
 
2139
   VMCILockFlags flags;
 
2140
   Bool pending;
 
2141
 
 
2142
   context = VMCIContext_Get(contextID);
 
2143
   if (!context) {
 
2144
      ASSERT(FALSE);
 
2145
      return;
 
2146
   }
 
2147
 
 
2148
   VMCI_GrabLock(&context->lock, &flags);
 
2149
   pending = VMCIHandleArray_GetSize(context->pendingDoorbellArray) > 0;
 
2150
   VMCI_ReleaseLock(&context->lock, flags);
 
2151
 
 
2152
   if (pending) {
 
2153
      VMCIHost_SignalBitmap(&context->hostContext);
 
2154
   }
 
2155
 
 
2156
   VMCIContext_Release(context);
 
2157
}
 
2158
 
 
2159
 
 
2160
/*
 
2161
 *----------------------------------------------------------------------
 
2162
 *
 
2163
 * VMCIContext_SetDomainName --
 
2164
 *
 
2165
 *      Sets the domain name of the given context.
 
2166
 *
 
2167
 * Results:
 
2168
 *      VMCI_SUCCESS on success, error code otherwise.
 
2169
 *
 
2170
 * Side effects:
 
2171
 *      None.
 
2172
 *
 
2173
 *----------------------------------------------------------------------
 
2174
 */
 
2175
 
 
2176
int
 
2177
VMCIContext_SetDomainName(VMCIContext *context,   // IN;
 
2178
                          const char *domainName) // IN:
 
2179
{
 
2180
   size_t domainNameLen;
 
2181
 
 
2182
   if (!context || !domainName) {
 
2183
      return VMCI_ERROR_INVALID_ARGS;
 
2184
   }
 
2185
 
 
2186
   domainNameLen = strlen(domainName);
 
2187
   if (domainNameLen >= sizeof context->domainName) {
 
2188
      return VMCI_ERROR_NO_MEM;
 
2189
   }
 
2190
 
 
2191
   memcpy(context->domainName, domainName, domainNameLen + 1);
 
2192
 
 
2193
   return VMCI_SUCCESS;
 
2194
}
 
2195
 
 
2196
 
 
2197
/*
 
2198
 *----------------------------------------------------------------------
 
2199
 *
 
2200
 * VMCIContext_GetDomainName --
 
2201
 *
 
2202
 *      Returns the domain name of the given context.
 
2203
 *
 
2204
 * Results:
 
2205
 *      VMCI_SUCCESS on success, error code otherwise.
 
2206
 *
 
2207
 * Side effects:
 
2208
 *      None.
 
2209
 *
 
2210
 *----------------------------------------------------------------------
 
2211
 */
 
2212
 
 
2213
int
 
2214
VMCIContext_GetDomainName(VMCIId contextID,         // IN:
 
2215
                          char *domainName,         // OUT:
 
2216
                          size_t domainNameBufSize) // IN:
 
2217
{
 
2218
   VMCIContext *context;
 
2219
   int rv = VMCI_SUCCESS;
 
2220
   size_t domainNameLen;
 
2221
 
 
2222
   if (contextID == VMCI_INVALID_ID || !domainName || !domainNameBufSize) {
 
2223
      return VMCI_ERROR_INVALID_ARGS;
 
2224
   }
 
2225
 
 
2226
   context = VMCIContext_Get(contextID);
 
2227
   if (!context) {
 
2228
      return VMCI_ERROR_NOT_FOUND;
 
2229
   }
 
2230
 
 
2231
   domainNameLen = strlen(context->domainName);
 
2232
   if (domainNameLen >= domainNameBufSize) {
 
2233
      rv = VMCI_ERROR_NO_MEM;
 
2234
      goto out;
 
2235
   }
 
2236
 
 
2237
   memcpy(domainName, context->domainName, domainNameLen + 1);
 
2238
 
 
2239
out:
 
2240
   VMCIContext_Release(context);
 
2241
   return rv;
 
2242
}
 
2243
 
 
2244
 
 
2245
#endif // defined(VMKERNEL)
 
2246
 
 
2247
 
 
2248
/*
 
2249
 *----------------------------------------------------------------------
 
2250
 *
 
2251
 * VMCI_ContextID2HostVmID --
 
2252
 *
 
2253
 *      Maps a context ID to the host specific (process/world) ID
 
2254
 *      of the VM/VMX.
 
2255
 *
 
2256
 * Results:
 
2257
 *      VMCI_SUCCESS on success, error code otherwise.
 
2258
 *
 
2259
 * Side effects:
 
2260
 *      None.
 
2261
 *
 
2262
 *----------------------------------------------------------------------
 
2263
 */
 
2264
 
 
2265
VMCI_EXPORT_SYMBOL(VMCI_ContextID2HostVmID)
 
2266
int
 
2267
VMCI_ContextID2HostVmID(VMCIId contextID,    // IN
 
2268
                        void *hostVmID,      // OUT
 
2269
                        size_t hostVmIDLen)  // IN
 
2270
{
 
2271
#if defined(VMKERNEL)
 
2272
   VMCIContext *context;
 
2273
   VMCIHostVmID vmID;
 
2274
   int result;
 
2275
 
 
2276
   context = VMCIContext_Get(contextID);
 
2277
   if (!context) {
 
2278
      return VMCI_ERROR_NOT_FOUND;
 
2279
   }
 
2280
 
 
2281
   result = VMCIHost_ContextToHostVmID(&context->hostContext, &vmID);
 
2282
   if (result == VMCI_SUCCESS) {
 
2283
      if (sizeof vmID == hostVmIDLen) {
 
2284
         memcpy(hostVmID, &vmID, hostVmIDLen);
 
2285
      } else {
 
2286
         result = VMCI_ERROR_INVALID_ARGS;
 
2287
      }
 
2288
   }
 
2289
 
 
2290
   VMCIContext_Release(context);
 
2291
 
 
2292
   return result;
 
2293
#else // !defined(VMKERNEL)
 
2294
   return VMCI_ERROR_UNAVAILABLE;
 
2295
#endif
 
2296
}
 
2297
 
 
2298
 
 
2299
/*
 
2300
 *----------------------------------------------------------------------
 
2301
 *
 
2302
 * VMCI_IsContextOwner --
 
2303
 *
 
2304
 *      Determines whether a given host OS specific representation of
 
2305
 *      user is the owner of the VM/VMX.
 
2306
 *
 
2307
 * Results:
 
2308
 *      VMCI_SUCCESS if the hostUser is owner, error code otherwise.
 
2309
 *
 
2310
 * Side effects:
 
2311
 *      None.
 
2312
 *
 
2313
 *----------------------------------------------------------------------
 
2314
 */
 
2315
 
 
2316
VMCI_EXPORT_SYMBOL(VMCI_IsContextOwner)
 
2317
int
 
2318
VMCI_IsContextOwner(VMCIId contextID,   // IN
 
2319
                    void *hostUser)     // IN
 
2320
{
 
2321
   if (VMCI_HostPersonalityActive()) {
 
2322
      VMCIContext *context;
 
2323
      VMCIHostUser *user = (VMCIHostUser *)hostUser;
 
2324
      int retval;
 
2325
 
 
2326
      if (vmkernel) {
 
2327
         return VMCI_ERROR_UNAVAILABLE;
 
2328
      }
 
2329
 
 
2330
      if (!hostUser) {
 
2331
         return VMCI_ERROR_INVALID_ARGS;
 
2332
      }
 
2333
 
 
2334
      context = VMCIContext_Get(contextID);
 
2335
      if (!context) {
 
2336
         return VMCI_ERROR_NOT_FOUND;
 
2337
      }
 
2338
 
 
2339
      if (context->validUser) {
 
2340
         retval = VMCIHost_CompareUser(user, &context->user);
 
2341
      } else {
 
2342
         retval = VMCI_ERROR_UNAVAILABLE;
 
2343
      }
 
2344
      VMCIContext_Release(context);
 
2345
 
 
2346
      return retval;
 
2347
   }
 
2348
   return VMCI_ERROR_UNAVAILABLE;
 
2349
}
 
2350
 
 
2351
 
 
2352
/*
 
2353
 *----------------------------------------------------------------------
 
2354
 *
 
2355
 * VMCIContext_SupportsHostQP --
 
2356
 *
 
2357
 *      Can host QPs be connected to this user process.  The answer is
 
2358
 *      FALSE unless a sufficient version number has previously been set
 
2359
 *      by this caller.
 
2360
 *
 
2361
 * Results:
 
2362
 *      VMCI_SUCCESS on success, error code otherwise.
 
2363
 *
 
2364
 * Side effects:
 
2365
 *      None.
 
2366
 *
 
2367
 *----------------------------------------------------------------------
 
2368
 */
 
2369
 
 
2370
Bool
 
2371
VMCIContext_SupportsHostQP(VMCIContext *context)    // IN: Context structure
 
2372
{
 
2373
#ifdef VMKERNEL
 
2374
   return TRUE;
 
2375
#else
 
2376
   if (!context || context->userVersion < VMCI_VERSION_HOSTQP) {
 
2377
      return FALSE;
 
2378
   }
 
2379
   return TRUE;
 
2380
#endif
 
2381
}