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>
46
#elif defined(__APPLE__)
47
# include <IOKit/IOLib.h>
49
#error "platform not supported."
52
#define LGPFX "VMCIUtil: "
55
#include "vm_atomic.h"
56
#include "vmci_defs.h"
57
#include "vmci_kernel_if.h"
58
#include "vmciGuestKernelIf.h"
60
#include "vmciProcess.h"
61
#include "vmciDatagram.h"
63
#include "vmciEvent.h"
64
#include "vmciKernelAPI.h"
66
static void VMCIUtilCidUpdate(VMCIId subID, VMCI_EventData *eventData,
69
static VMCIId ctxUpdateSubID = VMCI_INVALID_ID;
70
static Atomic_uint32 vmContextID = { VMCI_INVALID_ID };
74
*-----------------------------------------------------------------------------
78
* Subscribe to context id update event.
86
*-----------------------------------------------------------------------------
93
* We subscribe to the VMCI_EVENT_CTX_ID_UPDATE here so we can update the
94
* internal context id when needed.
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));
106
*-----------------------------------------------------------------------------
118
*-----------------------------------------------------------------------------
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));
132
*-----------------------------------------------------------------------------
134
* VMCIUtilCidUpdate --
136
* Gets called with the new context id if updated or resumed.
144
*-----------------------------------------------------------------------------
148
VMCIUtilCidUpdate(VMCIId subID, // IN:
149
VMCI_EventData *eventData, // IN:
150
void *clientData) // IN:
152
VMCIEventPayload_Context *evPayload = VMCIEventDataPayload(eventData);
154
if (subID != ctxUpdateSubID) {
155
VMCI_LOG(("VMCIUtil: Invalid subscriber id. %d.\n", subID));
158
if (eventData == NULL || evPayload->contextID == VMCI_INVALID_ID) {
159
VMCI_LOG(("VMCIUtil: Invalid event data.\n"));
162
VMCI_LOG(("VMCIUtil: Updating context id from 0x%x to 0x%x on event %d.\n",
163
Atomic_Read(&vmContextID),
164
evPayload->contextID,
166
Atomic_Write(&vmContextID, evPayload->contextID);
172
*-----------------------------------------------------------------------------
174
* VMCIUtil_CheckHostCapabilities --
176
* Verify that the host supports the hypercalls we need. If it does not,
177
* try to find fallback hypercalls and use those instead.
180
* TRUE if required hypercalls (or fallback hypercalls) are
181
* supported by the host, FALSE otherwise.
186
*-----------------------------------------------------------------------------
189
#define VMCI_UTIL_NUM_RESOURCES 1
192
VMCIUtil_CheckHostCapabilities(void)
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);
200
if (checkMsg == NULL) {
201
VMCI_LOG((LGPFX"Check host: Insufficient memory.\n"));
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);
211
msg->numResources = VMCI_UTIL_NUM_RESOURCES;
212
msg->resources[0] = VMCI_GET_CONTEXT_ID;
214
result = VMCI_SendDatagram(checkMsg);
215
VMCI_FreeKernelMem(checkMsg, msgSize);
217
/* We need the vector. There are no fallbacks. */
218
return (result == 0x1);
223
*-----------------------------------------------------------------------------
225
* VMCI_GetContextID --
227
* Returns the context id.
235
*-----------------------------------------------------------------------------
239
EXPORT_SYMBOL(VMCI_GetContextID);
243
VMCI_GetContextID(void)
245
if (Atomic_Read(&vmContextID) == VMCI_INVALID_ID) {
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);
255
return Atomic_Read(&vmContextID);
260
*-----------------------------------------------------------------------------
262
* VMCI_CheckHostCapabilities --
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,
270
* TRUE if successful, FALSE otherwise.
273
* Fallback mechanisms may be enabled in the API and vmmon.
275
*-----------------------------------------------------------------------------
279
VMCI_CheckHostCapabilities(void)
281
Bool result = VMCIEvent_CheckHostCapabilities();
282
result &= VMCIProcess_CheckHostCapabilities();
283
result &= VMCIDatagram_CheckHostCapabilities();
284
result &= VMCIUtil_CheckHostCapabilities();
286
VMCI_LOG((LGPFX"Host capability check: %s\n", result ? "PASSED" : "FAILED"));
292
*----------------------------------------------------------------------
296
* Returns the version of the VMCI guest driver.
299
* Returns a version number.
304
*----------------------------------------------------------------------
308
EXPORT_SYMBOL(VMCI_Version);
314
return VMCI_VERSION_NUMBER;
319
*----------------------------------------------------------------------
321
* VMCI_InInterrupt --
323
* Determines if we are running in tasklet/dispatch level or above.
326
* TRUE if tasklet/dispatch or above, FALSE otherwise.
331
*----------------------------------------------------------------------
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__)
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.
354
*----------------------------------------------------------------------
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().
363
* TRUE if a valid VMCI device is present, FALSE otherwise.
368
*----------------------------------------------------------------------
372
EXPORT_SYMBOL(VMCI_DeviceGet);
378
return VMCI_DeviceEnabled();
383
*----------------------------------------------------------------------
385
* VMCI_DeviceRelease --
387
* Indicates that the caller is done using the VMCI device.
395
*----------------------------------------------------------------------
399
EXPORT_SYMBOL(VMCI_DeviceRelease);
403
VMCI_DeviceRelease(void)
409
*----------------------------------------------------------------------
411
* VMCI_ReadDatagramsFromPort --
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
420
* This function assumes that it has exclusive access to the data
421
* in port for the duration of the call.
427
* Datagram handlers may be invoked.
429
*----------------------------------------------------------------------
433
VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle, // IN
434
VMCIIoPort dgInPort, // IN
435
uint8 *dgInBuffer, // IN
436
size_t dgInBufferSize) // IN
439
size_t currentDgInBufferSize = PAGE_SIZE;
440
size_t remainingBytes;
442
ASSERT(dgInBufferSize >= PAGE_SIZE);
444
VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
445
dg = (VMCIDatagram *)dgInBuffer;
446
remainingBytes = currentDgInBufferSize;
448
while (dg->dst.resource != VMCI_INVALID_ID || remainingBytes > PAGE_SIZE) {
452
* When the input buffer spans multiple pages, a datagram can
453
* start on any page boundary in the buffer.
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);
464
dgInSize = VMCI_DG_SIZE_ALIGNED(dg);
466
if (dgInSize <= dgInBufferSize) {
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.
476
if (dgInSize > remainingBytes) {
478
if (remainingBytes != currentDgInBufferSize) {
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.
486
memmove(dgInBuffer, dgInBuffer + currentDgInBufferSize - remainingBytes,
489
dg = (VMCIDatagram *)dgInBuffer;
492
if (currentDgInBufferSize != dgInBufferSize) {
493
currentDgInBufferSize = dgInBufferSize;
496
VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer + remainingBytes,
497
currentDgInBufferSize - remainingBytes);
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);
505
result = VMCIDatagram_Dispatch(dg->src.context, dg);
507
if (result < VMCI_SUCCESS) {
508
VMCI_LOG(("Datagram with resource %d failed with err %x.\n",
509
dg->dst.resource, result));
512
/* On to the next datagram. */
513
dg = (VMCIDatagram *)((uint8 *)dg + dgInSize);
518
* Datagram doesn't fit in datagram buffer of maximal size. We drop it.
521
VMCI_LOG(("Failed to receive datagram of size %u.\n",
524
bytesToSkip = dgInSize - remainingBytes;
525
if (currentDgInBufferSize != dgInBufferSize) {
526
currentDgInBufferSize = dgInBufferSize;
529
VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
530
if (bytesToSkip <= currentDgInBufferSize) {
533
bytesToSkip -= currentDgInBufferSize;
535
dg = (VMCIDatagram *)(dgInBuffer + bytesToSkip);
538
remainingBytes = (size_t) (dgInBuffer + currentDgInBufferSize - (uint8 *)dg);
540
if (remainingBytes < VMCI_DG_HEADERSIZE) {
541
/* Get the next batch of datagrams. */
543
VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
544
dg = (VMCIDatagram *)dgInBuffer;
545
remainingBytes = currentDgInBufferSize;
552
*----------------------------------------------------------------------
554
* VMCIContext_GetPrivFlags --
556
* Provided for compatibility with the host VMCI API.
559
* Always returns VMCI_NO_PRIVILEGE_FLAGS.
564
*----------------------------------------------------------------------
568
EXPORT_SYMBOL(VMCIContext_GetPrivFlags);
572
VMCIContext_GetPrivFlags(VMCIId contextID) // IN
574
return VMCI_NO_PRIVILEGE_FLAGS;
579
*----------------------------------------------------------------------
581
* VMCI_ContextID2HostVmID --
583
* Provided for compatibility with the host VMCI API.
586
* Returns VMCI_ERROR_UNAVAILABLE.
591
*----------------------------------------------------------------------
595
EXPORT_SYMBOL(VMCI_ContextID2HostVmID);
599
VMCI_ContextID2HostVmID(VMCIId contextID, // IN
600
void *hostVmID, // OUT
601
size_t hostVmIDLen) // IN
603
return VMCI_ERROR_UNAVAILABLE;