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

« back to all changes in this revision

Viewing changes to modules/linux/vmci/common/vmciDoorbell.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) 2010 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
 * vmciDoorbell.c --
 
21
 *
 
22
 *    This file implements the VMCI doorbell API on the host.
 
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 "vmciDatagram.h"
 
31
#include "vmciDoorbell.h"
 
32
#include "vmciDriver.h"
 
33
#include "vmciKernelAPI.h"
 
34
#include "vmciResource.h"
 
35
#include "vmciRoute.h"
 
36
#if defined(VMKERNEL)
 
37
#  include "vmciVmkInt.h"
 
38
#  include "vm_libc.h"
 
39
#  include "helper_ext.h"
 
40
#endif
 
41
 
 
42
#define LGPFX "VMCIDoorbell: "
 
43
 
 
44
#if !defined(SOLARIS) && !defined(__APPLE__)
 
45
 
 
46
#if defined(VMKERNEL)
 
47
   /* VMK doesn't need BH locks, so use lower ranks. */
 
48
#  define VMCIDoorbellInitLock(_l, _n) \
 
49
   VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_HIGHER)
 
50
#  define VMCIDoorbellGrabLock(_l, _f)       VMCI_GrabLock(_l, _f)
 
51
#  define VMCIDoorbellReleaseLock(_l, _f)    VMCI_ReleaseLock(_l, _f)
 
52
#else // VMKERNEL
 
53
#  define VMCIDoorbellInitLock(_l, _n) \
 
54
   VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_MIDDLE_BH)
 
55
#  define VMCIDoorbellGrabLock(_l, _f)       VMCI_GrabLock_BH(_l, _f)
 
56
#  define VMCIDoorbellReleaseLock(_l, _f)    VMCI_ReleaseLock_BH(_l, _f)
 
57
#endif // VMKERNEL
 
58
 
 
59
#define VMCI_DOORBELL_INDEX_TABLE_SIZE 64
 
60
#define VMCI_DOORBELL_HASH(_idx) \
 
61
   VMCI_HashId((_idx), VMCI_DOORBELL_INDEX_TABLE_SIZE)
 
62
 
 
63
 
 
64
/*
 
65
 * DoorbellEntry describes the a doorbell notification handle allocated by the
 
66
 * host.
 
67
 */
 
68
 
 
69
typedef struct VMCIDoorbellEntry {
 
70
   VMCIResource        resource;
 
71
   uint32              idx;
 
72
   VMCIListItem        idxListItem;
 
73
   VMCIPrivilegeFlags  privFlags;
 
74
   Bool                isDoorbell;
 
75
   Bool                runDelayed;
 
76
   VMCICallback        notifyCB;
 
77
   void                *clientData;
 
78
   VMCIEvent           destroyEvent;
 
79
} VMCIDoorbellEntry;
 
80
 
 
81
typedef struct VMCIDoorbellIndexTable {
 
82
   VMCILock lock;
 
83
   VMCIList entries[VMCI_DOORBELL_INDEX_TABLE_SIZE];
 
84
} VMCIDoorbellIndexTable;
 
85
 
 
86
 
 
87
/* The VMCI index table keeps track of currently registered doorbells. */
 
88
static VMCIDoorbellIndexTable vmciDoorbellIT;
 
89
 
 
90
 
 
91
/*
 
92
 * The maxNotifyIdx is one larger than the currently known bitmap index in
 
93
 * use, and is used to determine how much of the bitmap needs to be scanned.
 
94
 */
 
95
 
 
96
static uint32 maxNotifyIdx;
 
97
 
 
98
/*
 
99
 * The notifyIdxCount is used for determining whether there are free entries
 
100
 * within the bitmap (if notifyIdxCount + 1 < maxNotifyIdx).
 
101
 */
 
102
 
 
103
static uint32 notifyIdxCount;
 
104
 
 
105
/*
 
106
 * The lastNotifyIdxReserved is used to track the last index handed out - in
 
107
 * the case where multiple handles share a notification index, we hand out
 
108
 * indexes round robin based on lastNotifyIdxReserved.
 
109
 */
 
110
 
 
111
static uint32 lastNotifyIdxReserved;
 
112
 
 
113
/* This is a one entry cache used to by the index allocation. */
 
114
static uint32 lastNotifyIdxReleased = PAGE_SIZE;
 
115
 
 
116
 
 
117
static void VMCIDoorbellFreeCB(void *clientData);
 
118
static int VMCIDoorbellReleaseCB(void *clientData);
 
119
static void VMCIDoorbellDelayedDispatchCB(void *data);
 
120
 
 
121
 
 
122
/*
 
123
 *------------------------------------------------------------------------------
 
124
 *
 
125
 * VMCIDoorbell_Init --
 
126
 *
 
127
 *    General init code.
 
128
 *
 
129
 * Result:
 
130
 *    None.
 
131
 *
 
132
 * Side effects:
 
133
 *    None.
 
134
 *
 
135
 *------------------------------------------------------------------------------
 
136
 */
 
137
 
 
138
void
 
139
VMCIDoorbell_Init(void)
 
140
{
 
141
   uint32 bucket;
 
142
 
 
143
   for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); ++bucket) {
 
144
      VMCIList_Init(&vmciDoorbellIT.entries[bucket]);
 
145
   }
 
146
 
 
147
   VMCIDoorbellInitLock(&vmciDoorbellIT.lock, "VMCIDoorbellIndexTableLock");
 
148
}
 
149
 
 
150
 
 
151
/*
 
152
 *------------------------------------------------------------------------------
 
153
 *
 
154
 * VMCIDoorbell_Exit --
 
155
 *
 
156
 *    General init code.
 
157
 *
 
158
 * Result:
 
159
 *    None.
 
160
 *
 
161
 * Side effects:
 
162
 *    None.
 
163
 *
 
164
 *------------------------------------------------------------------------------
 
165
 */
 
166
 
 
167
void
 
168
VMCIDoorbell_Exit(void)
 
