~n-muench/ubuntu/precise/open-vm-tools/open-vm-tools.raring-precise.backport

« back to all changes in this revision

Viewing changes to modules/linux/vmci/vmciUtil.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
 
 * vmciUtil.c
21
 
 *
22
 
 * Small utility function for allocating kernel memory and copying data.
23
 
 *
24
 
 */
25
 
 
26
 
#ifdef __linux__
27
 
#  include "driver-config.h"
28
 
 
29
 
#  define EXPORT_SYMTAB
30
 
 
31
 
#  include <linux/module.h>
32
 
#  include <linux/module.h>
33
 
#  include "compat_kernel.h"
34
 
#  include "compat_slab.h"
35
 
#  include "compat_wait.h"
36
 
#  include "compat_interrupt.h"
37
 
#elif defined(_WIN32)
38
 
#  ifndef WINNT_DDK
39
 
#     error  This file only works with the NT ddk
40
 
#  endif // WINNT_DDK
41
 
#  include <ntddk.h>
42
 
#elif defined(SOLARIS)
43
 
#  include <sys/ddi.h>
44
 
#  include <sys/sunddi.h>
45
 
#  include <sys/disp.h>
46
 
#elif defined(__APPLE__)
47
 
#  include <IOKit/IOLib.h>
48
 
#else
49
 
#error "platform not supported."
50
 
#endif //linux
51
 
 
52
 
#define LGPFX "VMCIUtil: "
53
 
 
54
 
#include "vmware.h"
55
 
#include "vm_atomic.h"
56
 
#include "vmci_defs.h"
57
 
#include "vmci_kernel_if.h"
58
 
#include "vmciGuestKernelIf.h"
59
 
#include "vmciInt.h"
60
 
#include "vmciProcess.h"
61
 
#include "vmciDatagram.h"
62
 
#include "vmciUtil.h"
63
 
#include "vmciEvent.h"
64
 
#include "vmciKernelAPI.h"
65
 
 
66
 
static void VMCIUtilCidUpdate(VMCIId subID, VMCI_EventData *eventData,
67
 
                              void *clientData);
68
 
 
69
 
static VMCIId ctxUpdateSubID = VMCI_INVALID_ID;
70
 
static Atomic_uint32 vmContextID = { VMCI_INVALID_ID };
71
 
 
72
 
 
73
 
/*
74
 
 *-----------------------------------------------------------------------------
75
 
 *
76
 
 * VMCIUtil_Init --
77
 
 *
78
 
 *      Subscribe to context id update event.
79
 
 *
80
 
 * Results:
81
 
 *      None.
82
 
 *
83
 
 * Side effects:
84
 
 *      None.
85
 
 *
86
 
 *-----------------------------------------------------------------------------
87
 
 */
88
 
 
89
 
void
90
 
VMCIUtil_Init(void)
91
 
{
92
 
   /*
93
 
    * We subscribe to the VMCI_EVENT_CTX_ID_UPDATE here so we can update the
94
 
    * internal context id when needed.
95
 
    */
96
 
   if (VMCIEvent_Subscribe(VMCI_EVENT_CTX_ID_UPDATE, VMCI_FLAG_EVENT_NONE,
97
 
                           VMCIUtilCidUpdate, NULL,
98
 
                           &ctxUpdateSubID) < VMCI_SUCCESS) {
99
 
      VMCI_LOG(("VMCIUtil: Failed to subscribe to event %d.\n",
100
 
                VMCI_EVENT_CTX_ID_UPDATE));
101
 
   }
102
 
}
103
 
 
104
 
 
105
 
/*
106
 
 *-----------------------------------------------------------------------------
107
 
 *
108
 
 * VMCIUtil_Exit --
109
 
 *
110
 
 *      Cleanup
111
 
 *
112
 
 * Results:
113
 
 *      None.
114
 
 *
115
 
 * Side effects:
116
 
 *      None.
117
 
 *
118
 
 *-----------------------------------------------------------------------------
119
 
 */
120
 
 
121
 
void
122
 
VMCIUtil_Exit(void)
123
 
{
124
 
   if (VMCIEvent_Unsubscribe(ctxUpdateSubID) < VMCI_SUCCESS) {
125
 
      VMCI_LOG(("VMCIUtil: Failed to unsubscribe to event %d with subscriber "
126
 
                "id %d.\n", VMCI_EVENT_CTX_ID_UPDATE, ctxUpdateSubID));
127
 
   }
128
 
}
129
 
 
130
 
 
131
 
