~n-muench/ubuntu/oneiric/open-vm-tools/open-vm-tools.fix-836277

« back to all changes in this revision

Viewing changes to modules/linux/vmci/vmciUtil.c

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2008-08-15 21:21:40 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080815212140-05fhxj8wroosysmj
Tags: 2008.08.08-109361-1ubuntu1
* Merge from Debian unstable (LP: #258393), remaining Ubuntu change:
  - add ubuntu_toolchain_FTBFS.dpatch patch, fix FTBFS
* Update ubuntu_toolchain_FTBFS.dpatch patch for the new version.

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