169
{
 
170
   VMCI_CleanupLock(&vmciDoorbellIT.lock);
 
171
}
 
172
 
 
173
 
 
174
/*
 
175
 *------------------------------------------------------------------------------
 
176
 *
 
177
 * VMCIDoorbellFreeCB --
 
178
 *
 
179
 *    Callback to free doorbell entry structure when resource is no longer used,
 
180
 *    ie. the reference count reached 0.  The entry is freed in
 
181
 *    VMCIDoorbell_Destroy(), which is waiting on the signal that gets fired
 
182
 *    here.
 
183
 *
 
184
 * Result:
 
185
 *    None.
 
186
 *
 
187
 * Side effects:
 
188
 *    Signals VMCI event.
 
189
 *
 
190
 *------------------------------------------------------------------------------
 
191
 */
 
192
 
 
193
static void
 
194
VMCIDoorbellFreeCB(void *clientData)  // IN
 
195
{
 
196
   VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData;
 
197
   ASSERT(entry);
 
198
   VMCI_SignalEvent(&entry->destroyEvent);
 
199
}
 
200
 
 
201
 
 
202
/*
 
203
 *------------------------------------------------------------------------------
 
204
 *
 
205
 * VMCIDoorbellReleaseCB --
 
206
 *
 
207
 *     Callback to release the resource reference. It is called by the
 
208
 *     VMCI_WaitOnEvent function before it blocks.
 
209
 *
 
210
 * Result:
 
211
 *     Always 0.
 
212
 *
 
213
 * Side effects:
 
214
 *     None.
 
215
 *
 
216
 *------------------------------------------------------------------------------
 
217
 */
 
218
 
 
219
static int
 
220
VMCIDoorbellReleaseCB(void *clientData) // IN: doorbell entry
 
221
{
 
222
   VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData;
 
223
   ASSERT(entry);
 
224
   VMCIResource_Release(&entry->resource);
 
225
   return 0;
 
226
}
 
227
 
 
228
 
 
229
/*
 
230
 *------------------------------------------------------------------------------
 
231
 *
 
232
 * VMCIDoorbellGetPrivFlags --
 
233
 *
 
234
 *    Utility function that retrieves the privilege flags associated
 
235
 *    with a given doorbell handle. For guest endpoints, the
 
236
 *    privileges are determined by the context ID, but for host
 
237
 *    endpoints privileges are associated with the complete
 
238
 *    handle. Hypervisor endpoints are not yet supported.
 
239
 *
 
240
 * Result:
 
241
 *    VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
 
242
 *
 
243
 * Side effects:
 
244
 *    None.
 
245
 *
 
246
 *------------------------------------------------------------------------------
 
247
 */
 
248
 
 
249
int
 
250
VMCIDoorbellGetPrivFlags(VMCIHandle handle,             // IN
 
251
                         VMCIPrivilegeFlags *privFlags) // OUT
 
252
{
 
253
   if (privFlags == NULL || handle.context == VMCI_INVALID_ID) {
 
254
      return VMCI_ERROR_INVALID_ARGS;
 
255
   }
 
256
 
 
257
   if (handle.context == VMCI_HOST_CONTEXT_ID) {
 
258
      VMCIDoorbellEntry *entry;
 
259
      VMCIResource *resource;
 
260
 
 
261
      resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
 
262
      if (resource == NULL) {
 
263
         return VMCI_ERROR_INVALID_ARGS;
 
264
      }
 
265
      entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
 
266
      *privFlags = entry->privFlags;
 
267
      VMCIResource_Release(resource);
 
268
   } else if (handle.context == VMCI_HYPERVISOR_CONTEXT_ID) {
 
269
       /* Hypervisor endpoints for notifications are not supported (yet). */
 
270
      return VMCI_ERROR_INVALID_ARGS;
 
271
   } else {
 
272
      *privFlags = VMCIContext_GetPrivFlags(handle.context);
 
273
   }
 
274
 
 
275
   return VMCI_SUCCESS;
 
276
}
 
277
 
 
278
 
 
279
/*
 
280
 *-----------------------------------------------------------------------------
 
281
 *
 
282
 * VMCIDoorbellIndexTableFind --
 
283
 *
 
284
 *    Find doorbell entry by bitmap index.
 
285
 *
 
286
 * Results:
 
287
 *    Entry if found, NULL if not.
 
288
 *
 
289
 * Side effects:
 
290
 *    None.
 
291
 *
 
292
 *-----------------------------------------------------------------------------
 
293
 */
 
294
 
 
295
static VMCIDoorbellEntry *
 
296
VMCIDoorbellIndexTableFind(uint32 idx) // IN
 
297
{
 
298
   uint32 bucket = VMCI_DOORBELL_HASH(idx);
 
299
   VMCIListItem *iter;
 
300
 
 
301
   ASSERT(VMCI_GuestPersonalityActive());
 
302
 
 
303
   VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
 
304
      VMCIDoorbellEntry *cur =
 
305
         VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
 
306
 
 
307
      ASSERT(cur);
 
308
 
 
309
      if (idx == cur->idx) {
 
310
         return cur;
 
311
      }
 
312
   }
 
313
 
 
314
   return NULL;
 
315
}
 
316
 
 
317
 
 
318
/*
 
319
 *------------------------------------------------------------------------------
 
320
 *
 
321
 * VMCIDoorbellIndexTableAdd --
 
322
 *
 
323
 *    Add the given entry to the index table.  This will hold() the entry's
 
324
 *    resource so that the entry is not deleted before it is removed from the
 
325
 *    table.
 
326
 *
 
327
 * Results:
 
328
 *    None.
 
329
 *
 
330
 * Side effects:
 
331
 *    None.
 
332
 *
 
333
 *------------------------------------------------------------------------------
 
334
 */
 
335
 
 
336
static void
 
337
VMCIDoorbellIndexTableAdd(VMCIDoorbellEntry *entry) // IN/OUT
 