/*
132
 
 *-----------------------------------------------------------------------------
133
 
 *
134
 
 * VMCIUtilCidUpdate --
135
 
 *
136
 
 *      Gets called with the new context id if updated or resumed.
137
 
 *
138
 
 * Results:
139
 
 *      Context id.
140
 
 *
141
 
 * Side effects:
142
 
 *      None.
143
 
 *
144
 
 *-----------------------------------------------------------------------------
145
 
 */
146
 
 
147
 
static void
148
 
VMCIUtilCidUpdate(VMCIId subID,               // IN:
149
 
                  VMCI_EventData *eventData,  // IN:
150
 
                  void *clientData)           // IN:
151
 
{
152
 
   VMCIEventPayload_Context *evPayload = VMCIEventDataPayload(eventData);
153
 
 
154
 
   if (subID != ctxUpdateSubID) {
155
 
      VMCI_LOG(("VMCIUtil: Invalid subscriber id. %d.\n", subID));
156
 
      return;
157
 
   }
158
 
   if (eventData == NULL || evPayload->contextID == VMCI_INVALID_ID) {
159
 
      VMCI_LOG(("VMCIUtil: Invalid event data.\n"));
160
 
      return;
161
 
   }
162
 
   VMCI_LOG(("VMCIUtil: Updating context id from 0x%x to 0x%x on event %d.\n",
163
 
             Atomic_Read(&vmContextID),
164
 
             evPayload->contextID,
165
 
             eventData->event));
166
 
   Atomic_Write(&vmContextID, evPayload->contextID);
167
 
}
168
 
 
169
 
 
170
 
 
171
 
/*
172
 
 *-----------------------------------------------------------------------------
173
 
 *
174
 
 * VMCIUtil_CheckHostCapabilities --
175
 
 *
176
 
 *      Verify that the host supports the hypercalls we need. If it does not,
177
 
 *      try to find fallback hypercalls and use those instead.
178
 
 *
179
 
 * Results:
180
 
 *      TRUE if required hypercalls (or fallback hypercalls) are
181
 
 *      supported by the host, FALSE otherwise.
182
 
 *
183
 
 * Side effects:
184
 
 *      None.
185
 
 *
186
 
 *-----------------------------------------------------------------------------
187
 
 */
188
 
 
189
 
#define VMCI_UTIL_NUM_RESOURCES 1
190
 
 
191
 
Bool
192
 
VMCIUtil_CheckHostCapabilities(void)
193
 
{
194
 
   int result;
195
 
   VMCIResourcesQueryMsg *msg;
196
 
   uint32 msgSize = sizeof(VMCIResourcesQueryHdr) +
197
 
      VMCI_UTIL_NUM_RESOURCES * sizeof(VMCI_Resource);
198
 
   VMCIDatagram *checkMsg = VMCI_AllocKernelMem(msgSize, VMCI_MEMORY_NONPAGED);
199
 
 
200
 
   if (checkMsg == NULL) {
201
 
      VMCI_LOG((LGPFX"Check host: Insufficient memory.\n"));
202
 
      return FALSE;
203
 
   }
204
 
 
205
 
   checkMsg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
206
 
                                    VMCI_RESOURCES_QUERY);
207
 
   checkMsg->src = VMCI_ANON_SRC_HANDLE;
208
 
   checkMsg->payloadSize = msgSize - VMCI_DG_HEADERSIZE;
209
 
   msg = (VMCIResourcesQueryMsg *)VMCI_DG_PAYLOAD(checkMsg);
210
 
 
211
 
   msg->numResources = VMCI_UTIL_NUM_RESOURCES;
212
 
   msg->resources[0] = VMCI_GET_CONTEXT_ID;
213
 
 
214
 
   result = VMCI_SendDatagram(checkMsg);
215
 
   VMCI_FreeKernelMem(checkMsg, msgSize);
216
 
 
217
 
   /* We need the vector. There are no fallbacks. */
218
 
   return (result == 0x1);
219
 
}
220
 
 
221
 
 
222
 
/*
223
 
 *-----------------------------------------------------------------------------
224
 
 *
225
 
 * VMCI_GetContextID --
226
 
 *
227
 
 *      Returns the context id.
228
 
 *
229
 
 * Results:
230
 
 *      Context id.
231
 
 *
232
 
 * Side effects:
233
 
 *      None.
234
 
 *
235
 
 *-----------------------------------------------------------------------------
236
 
 */
237
 
 
238
 
#ifdef __linux__
239
 
EXPORT_SYMBOL(VMCI_GetContextID);
240
 
#endif
241
 
 
242
 
VMCIId
243
 
VMCI_GetContextID(void)
244
 
