1
/*********************************************************
2
* Copyright (C) 2006 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation version 2 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
*********************************************************/
22
* Small utility function for allocating kernel memory and copying data.
27
# include "driver-config.h"
29
# define EXPORT_SYMTAB
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"
39
# error This file only works with the NT ddk
42
#elif defined(SOLARIS)
44
# include <sys/sunddi.h>
45
# include <sys/disp.h>
47
#error "platform not supported."
50
#define LGPFX "VMCIUtil: "
53
#include "vm_atomic.h"
54
#include "vmci_defs.h"
55
#include "vmci_kernel_if.h"
56
#include "vmciGuestKernelIf.h"
58
#include "vmciProcess.h"
59
#include "vmciDatagram.h"
61
#include "vmciEvent.h"
63
static void VMCIUtilCidUpdate(VMCIId subID, VMCI_EventData *eventData,
66
static VMCIId ctxUpdateSubID = VMCI_INVALID_ID;
67
static Atomic_uint32 vmContextID = { VMCI_INVALID_ID };
71
*-----------------------------------------------------------------------------
75
* Subscribe to context id update event.
83
*-----------------------------------------------------------------------------
90
* We subscribe to the VMCI_EVENT_CTX_ID_UPDATE here so we can update the
91
* internal context id when needed.
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));
102
*-----------------------------------------------------------------------------
114
*-----------------------------------------------------------------------------
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));
128
*-----------------------------------------------------------------------------
130
* VMCIUtilCidUpdate --
132
* Gets called with the new context id if updated or resumed.
140
*-----------------------------------------------------------------------------
144
VMCIUtilCidUpdate(VMCIId subID, // IN:
145
VMCI_EventData *eventData, // IN:
146
void *clientData) // IN:
148
VMCIEventPayload_Context *evPayload = VMCIEventDataPayload(eventData);
150
if (subID != ctxUpdateSubID) {
151
VMCI_LOG(("VMCIUtil: Invalid subscriber id. %d.\n", subID));
154
if (eventData == NULL || evPayload->contextID == VMCI_INVALID_ID) {
155
VMCI_LOG(("VMCIUtil: Invalid event data.\n"));
158
VMCI_LOG(("VMCIUtil: Updating context id from 0x%x to 0x%x on event %d.\n",
159
Atomic_Read(&vmContextID),
160
evPayload->contextID,
162
Atomic_Write(&vmContextID, evPayload->contextID);
168
*-----------------------------------------------------------------------------
170
* VMCIUtil_CheckHostCapabilities --
172
* Verify that the host supports the hypercalls we need. If it does not,
173
* try to find fallback hypercalls and use those instead.
176
* TRUE if required hypercalls (or fallback hypercalls) are
177
* supported by the host, FALSE otherwise.
182
*-----------------------------------------------------------------------------
185
#define VMCI_UTIL_NUM_RESOURCES 1
188
VMCIUtil_CheckHostCapabilities(void)
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);
196
if (checkMsg == NULL) {
197
VMCI_LOG((LGPFX"Check host: Insufficient memory.\n"));
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);
207
msg->numResources = VMCI_UTIL_NUM_RESOURCES;
208
msg->resources[0] = VMCI_GET_CONTEXT_ID;
210
result = VMCI_SendDatagram(checkMsg);
211
VMCI_FreeKernelMem(checkMsg, msgSize);
213
/* We need the vector. There are no fallbacks. */
214
return (result == 0x1);
219
*-----------------------------------------------------------------------------
221
* VMCI_GetContextID --
223
* Returns the context id.
231
*-----------------------------------------------------------------------------
235
EXPORT_SYMBOL(VMCI_GetContextID);
239
VMCI_GetContextID(void)
241
if (Atomic_Read(&vmContextID) == VMCI_INVALID_ID) {
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);
251
return Atomic_Read(&vmContextID);
256
*-----------------------------------------------------------------------------
258
* VMCI_CheckHostCapabilities --
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,
266
* TRUE if successful, FALSE otherwise.
269
* Fallback mechanisms may be enabled in the API and vmmon.
271
*-----------------------------------------------------------------------------
275
VMCI_CheckHostCapabilities(void)
277
Bool result = VMCIEvent_CheckHostCapabilities();
278
result &= VMCIProcess_CheckHostCapabilities();
279
result &= VMCIDatagram_CheckHostCapabilities();
280
result &= VMCIUtil_CheckHostCapabilities();
282
VMCI_LOG((LGPFX"Host capability check: %s\n", result ? "PASSED" : "FAILED"));
288
*----------------------------------------------------------------------
292
* Returns the version of the VMCI guest driver.
295
* Returns a version number.
300
*----------------------------------------------------------------------
304
EXPORT_SYMBOL(VMCI_Version);
310
return VMCI_VERSION_NUMBER;
315
*----------------------------------------------------------------------
317
* VMCI_InInterrupt --
319
* Determines if we are running in tasklet/dispatch level or above.
322
* TRUE if tasklet/dispatch or above, FALSE otherwise.
327
*----------------------------------------------------------------------
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. */
344
*----------------------------------------------------------------------
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().
353
* TRUE if a valid VMCI device is present, FALSE otherwise.
358
*----------------------------------------------------------------------
362
EXPORT_SYMBOL(VMCI_DeviceGet);
368
return VMCI_DeviceEnabled();
373
*----------------------------------------------------------------------
375
* VMCI_DeviceRelease --
377
* Indicates that the caller is done using the VMCI device.
385
*----------------------------------------------------------------------
389
EXPORT_SYMBOL(VMCI_DeviceRelease);
393
VMCI_DeviceRelease(void)
399
*----------------------------------------------------------------------
401
* VMCI_ReadDatagramsFromPort --
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
410
* This function assumes that it has exclusive access to the data
411
* in port for the duration of the call.
417
* Datagram handlers may be invoked.
419
*----------------------------------------------------------------------
423
VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle, // IN
424
VMCIIoPort dgInPort, // IN
425
uint8 *dgInBuffer, // IN
426
size_t dgInBufferSize) // IN
429
size_t currentDgInBufferSize = PAGE_SIZE;
430
size_t remainingBytes;
432
ASSERT(dgInBufferSize >= PAGE_SIZE);
434
VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
435
dg = (VMCIDatagram *)dgInBuffer;
436
remainingBytes = currentDgInBufferSize;
438
while (dg->dst.resource != VMCI_ERROR_INVALID_RESOURCE || remainingBytes > PAGE_SIZE) {
442
* When the input buffer spans multiple pages, a datagram can
443
* start on any page boundary in the buffer.
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);
454
dgInSize = VMCI_DG_SIZE_ALIGNED(dg);
456
if (dgInSize <= dgInBufferSize) {
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.
466
if (dgInSize > remainingBytes) {
468
if (remainingBytes != currentDgInBufferSize) {
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.
476
memmove(dgInBuffer, dgInBuffer + currentDgInBufferSize - remainingBytes,
479
dg = (VMCIDatagram *)dgInBuffer;
482
if (currentDgInBufferSize != dgInBufferSize) {
483
currentDgInBufferSize = dgInBufferSize;
486
VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer + remainingBytes,
487
currentDgInBufferSize - remainingBytes);
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);
495
result = VMCIDatagram_Dispatch(dg->src.context, dg);
497
if (result < VMCI_SUCCESS) {
498
VMCI_LOG(("Datagram with resource %d failed with err %x.\n",
499
dg->dst.resource, result));
502
/* On to the next datagram. */
503
dg = (VMCIDatagram *)((uint8 *)dg + dgInSize);
508
* Datagram doesn't fit in datagram buffer of maximal size. We drop it.
511
VMCI_LOG(("Failed to receive datagram of size %u.\n",
514
bytesToSkip = dgInSize - remainingBytes;
515
if (currentDgInBufferSize != dgInBufferSize) {
516
currentDgInBufferSize = dgInBufferSize;
519
VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
520
if (bytesToSkip <= currentDgInBufferSize) {
523
bytesToSkip -= currentDgInBufferSize;
525
dg = (VMCIDatagram *)(dgInBuffer + bytesToSkip);
528
remainingBytes = (size_t) (dgInBuffer + currentDgInBufferSize - (uint8 *)dg);
530
if (remainingBytes < VMCI_DG_HEADERSIZE) {
531
/* Get the next batch of datagrams. */
533
VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
534
dg = (VMCIDatagram *)dgInBuffer;
535
remainingBytes = currentDgInBufferSize;