338
{
 
339
   uint32 bucket;
 
340
   uint32 newNotifyIdx;
 
341
   VMCILockFlags flags;
 
342
 
 
343
   ASSERT(entry);
 
344
   ASSERT(VMCI_GuestPersonalityActive());
 
345
 
 
346
   VMCIResource_Hold(&entry->resource);
 
347
 
 
348
   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
 
349
 
 
350
   /*
 
351
    * Below we try to allocate an index in the notification bitmap with "not
 
352
    * too much" sharing between resources. If we use less that the full bitmap,
 
353
    * we either add to the end if there are no unused flags within the
 
354
    * currently used area, or we search for unused ones. If we use the full
 
355
    * bitmap, we allocate the index round robin.
 
356
    */
 
357
 
 
358
   if (maxNotifyIdx < PAGE_SIZE || notifyIdxCount < PAGE_SIZE) {
 
359
      if (lastNotifyIdxReleased < maxNotifyIdx &&
 
360
          !VMCIDoorbellIndexTableFind(lastNotifyIdxReleased)) {
 
361
         newNotifyIdx = lastNotifyIdxReleased;
 
362
         lastNotifyIdxReleased = PAGE_SIZE;
 
363
      } else {
 
364
         Bool reused = FALSE;
 
365
         newNotifyIdx = lastNotifyIdxReserved;
 
366
         if (notifyIdxCount + 1 < maxNotifyIdx) {
 
367
            do {
 
368
               if (!VMCIDoorbellIndexTableFind(newNotifyIdx)) {
 
369
                  reused = TRUE;
 
370
                  break;
 
371
               }
 
372
               newNotifyIdx = (newNotifyIdx + 1) % maxNotifyIdx;
 
373
            } while(newNotifyIdx != lastNotifyIdxReleased);
 
374
         }
 
375
         if (!reused) {
 
376
            newNotifyIdx = maxNotifyIdx;
 
377
            maxNotifyIdx++;
 
378
         }
 
379
      }
 
380
   } else {
 
381
      newNotifyIdx = (lastNotifyIdxReserved + 1) % PAGE_SIZE;
 
382
   }
 
383
   lastNotifyIdxReserved = newNotifyIdx;
 
384
   notifyIdxCount++;
 
385
 
 
386
   entry->idx = newNotifyIdx;
 
387
   bucket = VMCI_DOORBELL_HASH(entry->idx);
 
388
   VMCIList_Insert(&entry->idxListItem, &vmciDoorbellIT.entries[bucket]);
 
389
 
 
390
   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
 
391
}
 
392
 
 
393
 
 
394
/*
 
395
 *------------------------------------------------------------------------------
 
396
 *
 
397
 * VMCIDoorbellIndexTableRemove --
 
398
 *
 
399
 *    Remove the given entry from the index table.  This will release() the
 
400
 *    entry's resource.
 
401
 *
 
402
 * Results:
 
403
 *    None.
 
404
 *
 
405
 * Side effects:
 
406
 *    None.
 
407
 *
 
408
 *------------------------------------------------------------------------------
 
409
 */
 
410
 
 
411
static void
 
412
VMCIDoorbellIndexTableRemove(VMCIDoorbellEntry *entry) // IN/OUT
 
413
{
 
414
   uint32 bucket;
 
415
   VMCILockFlags flags;
 
416
 
 
417
   ASSERT(entry);
 
418
   ASSERT(VMCI_GuestPersonalityActive());
 
419
 
 
420
   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
 
421
 
 
422
   bucket = VMCI_DOORBELL_HASH(entry->idx);
 
423
   VMCIList_Remove(&entry->idxListItem, &vmciDoorbellIT.entries[bucket]);
 
424
 
 
425
   notifyIdxCount--;
 
426
   if (entry->idx == maxNotifyIdx - 1) {
 
427
      /*
 
428
       * If we delete an entry with the maximum known notification index, we
 
429
       * take the opportunity to prune the current max. As there might be other
 
430
       * unused indices immediately below, we lower the maximum until we hit an
 
431
       * index in use.
 
432
       */
 
433
 
 
434
      while (maxNotifyIdx > 0 &&
 
435
             !VMCIDoorbellIndexTableFind(maxNotifyIdx - 1)) {
 
436
         maxNotifyIdx--;
 
437
      }
 
438
   }
 
439
   lastNotifyIdxReleased = entry->idx;
 
440
 
 
441
   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
 
442
 
 
443
   VMCIResource_Release(&entry->resource);
 
444
}
 
445
 
 
446
 
 
447
/*
 
448
 *------------------------------------------------------------------------------
 
449
 *
 
450
 * VMCIDoorbellLink --
 
451
 *
 
452
 *    Creates a link between the given doorbell handle and the given
 
453
 *    index in the bitmap in the device backend.
 
454
 *
 
455
 * Results:
 
456
 *    VMCI_SUCCESS if success, appropriate error code otherwise.
 
457
 *
 
458
 * Side effects:
 
459
 *    Notification state is created in hypervisor.
 
460
 *
 
461
 *------------------------------------------------------------------------------
 
462
 */
 
463
 
 
464
static int
 
465
VMCIDoorbellLink(VMCIHandle handle, // IN
 
466
                 Bool isDoorbell,   // IN
 
467
                 uint32 notifyIdx)  // IN
 
468
{
 
469
#if defined(VMKERNEL)
 
470
   VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
 
471
   return VMCI_ERROR_DST_UNREACHABLE;
 
472
#else // VMKERNEL
 
473
   VMCIId resourceID;
 
474
   VMCIDoorbellLinkMsg linkMsg;
 
475
 
 
476
   ASSERT(!VMCI_HANDLE_INVALID(handle));
 
477
   ASSERT(VMCI_GuestPersonalityActive());
 
478
 
 
479
   if (isDoorbell) {
 
480
      resourceID = VMCI_DOORBELL_LINK;
 
481
   } else {
 
482
      ASSERT(FALSE);
 
483
      return VMCI_ERROR_UNAVAILABLE;
 
484
   }
 
485
 
 
486
   linkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID);
 