{
245
 
   if (Atomic_Read(&vmContextID) == VMCI_INVALID_ID) {
246
 
      uint32 result;
247
 
      VMCIDatagram getCidMsg;
248
 
      getCidMsg.dst =  VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
249
 
                                        VMCI_GET_CONTEXT_ID);
250
 
      getCidMsg.src = VMCI_ANON_SRC_HANDLE;
251
 
      getCidMsg.payloadSize = 0;
252
 
      result = VMCI_SendDatagram(&getCidMsg);
253
 
      Atomic_Write(&vmContextID, result);
254
 
   }
255
 
   return Atomic_Read(&vmContextID);
256
 
}
257
 
 
258
 
 
259
 
/*
260
 
 *-----------------------------------------------------------------------------
261
 
 *
262
 
 * VMCI_CheckHostCapabilities --
263
 
 *
264
 
 *      Tell host which guestcalls we support and let each API check
265
 
 *      that the host supports the hypercalls it needs. If a hypercall
266
 
 *      is not supported, the API can check for a fallback hypercall,
267
 
 *      or fail the check.
268
 
 *
269
 
 * Results:
270
 
 *      TRUE if successful, FALSE otherwise.
271
 
 *
272
 
 * Side effects:
273
 
 *      Fallback mechanisms may be enabled in the API and vmmon.
274
 
 *
275
 
 *-----------------------------------------------------------------------------
276
 
 */
277
 
 
278
 
Bool
279
 
VMCI_CheckHostCapabilities(void)
280
 
{
281
 
   Bool result = VMCIEvent_CheckHostCapabilities();
282
 
   result &= VMCIProcess_CheckHostCapabilities();
283
 
   result &= VMCIDatagram_CheckHostCapabilities();
284
 
   result &= VMCIUtil_CheckHostCapabilities();
285
 
 
286
 
   VMCI_LOG((LGPFX"Host capability check: %s\n", result ? "PASSED" : "FAILED"));
287
 
 
288
 
   return result;
289
 
}
290
 
 
291
 
/*
292
 
 *----------------------------------------------------------------------
293
 
 *
294
 
 * VMCI_Version --
295
 
 *
296
 
 *     Returns the version of the VMCI guest driver.
297
 
 *
298
 
 * Results:
299
 
 *      Returns a version number.
300
 
 *
301
 
 * Side effects:
302
 
 *      None.
303
 
 *
304
 
 *----------------------------------------------------------------------
305
 
 */
306
 
 
307
 
#ifdef __linux__
308
 
EXPORT_SYMBOL(VMCI_Version);
309
 
#endif
310
 
 
311
 
uint32
312
 
VMCI_Version()
313
 
{
314
 
   return VMCI_VERSION_NUMBER;
315
 
}
316
 
 
317
 
 
318
 
/*
319
 
 *----------------------------------------------------------------------
320
 
 *
321
 
 * VMCI_InInterrupt --
322
 
 *
323
 
 *     Determines if we are running in tasklet/dispatch level or above.
324
 
 *
325
 
 * Results:
326
 
 *      TRUE if tasklet/dispatch or above, FALSE otherwise.
327
 
 *
328
 
 * Side effects:
329
 
 *      None.
330
 
 *
331
 
 *----------------------------------------------------------------------
332
 
 */
333
 
 
334
 
Bool
335
 
VMCI_InInterrupt()
336
 
{
337
 
#if defined(_WIN32)
338
 
   return KeGetCurrentIrql() >= DISPATCH_LEVEL;
339
 
#elif defined(__linux__)
340
 
   return in_interrupt();
341
 
#elif defined(SOLARIS)
342
 
   return servicing_interrupt();   /* servicing_interrupt is not part of DDI. */
343
 
#elif defined(__APPLE__)
344
 
   /*
345
 
    * All interrupt servicing is handled by IOKit functions, by the time the IOService
346
 
    * interrupt handler is called we're no longer in an interrupt dispatch level.
347
 
    */
348
 
   return false;
349
 
#endif //
350
 
}
351
 
 
352
 
 
353
 
/*
354
 
 *----------------------------------------------------------------------
355
 
 *
356
 
 * VMCI_DeviceGet --
357
 
 *
358
 
 *      Verifies that a valid VMCI device is present, and indicates
359
 
 *      the callers intention to use the device until it calls
360
 
 *      VMCI_DeviceRelease().
361
 
 *
362
 
 * Results:
363
 
 *      TRUE if a valid VMCI device is present, FALSE otherwise.
364
 
 *
365
 
 * Side effects:
366
 
 *      None.
367
 
 *
368
 
 *----------------------------------------------------------------------
369
 
 */