487
   linkMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
 
488
   linkMsg.hdr.payloadSize = sizeof linkMsg - VMCI_DG_HEADERSIZE;
 
489
   linkMsg.handle = handle;
 
490
   linkMsg.notifyIdx = notifyIdx;
 
491
 
 
492
   return VMCI_SendDatagram((VMCIDatagram *)&linkMsg);
 
493
#endif // VMKERNEL
 
494
}
 
495
 
 
496
 
 
497
/*
 
498
 *------------------------------------------------------------------------------
 
499
 *
 
500
 * VMCIDoorbellUnlink --
 
501
 *
 
502
 *    Unlinks the given doorbell handle from an index in the bitmap in
 
503
 *    the device backend.
 
504
 *
 
505
 * Results:
 
506
 *      VMCI_SUCCESS if success, appropriate error code otherwise.
 
507
 *
 
508
 * Side effects:
 
509
 *      Notification state is destroyed in hypervisor.
 
510
 *
 
511
 *------------------------------------------------------------------------------
 
512
 */
 
513
 
 
514
static int
 
515
VMCIDoorbellUnlink(VMCIHandle handle, // IN
 
516
                   Bool isDoorbell)   // IN
 
517
{
 
518
#if defined(VMKERNEL)
 
519
   VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
 
520
   return VMCI_ERROR_DST_UNREACHABLE;
 
521
#else // VMKERNEL
 
522
   VMCIId resourceID;
 
523
   VMCIDoorbellUnlinkMsg unlinkMsg;
 
524
 
 
525
   ASSERT(!VMCI_HANDLE_INVALID(handle));
 
526
   ASSERT(VMCI_GuestPersonalityActive());
 
527
 
 
528
   if (isDoorbell) {
 
529
      resourceID = VMCI_DOORBELL_UNLINK;
 
530
   } else {
 
531
      ASSERT(FALSE);
 
532
      return VMCI_ERROR_UNAVAILABLE;
 
533
   }
 
534
 
 
535
   unlinkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID);
 
536
   unlinkMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
 
537
   unlinkMsg.hdr.payloadSize = sizeof unlinkMsg - VMCI_DG_HEADERSIZE;
 
538
   unlinkMsg.handle = handle;
 
539
 
 
540
   return VMCI_SendDatagram((VMCIDatagram *)&unlinkMsg);
 
541
#endif // VMKERNEL
 
542
}
 
543
 
 
544
 
 
545
/*
 
546
 *------------------------------------------------------------------------------
 
547
 *
 
548
 * VMCIDoorbell_Create --
 
549
 *
 
550
 *    Creates a doorbell with the given callback. If the handle is
 
551
 *    VMCI_INVALID_HANDLE, a free handle will be assigned, if
 
552
 *    possible. The callback can be run immediately (potentially with
 
553
 *    locks held - the default) or delayed (in a kernel thread) by
 
554
 *    specifying the flag VMCI_FLAG_DELAYED_CB. If delayed execution
 
555
 *    is selected, a given callback may not be run if the kernel is
 
556
 *    unable to allocate memory for the delayed execution (highly
 
557
 *    unlikely).
 
558
 *
 
559
 * Results:
 
560
 *    VMCI_SUCCESS on success, appropriate error code otherwise.
 
561
 *
 
562
 * Side effects:
 
563
 *    None.
 
564
 *
 
565
 *------------------------------------------------------------------------------
 
566
 */
 
567
 
 
568
VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create)
 
569
int
 
570
VMCIDoorbell_Create(VMCIHandle *handle,            // IN/OUT
 
571
                    uint32 flags,                  // IN
 
572
                    VMCIPrivilegeFlags privFlags,  // IN
 
573
                    VMCICallback notifyCB,         // IN
 
574
                    void *clientData)              // IN
 
575
{
 
576
   VMCIDoorbellEntry *entry;
 
577
   VMCIHandle newHandle;
 
578
   int result;
 
579
 
 
580
   if (!handle || !notifyCB || flags & ~VMCI_FLAG_DELAYED_CB ||
 
581
       privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
 
582
      return VMCI_ERROR_INVALID_ARGS;
 
583
   }
 
584
 
 
585
   entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED);
 
586
   if (entry == NULL) {
 
587
      VMCI_WARNING((LGPFX"Failed allocating memory for datagram entry.\n"));
 
588
      return VMCI_ERROR_NO_MEM;
 
589
   }
 
590
 
 
591
   if (!VMCI_CanScheduleDelayedWork() && (flags & VMCI_FLAG_DELAYED_CB)) {
 
592
      result = VMCI_ERROR_INVALID_ARGS;
 
593
      goto freeMem;
 
594
   }
 
595
 
 
596
   if (VMCI_HANDLE_INVALID(*handle)) {
 
597
      VMCIId contextID = VMCI_GetContextID();
 
598
      VMCIId resourceID = VMCIResource_GetID(contextID);
 
599
      if (resourceID == VMCI_INVALID_ID) {
 
600
         result = VMCI_ERROR_NO_HANDLE;
 
601
         goto freeMem;
 
602
      }
 
603
      newHandle = VMCI_MAKE_HANDLE(contextID, resourceID);
 
604
   } else {
 
605
      Bool validContext;
 
606
 
 
607
      /*
 
608
       * Validate the handle.  We must do both of the checks below
 
609
       * because we can be acting as both a host and a guest at the
 
610
       * same time. We always allow the host context ID, since the
 
611
       * host functionality is in practice always there with the
 
612
       * unified driver.
 
613
       */
 
614
 
 
615
      validContext = FALSE;
 
616
      if (VMCI_HOST_CONTEXT_ID == handle->context) {
 
617
         validContext = TRUE;
 
618
      }
 
619
      if (VMCI_GuestPersonalityActive() && VMCI_GetContextID() == handle->context) {
 
620
         validContext = TRUE;
 
621
      }
 
622
 
 
623
      if (!validContext || VMCI_INVALID_ID == handle->resource) {
 
624
         VMCI_DEBUG_LOG(4, (LGPFX"Invalid argument (handle=0x%x:0x%x).\n",
 
625
                            handle->context, handle->resource));
 
626
         result = VMCI_ERROR_INVALID_ARGS;
 
627
         goto freeMem;
 
628
      }
 
629
 
 
630
      newHandle = *handle;
 
631
   }
 
632
 
 
633
   entry->idx = 0;
 
634
   VMCIList_Init(&entry->idxListItem);
 
635
   entry->privFlags = privFlags;
 
636
   entry->isDoorbell = TRUE;
 
637
   entry->runDelayed = (flags & VMCI_FLAG_DELAYED_CB) ? TRUE : FALSE;
 
638
   entry->notifyCB = notifyCB;
 
639
   entry->clientData = clientData;
 
640
   VMCI_CreateEvent(&entry->destroyEvent);
 
641
 
 
642
   result = VMCIResource_Add(&entry->resource, VMCI_RESOURCE_TYPE_DOORBELL,
 
643
                             newHandle, VMCIDoorbellFreeCB, entry);
 
644
   if (result != VMCI_SUCCESS) {
 
645
      VMCI_WARNING((LGPFX"Failed to add new resource (handle=0x%x:0x%x).\n",
 
646
                    newHandle.context, newHandle.resource));
 
647
      goto destroy;
 
648
   }
 
649
 
 
650
   if (VMCI_GuestPersonalityActive()) {
 
651
      result = VMCIDoorbellLink(newHandle, entry->isDoorbell, entry->idx);
 
652
      if (VMCI_SUCCESS != result) {
 
653
         goto destroyResource;
 
654
      }
 
655
      VMCIDoorbellIndexTableAdd(entry);
 
656
   }
 
657
 
 
658
   if (VMCI_HANDLE_INVALID(*handle)) {
 
659
      *handle = newHandle;
 
660
   }
 
661
 
 
662
   return result;
 
663
 
 
664
destroyResource:
 
665
   VMCIResource_Remove(newHandle, VMCI_RESOURCE_TYPE_DOORBELL);
 
666
destroy:
 
667
   VMCI_DestroyEvent(&entry->destroyEvent);
 
668
freeMem:
 
669
   VMCI_FreeKernelMem(entry, sizeof *entry);
 
670
   return result;
 
671
}
 
672
 
 
673
 
 
674
/*
 
675
 *------------------------------------------------------------------------------
 
676
 *
 
677
 * VMCIDoorbell_Destroy --
 
678
 *
 
679
 *    Destroys a doorbell previously created with
 
680
 *    VMCIDoorbell_Create. This operation may block waiting for a
 
681
 *    callback to finish.
 
682
 *
 
683
 * Results:
 
684
 *    VMCI_SUCCESS on success, appropriate error code otherwise.
 
685
 *
 
686
 * Side effects:
 
687
 *    May block.
 
688
 *
 
689
 *------------------------------------------------------------------------------
 
690
 */
 
691
 
 
692
VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy)
 
693
int
 
694
VMCIDoorbell_Destroy(VMCIHandle handle)  // IN
 
695
{
 
696
   VMCIDoorbellEntry *entry;
 
697
   VMCIResource *resource;
 
698
 
 
699
   if (VMCI_HANDLE_INVALID(handle)) {
 
700
      return VMCI_ERROR_INVALID_ARGS;
 
701
   }
 
702
 
 
703
   resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
 
704
   if (resource == NULL) {
 
705
      VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy doorbell (handle=0x%x:0x%x).\n",
 
706
                         handle.context, handle.resource));
 
707
      return VMCI_ERROR_NOT_FOUND;
 
708
   }
 
709
   entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
 
710
 
 
711
   if (VMCI_GuestPersonalityActive()) {
 
712
      int result;
 
713
 
 
714
      VMCIDoorbellIndexTableRemove(entry);
 
715
 
 
716
      result = VMCIDoorbellUnlink(handle, entry->isDoorbell);
 
717
      if (VMCI_SUCCESS != result) {
 
718
 
 
719
         /*
 
720
          * The only reason this should fail would be an inconsistency between
 
721
          * guest and hypervisor state, where the guest believes it has an
 
722
          * active registration whereas the hypervisor doesn't. One case where
 
723
          * this may happen is if a doorbell is unregistered following a
 
724
          * hibernation at a time where the doorbell state hasn't been restored
 
725
          * on the hypervisor side yet. Since the handle has now been removed
 
726
          * in the guest, we just print a warning and return success.
 
727
          */
 
728
 
 
729
         VMCI_DEBUG_LOG(4, (LGPFX"Unlink of %s (handle=0x%x:0x%x) unknown by "
 
730
                            "hypervisor (error=%d).\n",
 
731
                            entry->isDoorbell ? "doorbell" : "queuepair",
 
732
                            handle.context, handle.resource, result));
 
733
      }
 
734
   }
 
735
 
 
736
   /*
 
737
    * Now remove the resource from the table.  It might still be in use
 
738
    * after this, in a callback or still on the delayed work queue.
 
739
    */
 
740
 
 
741
   VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DOORBELL);
 
742
 
 
743
   /*
 
744
    * We now wait on the destroyEvent and release the reference we got
 
745
    * above.
 
746
    */
 
747
 
 
748
   VMCI_WaitOnEvent(&entry->destroyEvent, VMCIDoorbellReleaseCB, entry);
 
749
 
 
750
   /*
 
751
    * We know that we are now the only reference to the above entry so
 
752
    * can safely free it.
 
753
    */
 
754
 
 
755
   VMCI_DestroyEvent(&entry->destroyEvent);
 
756
   VMCI_FreeKernelMem(entry, sizeof *entry);
 
757
 
 
758
   return VMCI_SUCCESS;
 
759
}
 