370
 
 
371
 
#ifdef __linux__
372
 
EXPORT_SYMBOL(VMCI_DeviceGet);
373
 
#endif
374
 
 
375
 
Bool
376
 
VMCI_DeviceGet(void)
377
 
{
378
 
   return VMCI_DeviceEnabled();
379
 
}
380
 
 
381
 
 
382
 
/*
383
 
 *----------------------------------------------------------------------
384
 
 *
385
 
 * VMCI_DeviceRelease --
386
 
 *
387
 
 *      Indicates that the caller is done using the VMCI device.
388
 
 *
389
 
 * Results:
390
 
 *      None.
391
 
 *
392
 
 * Side effects:
393
 
 *      None.
394
 
 *
395
 
 *----------------------------------------------------------------------
396
 
 */
397
 
 
398
 
#ifdef __linux__
399
 
EXPORT_SYMBOL(VMCI_DeviceRelease);
400
 
#endif
401
 
 
402
 
void
403
 
VMCI_DeviceRelease(void)
404
 
{
405
 
}
406
 
 
407
 
 
408
 
/*
409
 
 *----------------------------------------------------------------------
410
 
 *
411
 
 * VMCI_ReadDatagramsFromPort --
412
 
 *
413
 
 *      Reads datagrams from the data in port and dispatches them. We
414
 
 *      always start reading datagrams into only the first page of the
415
 
 *      datagram buffer. If the datagrams don't fit into one page, we
416
 
 *      use the maximum datagram buffer size for the remainder of the
417
 
 *      invocation. This is a simple heuristic for not penalizing
418
 
 *      small datagrams.
419
 
 *
420
 
 *      This function assumes that it has exclusive access to the data
421
 
 *      in port for the duration of the call.
422
 
 *
423
 
 * Results:
424
 
 *      No result.
425
 
 *
426
 
 * Side effects:
427
 
 *      Datagram handlers may be invoked.
428
 
 *
429
 
 *----------------------------------------------------------------------
430
 
 */
431
 
 
432
 
void
433
 
VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle,  // IN
434
 
                           VMCIIoPort dgInPort,    // IN
435
 
                           uint8 *dgInBuffer,      // IN
436
 
                           size_t dgInBufferSize)  // IN
437
 
{
438
 
   VMCIDatagram *dg;
439
 
   size_t currentDgInBufferSize = PAGE_SIZE;
440
 
   size_t remainingBytes;
441
 
 
442
 
   ASSERT(dgInBufferSize >= PAGE_SIZE);
443
 
 
444
 
   VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
445
 
   dg = (VMCIDatagram *)dgInBuffer;
446
 
   remainingBytes = currentDgInBufferSize;
447
 
 
448
 
   while (dg->dst.resource != VMCI_INVALID_ID || remainingBytes > PAGE_SIZE) {
449
 
      unsigned dgInSize;
450
 
 
451
 
      /*
452
 
       * When the input buffer spans multiple pages, a datagram can
453
 
       * start on any page boundary in the buffer.
454
 
       */
455
 
 
456
 
      if (dg->dst.resource == VMCI_INVALID_ID) {
457
 
         ASSERT(remainingBytes > PAGE_SIZE);
458
 
         dg = (VMCIDatagram *)ROUNDUP((uintptr_t)dg + 1, PAGE_SIZE);
459
 
         ASSERT((uint8 *)dg < dgInBuffer + currentDgInBufferSize);
460
 
         remainingBytes = (size_t)(dgInBuffer + currentDgInBufferSize - (uint8 *)dg);
461
 
         continue;
462
 
      }
463
 
 
464
 
      dgInSize = VMCI_DG_SIZE_ALIGNED(dg);
465
 
 
466
 
      if (dgInSize <= dgInBufferSize) {
467
 
         int result;
468
 
 
469
 
         /*
470
 
          * If the remaining bytes in the datagram buffer doesn't
471
 
          * contain the complete datagram, we first make sure we have
472
 
          * enough room for it and then we read the reminder of the
473
 
          * datagram and possibly any following datagrams.
474
 
          */
475
 
 
476
 
         if (dgInSize > remainingBytes) {
477
 
 
478
 
            if (remainingBytes != currentDgInBufferSize) {
479
 
 
480
 
               /*
481
 
                * We move the partial datagram to the front and read
482
 
                * the reminder of the datagram and possibly following
483
 
                * calls into the following bytes.
484
 
                */
485
 
 
486
 
               memmove(dgInBuffer, dgInBuffer + currentDgInBufferSize - remainingBytes,
487
 
                       remainingBytes);
488
 
 
489
 
               dg = (VMCIDatagram *)dgInBuffer;
490
 
            }
491
 
 
492
 
            if (currentDgInBufferSize != dgInBufferSize) {
493
 
               currentDgInBufferSize = dgInBufferSize;
494
 
            }
495
 
 
496
 
            VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer + remainingBytes,
497
 
                               currentDgInBufferSize - remainingBytes);
498
 
         }
499
 
 
500
 
         /* We special case event datagrams from the hypervisor. */
501
 
         if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
502
 
             dg->dst.resource == VMCI_EVENT_HANDLER) {
503
 
            result = VMCIEvent_Dispatch(dg);
504
 
         } else {
505
 
            result = VMCIDatagram_Dispatch(dg->src.context, dg);
506
 
         }
507
 
         if (result < VMCI_SUCCESS) {
508
 
            VMCI_LOG(("Datagram with resource %d failed with err %x.\n",
509
 
                      dg->dst.resource, result));
510
 
         }
511
 
 
512
 
         /* On to the next datagram. */
513
 
         dg = (VMCIDatagram *)((uint8 *)dg + dgInSize);
514
 
      } else {
515
 
         size_t bytesToSkip;
516
 
 
517
 
         /*
518
 
          * Datagram doesn't fit in datagram buffer of maximal size. We drop it.
519
 
          */
520
 
 
521
 
         VMCI_LOG(("Failed to receive datagram of size %u.\n",
522
 
                   dgInSize));
523
 
 
524
 
         bytesToSkip = dgInSize - remainingBytes;
525
 
         if (currentDgInBufferSize != dgInBufferSize) {
526
 
            currentDgInBufferSize = dgInBufferSize;
527
 
         }
528
 
         for (;;) {
529
 
            VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
530
 
            if (bytesToSkip <= currentDgInBufferSize) {
531
 
               break;
532
 
            }
533
 
            bytesToSkip -= currentDgInBufferSize;
534
 
         }
535
 
         dg = (VMCIDatagram *)(dgInBuffer + bytesToSkip);
536
 
      }