760
 
 
761
 
 
762
/*
 
763
 *------------------------------------------------------------------------------
 
764
 *
 
765
 * VMCIDoorbellNotifyAsGuest --
 
766
 *
 
767
 *    Notify another guest or the host.  We send a datagram down to the
 
768
 *    host via the hypervisor with the notification info.
 
769
 *
 
770
 * Results:
 
771
 *    VMCI_SUCCESS on success, appropriate error code otherwise.
 
772
 *
 
773
 * Side effects:
 
774
 *    May do a hypercall.
 
775
 *
 
776
 *------------------------------------------------------------------------------
 
777
 */
 
778
 
 
779
static int
 
780
VMCIDoorbellNotifyAsGuest(VMCIHandle handle,            // IN
 
781
                          VMCIPrivilegeFlags privFlags) // IN
 
782
{
 
783
#if defined(VMKERNEL)
 
784
   VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
 
785
   return VMCI_ERROR_DST_UNREACHABLE;
 
786
#else // VMKERNEL
 
787
   VMCIDoorbellNotifyMsg notifyMsg;
 
788
 
 
789
   ASSERT(VMCI_GuestPersonalityActive());
 
790
 
 
791
   notifyMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
 
792
                                        VMCI_DOORBELL_NOTIFY);
 
793
   notifyMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
 
794
   notifyMsg.hdr.payloadSize = sizeof notifyMsg - VMCI_DG_HEADERSIZE;
 
795
   notifyMsg.handle = handle;
 
796
 
 
797
   return VMCI_SendDatagram((VMCIDatagram *)&notifyMsg);
 
798
#endif // VMKERNEL
 
799
}
 
800
 
 
801
 
 
802
/*
 
803
 *------------------------------------------------------------------------------
 
804
 *
 
805
 * VMCIDoorbell_Notify --
 
806
 *
 
807
 *    Generates a notification on the doorbell identified by the
 
808
 *    handle. For host side generation of notifications, the caller
 
809
 *    can specify what the privilege of the calling side is.
 
810
 *
 
811
 * Results:
 
812
 *    VMCI_SUCCESS on success, appropriate error code otherwise.
 
813
 *
 
814
 * Side effects:
 
815
 *    May do a hypercall.
 
816
 *
 
817
 *------------------------------------------------------------------------------
 
818
 */
 
819
 
 
820
VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify)
 
821
int
 
822
VMCIDoorbell_Notify(VMCIHandle dst,               // IN
 
823
                    VMCIPrivilegeFlags privFlags) // IN
 
824
{
 
825
   int retval;
 
826
   VMCIRoute route;
 
827
   VMCIHandle src;
 
828
 
 
829
   if (VMCI_HANDLE_INVALID(dst) || (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS)) {
 
830
      return VMCI_ERROR_INVALID_ARGS;
 
831
   }
 
832
 
 
833
   src = VMCI_INVALID_HANDLE;
 
834
   retval = VMCI_Route(&src, &dst, FALSE, &route);
 
835
   if (retval < VMCI_SUCCESS) {
 
836
      return retval;
 
837
   }
 
838
 
 
839
   if (VMCI_ROUTE_AS_HOST == route) {
 
840
      return VMCIContext_NotifyDoorbell(VMCI_HOST_CONTEXT_ID, dst, privFlags);
 
841
   }
 
842
 
 
843
   if (VMCI_ROUTE_AS_GUEST == route) {
 
844
      return VMCIDoorbellNotifyAsGuest(dst, privFlags);
 
845
   }
 
846
 
 
847
   VMCI_WARNING((LGPFX"Unknown route (%d) for doorbell.\n", route));
 
848
   return VMCI_ERROR_DST_UNREACHABLE;
 
849
}
 
850
 
 
851
 
 
852
/*
 
853
 *------------------------------------------------------------------------------
 
854
 *
 
855
 * VMCIDoorbellDelayedDispatchCB --
 
856
 *
 
857
 *    Calls the specified callback in a delayed context.
 
858
 *
 
859
 * Results:
 
860
 *    None.
 
861
 *
 
862
 * Side effects:
 
863
 *    None.
 
864
 *
 
865
 *------------------------------------------------------------------------------
 
866
 */
 
867
 
 
868
static void
 
869
VMCIDoorbellDelayedDispatchCB(void *data) // IN
 
870
{
 
871
   VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)data;
 
872
 
 
873
   ASSERT(data);
 
874
 
 
875
   entry->notifyCB(entry->clientData);
 
876
 
 
877
   VMCIResource_Release(&entry->resource);
 
878
}
 
879
 
 
880
 
 
881
/*
 
882
 *------------------------------------------------------------------------------
 
883
 *
 
884
 * VMCIDoorbellHostContextNotify --
 
885
 *
 
886
 *    Dispatches a doorbell notification to the host context.
 
887
 *
 
888
 * Results:
 
889
 *    VMCI_SUCCESS on success. Appropriate error code otherwise.
 
890
 *
 
891
 * Side effects:
 
892
 *    None.
 
893
 *
 
894
 *------------------------------------------------------------------------------
 
895
 */
 
896
 
 
897
int
 
898
VMCIDoorbellHostContextNotify(VMCIId srcCID,     // IN
 
899
                              VMCIHandle handle) // IN
 
900
{
 
901
   VMCIDoorbellEntry *entry;
 
902
   VMCIResource *resource;
 
903
   int result;
 
904
 
 
905
   ASSERT(VMCI_HostPersonalityActive());
 
906
 
 
907
   resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
 
908
   if (resource == NULL) {
 
909
      VMCI_DEBUG_LOG(4,
 
910
                     (LGPFX"Notifying an invalid doorbell (handle=0x%x:0x%x).\n",
 
911
                      handle.context, handle.resource));
 
912
      return VMCI_ERROR_INVALID_ARGS;
 
913
   }
 
914
   entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
 
915
 
 
916
   if (entry->runDelayed) {
 
917
      result = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, entry);
 
918
      if (result < VMCI_SUCCESS) {
 
919
         /*
 
920
          * If we failed to schedule the delayed work, we need to
 
921
          * release the resource immediately. Otherwise, the resource
 
922
          * will be released once the delayed callback has been
 
923
          * completed.
 
924
          */
 
925
 
 
926
         VMCI_DEBUG_LOG(10, (LGPFX"Failed to schedule delayed doorbell "
 
927
                             "notification (result=%d).\n", result));
 
928
         VMCIResource_Release(resource);
 
929
      }
 
930
   } else {
 
931
      entry->notifyCB(entry->clientData);
 
932
      VMCIResource_Release(resource);
 
933
      result = VMCI_SUCCESS;
 
934
   }
 
935
   return result;
 
936
}
 
937
 
 
938
 
 
939
/*
 
940
 *------------------------------------------------------------------------------
 
941
 *
 
942
 * VMCIDoorbell_Hibernate --
 
943
 *
 
944
 *      When a guest leaves hibernation, the device driver state is out of sync
 
945
 *      with the device state, since the driver state has doorbells registered
 
946
 *      that aren't known to the device.  This function takes care of
 
947
 *      reregistering any doorbells. In case an error occurs during
 
948
 *      reregistration (this is highly unlikely since 1) it succeeded the first
 
949
 *      time 2) the device driver is the only source of doorbell registrations),
 
950
 *      we simply log the error.  The doorbell can still be destroyed using
 
951
 *      VMCIDoorbell_Destroy.
 
952
 *
 
953
 * Results:
 
954
 *      None.
 
955
 *
 
956
 * Side effects:
 
957
 *      None.
 
958
 *
 
959
 *------------------------------------------------------------------------------
 
960
 */
 
961
 
 
962
void
 
963
VMCIDoorbell_Hibernate(Bool enterHibernate)
 
964
{
 
965
   uint32 bucket;
 
966
   VMCIListItem *iter;
 
967
   VMCILockFlags flags;
 
968
 
 
969
   if (!VMCI_GuestPersonalityActive() || enterHibernate) {
 
970
      return;
 
971
   }
 
972
 
 
973
   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
 
974
 
 
975
   for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); bucket++) {
 
976
      VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
 
977
         int result;
 
978
         VMCIDoorbellEntry *cur;
 
979
 
 
980
         cur = VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
 
981
         result = VMCIDoorbellLink(cur->resource.handle, cur->isDoorbell,
 
982
                                   cur->idx);
 
983
         if (result != VMCI_SUCCESS && result != VMCI_ERROR_DUPLICATE_ENTRY) {
 
984
            VMCI_WARNING((LGPFX"Failed to reregister doorbell "
 
985
                          "(handle=0x%x:0x%x) of resource %s to index "
 
986
                          "(error: %d).\n",
 
987
                          cur->resource.handle.context,
 
988
                          cur->resource.handle.resource,
 
989
                          cur->isDoorbell ? "doorbell" : "queue pair", result));
 
990
         }
 
991
      }
 
992
   }
 
993
 
 
994
   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
 
995
}
 
996
 
 
997
 
 
998
/*
 
999
 *------------------------------------------------------------------------------
 
1000
 *
 
1001
 * VMCIDoorbell_Sync --
 
1002
 *
 
1003
 *      Use this as a synchronization point when setting globals, for example,
 
1004
 *      during device shutdown.
 
1005
 *
 
1006
 * Results:
 
1007
 *      None.
 
1008
 *
 
1009
 * Side effects:
 
1010
 *      None.
 
1011
 *
 
1012
 *------------------------------------------------------------------------------
 
1013
 */
 
1014
 
 
1015
void
 
1016
VMCIDoorbell_Sync(void)
 
1017
{
 
1018
   VMCILockFlags flags;
 
1019
   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
 
1020
   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
 
1021
   VMCIResource_Sync();
 
1022
}
 
1023
 
 
1024
 
 
1025
/*
 
1026
 *------------------------------------------------------------------------------
 
1027
 *
 
1028
 * VMCI_RegisterNotificationBitmap --
 
1029
 *
 
1030
 *      Register the notification bitmap with the host.
 
1031
 *
 
1032
 * Results:
 
1033
 *      TRUE if the bitmap is registered successfully with the device, FALSE
 
1034
 *      otherwise.
 
1035
 *
 
1036
 * Side effects:
 
1037
 *      None.
 
1038
 *
 
1039
 *------------------------------------------------------------------------------
 
1040
 */
 
1041
 
 
1042
Bool
 
1043
VMCI_RegisterNotificationBitmap(PPN bitmapPPN)
 
1044
{
 
1045
   int result;
 
1046
   VMCINotifyBitmapSetMsg bitmapSetMsg;
 
1047
 
 
1048
   /*
 
1049
    * Do not ASSERT() on the guest device here.  This function can get called
 
1050
    * during device initialization, so the ASSERT() will fail even though
 
1051
    * the device is (almost) up.
 
1052
    */
 
1053
 
 
1054
   bitmapSetMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
 
1055
                                           VMCI_SET_NOTIFY_BITMAP);
 
1056
   bitmapSetMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
 
1057
   bitmapSetMsg.hdr.payloadSize = sizeof bitmapSetMsg - VMCI_DG_HEADERSIZE;
 
1058
   bitmapSetMsg.bitmapPPN = bitmapPPN;
 
1059
 
 
1060
   result = VMCI_SendDatagram((VMCIDatagram *)&bitmapSetMsg);
 
1061
   if (result != VMCI_SUCCESS) {
 
1062
      VMCI_DEBUG_LOG(4, (LGPFX"Failed to register (PPN=%u) as "
 
1063
                         "notification bitmap (error=%d).\n",
 
1064
                         bitmapPPN, result));
 
1065
      return FALSE;
 
1066
   }
 
1067
   return TRUE;
 
1068
}
 