537
 
 
538
 
      remainingBytes = (size_t) (dgInBuffer + currentDgInBufferSize - (uint8 *)dg);
539
 
 
540
 
      if (remainingBytes < VMCI_DG_HEADERSIZE) {
541
 
         /* Get the next batch of datagrams. */
542
 
 
543
 
         VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
544
 
         dg = (VMCIDatagram *)dgInBuffer;
545
 
         remainingBytes = currentDgInBufferSize;
546
 
      }
547
 
   }
548
 
}
549
 
 
550
 
 
551
 
/*
552
 
 *----------------------------------------------------------------------
553
 
 *
554
 
 * VMCIContext_GetPrivFlags --
555
 
 *
556
 
 *      Provided for compatibility with the host VMCI API.
557
 
 *
558
 
 * Results:
559
 
 *      Always returns VMCI_NO_PRIVILEGE_FLAGS.
560
 
 *
561
 
 * Side effects:
562
 
 *      None.
563
 
 *
564
 
 *----------------------------------------------------------------------
565
 
 */
566
 
 
567
 
#ifdef __linux__
568
 
EXPORT_SYMBOL(VMCIContext_GetPrivFlags);
569
 
#endif
570
 
 
571
 
VMCIPrivilegeFlags
572
 
VMCIContext_GetPrivFlags(VMCIId contextID) // IN
573
 
{
574
 
   return VMCI_NO_PRIVILEGE_FLAGS;
575
 
}
576
 
 
577
 
 
578
 
/*
579
 
 *----------------------------------------------------------------------
580
 
 *
581
 
 * VMCI_ContextID2HostVmID --
582
 
 *
583
 
 *      Provided for compatibility with the host VMCI API.
584
 
 *
585
 
 * Results:
586
 
 *      Returns VMCI_ERROR_UNAVAILABLE.
587
 
 *
588
 
 * Side effects:
589
 
 *      None.
590
 
 *
591
 
 *----------------------------------------------------------------------
592
 
 */
593
 
 
594
 
#ifdef __linux__
595
 
EXPORT_SYMBOL(VMCI_ContextID2HostVmID);
596
 
#endif
597
 
 
598
 
int
599
 
VMCI_ContextID2HostVmID(VMCIId contextID,    // IN
600
 
                        void *hostVmID,      // OUT
601
 
                        size_t hostVmIDLen)  // IN
602
 
{
603
 
   return VMCI_ERROR_UNAVAILABLE;
604
 
}