1069
 
 
1070
 
 
1071
/*
 
1072
 *-------------------------------------------------------------------------
 
1073
 *
 
1074
 * VMCIDoorbellFireEntries --
 
1075
 *
 
1076
 *     Executes or schedules the handlers for a given notify index.
 
1077
 *
 
1078
 * Result:
 
1079
 *     Notification hash entry if found. NULL otherwise.
 
1080
 *
 
1081
 * Side effects:
 
1082
 *     Whatever the side effects of the handlers are.
 
1083
 *
 
1084
 *-------------------------------------------------------------------------
 
1085
 */
 
1086
 
 
1087
static void
 
1088
VMCIDoorbellFireEntries(uint32 notifyIdx) // IN
 
1089
{
 
1090
   uint32 bucket = VMCI_DOORBELL_HASH(notifyIdx);
 
1091
   VMCIListItem *iter;
 
1092
   VMCILockFlags flags;
 
1093
 
 
1094
   ASSERT(VMCI_GuestPersonalityActive());
 
1095
 
 
1096
   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
 
1097
 
 
1098
   VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
 
1099
      VMCIDoorbellEntry *cur =
 
1100
         VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
 
1101
 
 
1102
      ASSERT(cur);
 
1103
 
 
1104
      if (cur->idx == notifyIdx) {
 
1105
         ASSERT(cur->notifyCB);
 
1106
         if (cur->runDelayed) {
 
1107
            int err;
 
1108
 
 
1109
            VMCIResource_Hold(&cur->resource);
 
1110
            err = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, cur);
 
1111
            if (err != VMCI_SUCCESS) {
 
1112
               VMCIResource_Release(&cur->resource);
 
1113
               goto out;
 
1114
            }
 
1115
         } else {
 
1116
            cur->notifyCB(cur->clientData);
 
1117
         }
 
1118
      }
 
1119
   }
 
1120
 
 
1121
out:
 
1122
   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
 
1123
}
 
1124
 
 
1125
 
 
1126
/*
 
1127
 *------------------------------------------------------------------------------
 
1128
 *
 
1129
 * VMCI_ScanNotificationBitmap --
 
1130
 *
 
1131
 *      Scans the notification bitmap, collects pending notifications,
 
1132
 *      resets the bitmap and invokes appropriate callbacks.
 
1133
 *
 
1134
 * Results:
 
1135
 *      None.
 
1136
 *
 
1137
 * Side effects:
 
1138
 *      May schedule tasks, allocate memory and run callbacks.
 
1139
 *
 
1140
 *------------------------------------------------------------------------------
 
1141
 */
 
1142
 
 
1143
void
 
1144
VMCI_ScanNotificationBitmap(uint8 *bitmap)
 
1145
{
 
1146
   uint32 idx;
 
1147
 
 
1148
   ASSERT(bitmap);
 
1149
   ASSERT(VMCI_GuestPersonalityActive());
 
1150
 
 
1151
   for (idx = 0; idx < maxNotifyIdx; idx++) {
 
1152
      if (bitmap[idx] & 0x1) {
 
1153
         bitmap[idx] &= ~1;
 
1154
         VMCIDoorbellFireEntries(idx);
 
1155
      }
 
1156
   }
 
1157
}
 
1158
 
 
1159
 
 
1160
#else // SOLARIS) || __APPLE__
 
1161
 
 
1162
/*
 
1163
 *-----------------------------------------------------------------------------
 
1164
 *
 
1165
 * VMCIDoorbell_Create/VMCIDoorbell_Destroy/VMCIDoorbell_Notify/
 
1166
 * VMCIDoorbellHostContextNotify/VMCIDoorbellGetPrivFlags/
 
1167
 * VMCIDoorbell_Init/VMCIDoorbell_Exit --
 
1168
 *
 
1169
 *      The doorbell functions have yet to be implemented for Solaris
 
1170
 *      and Mac OS X guest drivers.
 
1171
 *
 
1172
 * Results:
 
1173
 *      VMCI_ERROR_UNAVAILABLE.
 
1174
 *
 
1175
 * Side effects:
 
1176
 *      None.
 
1177
 *
 
1178
 *-----------------------------------------------------------------------------
 
1179
 */
 
1180
 
 
1181
VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create)
 
1182
int
 
1183
VMCIDoorbell_Create(VMCIHandle *handle,            // IN
 
1184
                    uint32 flags,                  // IN
 
1185
                    VMCIPrivilegeFlags privFlags,  // IN
 
1186
                    VMCICallback notifyCB,         // IN
 
1187
                    void *clientData)              // IN
 
1188
{
 
1189
   return VMCI_ERROR_UNAVAILABLE;
 
1190
}
 
1191
 
 
1192
 
 
1193
VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy)
 
1194
int
 
1195
VMCIDoorbell_Destroy(VMCIHandle handle)  // IN
 
1196
{
 
1197
   return VMCI_ERROR_UNAVAILABLE;
 
1198
}
 
1199
 
 
1200
 
 
1201
VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify)
 
1202
int
 
1203
VMCIDoorbell_Notify(VMCIHandle handle,             // IN
 
1204
                    VMCIPrivilegeFlags privFlags)  // IN
 
1205
{
 
1206
   return VMCI_ERROR_UNAVAILABLE;
 
1207
}
 
1208
 
 
1209
 
 
1210
int
 
1211
VMCIDoorbellHostContextNotify(VMCIId srcCID,     // IN
 
1212
                              VMCIHandle handle) // IN
 
1213
{
 
1214
   return VMCI_ERROR_UNAVAILABLE;
 
1215
}
 
1216
 
 
1217
 
 
1218
int
 
1219
VMCIDoorbellGetPrivFlags(VMCIHandle handle,             // IN
 
1220
                         VMCIPrivilegeFlags *privFlags) // OUT
 
1221
{
 
1222
   return VMCI_ERROR_UNAVAILABLE;
 
1223
}
 
1224
 
 
1225
 
 
1226
void
 
1227
VMCIDoorbell_Init(void)
 
1228
{
 
1229
}
 
1230
 
 
1231
 
 
1232
void
 
1233
VMCIDoorbell_Exit(void)
 
1234
{
 
1235
}
 
1236
 
 
1237
#endif // SOLARIS) || __APPLE__