コード例 #1
0
ファイル: vmciDs.c プロジェクト: ianw/vmware-workstation-7
static int
DsRequestCb(void *notifyData,  // IN: callback data
            VMCIDatagram *msg) // IN: datagram 
{
   /* FIXME: On-stack 300byte buffer is no-no.  Besides that it is ignored anyway. */
   char replyBuffer[VMCI_DS_MAX_MSG_SIZE + sizeof(VMCIDatagram)];
   VMCIDatagram *replyMsg = (VMCIDatagram *)replyBuffer;
   int written, retval;
   VMCIPrivilegeFlags srcPrivFlags;

   VMCI_DEBUG_LOG((LGPFX"Got request from context: %d\n", msg->src.context));

   if (VMCIDatagram_GetPrivFlags(msg->src, &srcPrivFlags) != VMCI_SUCCESS) {
      retval = VMCI_ERROR_INVALID_ARGS;
      goto done;
   }
   replyMsg->dst = msg->src;
   replyMsg->src = dsAPI.handle;
   DsHandleMessage(VMCI_DG_PAYLOAD(msg), VMCI_DG_PAYLOAD(replyMsg), 
                   VMCI_DS_MAX_MSG_SIZE, &written, msg->src.context,
                   srcPrivFlags);
   replyMsg->payloadSize = written;

   /* Send reply back to source handle. */
   retval = VMCIDatagramSendInt(replyMsg);
done:
   if (retval >= VMCI_SUCCESS) {
      VMCI_DEBUG_LOG((LGPFX"Successfully replied with %d bytes\n", written));
   } else {
      VMCILOG((LGPFX"Failed to reply to request: %d.\n", retval));
   }

   return retval;
}
コード例 #2
0
int
vmci_datagram_create_handle_priv(
   VMCIId resourceID,            // IN: Optional, generated if VMCI_INVALID_ID
   uint32 flags,                 // IN:
   VMCIPrivilegeFlags privFlags, // IN:
   VMCIDatagramRecvCB recvCB,    // IN:
   void *clientData,             // IN:
   VMCIHandle *outHandle)        // OUT: newly created handle
{
   if (outHandle == NULL) {
      return VMCI_ERROR_INVALID_ARGS;
   }

   if (recvCB == NULL) {
      VMCI_DEBUG_LOG(4,
                     (LGPFX"Client callback needed when creating datagram.\n"));
      return VMCI_ERROR_INVALID_ARGS;
   }

   if (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
      return VMCI_ERROR_INVALID_ARGS;
   }

   return DatagramCreateHnd(resourceID, flags, privFlags, recvCB, clientData,
                            outHandle);
}
コード例 #3
0
int
VMCI_HostInit(void)
{
   int result;

   /*
    * In theory, it is unsafe to pass an eventHnd of -1 to platforms which use
    * it (VMKernel/Windows/Mac OS at the time of this writing). In practice we
    * are fine though, because the event is never used in the case of the host
    * context.
    */
   result = VMCIContext_InitContext(VMCI_HOST_CONTEXT_ID,
                                    VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
                                    -1, VMCI_VERSION, NULL, &hostContext);
   if (result < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to initialize VMCIContext (result=%d).\n",
                    result));
      goto errorExit;
   }

   result = VMCIQPBroker_Init();
   if (result < VMCI_SUCCESS) {
      goto hostContextExit;
   }

   VMCI_DEBUG_LOG(0, (LGPFX"host components initialized.\n"));
   return VMCI_SUCCESS;

hostContextExit:
   VMCIContext_ReleaseContext(hostContext);
errorExit:
   return result;
}
コード例 #4
0
static int
VPageChannelSendConnectionMessage(VPageChannel *channel) // IN
{
   VPageChannelGuestConnectMessage message;

   ASSERT(channel);

   channel->state = VPCState_Connecting;

   memset(&message, 0, sizeof message);
   message.dgHandle = channel->dgHandle;
   message.qpHandle = channel->qpHandle;
   message.produceQSize = channel->produceQSize;
   message.consumeQSize = channel->consumeQSize;
   message.doorbellHandle = channel->doorbellHandle;

   VMCI_DEBUG_LOG(10,
                  (LGPFX"Sending guest connect (channel=%p) "
                   "(qp handle=0x%x:0x%x).\n",
                   channel,
                   channel->qpHandle.context,
                   channel->qpHandle.resource));

   return VPageChannelSendControl(channel, VPCPacket_GuestConnect,
                                  (char *)&message, sizeof message, 0, NULL);
}
コード例 #5
0
int
vmci_datagram_destroy_handle(VMCIHandle handle) // IN
{
   DatagramEntry *entry;
   VMCIResource *resource = VMCIResource_Get(handle,
                                             VMCI_RESOURCE_TYPE_DATAGRAM);
   if (resource == NULL) {
      VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy datagram (handle=0x%x:0x%x).\n",
                         handle.context, handle.resource));
      return VMCI_ERROR_NOT_FOUND;
   }
   entry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);

   VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DATAGRAM);

   /*
    * We now wait on the destroyEvent and release the reference we got
    * above.
    */
   VMCI_WaitOnEvent(&entry->destroyEvent, DatagramReleaseCB, entry);

   /*
    * We know that we are now the only reference to the above entry so
     * can safely free it.
     */
   VMCI_DestroyEvent(&entry->destroyEvent);
   VMCI_FreeKernelMem(entry, sizeof *entry);

   return VMCI_SUCCESS;
}
コード例 #6
0
int
VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg) // IN
{
#if defined(VMKERNEL)
   VMCI_WARNING((LGPFX"Cannot dispatch within guest in VMKERNEL.\n"));
   return VMCI_ERROR_DST_UNREACHABLE;
#else // VMKERNEL
   int retval;
   VMCIResource *resource;
   DatagramEntry *dstEntry;

   ASSERT(dg);

   resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM);
   if (NULL == resource) {
      VMCI_DEBUG_LOG(4, (LGPFX"destination (handle=0x%x:0x%x) doesn't exist.\n",
                         dg->dst.context, dg->dst.resource));
      return VMCI_ERROR_NO_HANDLE;
   }

   dstEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
   if (dstEntry->runDelayed) {
      VMCIDelayedDatagramInfo *dgInfo;

      dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)dg->payloadSize,
                                   (VMCI_MEMORY_ATOMIC | VMCI_MEMORY_NONPAGED));
      if (NULL == dgInfo) {
         VMCIResource_Release(resource);
         retval = VMCI_ERROR_NO_MEM;
         goto exit;
      }

      dgInfo->inDGHostQueue = FALSE;
      dgInfo->entry = dstEntry;
      memcpy(&dgInfo->msg, dg, VMCI_DG_SIZE(dg));

      retval = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo);
      if (retval < VMCI_SUCCESS) {
         VMCI_WARNING((LGPFX"Failed to schedule delayed work for datagram "
                       "(result=%d).\n", retval));
         VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dg->payloadSize);
         VMCIResource_Release(resource);
         dgInfo = NULL;
         goto exit;
      }
   } else {
      dstEntry->recvCB(dstEntry->clientData, dg);
      VMCIResource_Release(resource);
      retval = VMCI_SUCCESS;
   }

exit:
   return retval;
#endif // VMKERNEL
}
コード例 #7
0
static void
VMCIUtilCidUpdate(VMCIId subID,               // IN:
                  VMCI_EventData *eventData,  // IN:
                  void *clientData)           // IN:
{
   VMCIEventPayload_Context *evPayload = VMCIEventDataPayload(eventData);

   if (subID != ctxUpdateSubID) {
      VMCI_DEBUG_LOG(4, (LGPFX"Invalid subscriber (ID=0x%x).\n", subID));
      return;
   }
   if (eventData == NULL || evPayload->contextID == VMCI_INVALID_ID) {
      VMCI_DEBUG_LOG(4, (LGPFX"Invalid event data.\n"));
      return;
   }
   VMCI_LOG((LGPFX"Updating context from (ID=0x%x) to (ID=0x%x) on event "
             "(type=%d).\n", Atomic_Read(&vmContextID), evPayload->contextID,
             eventData->event));
   Atomic_Write(&vmContextID, evPayload->contextID);
}
コード例 #8
0
int
VMCI_SharedInit(void)
{
   int result;

   result = VMCIResource_Init();
   if (result < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to initialize VMCIResource (result=%d).\n",
                    result));
      goto errorExit;
   }

   result = VMCIContext_Init();
   if (result < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to initialize VMCIContext (result=%d).\n",
                    result));
      goto resourceExit;
   }

   result = VMCIDatagram_Init();
   if (result < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to initialize VMCIDatagram (result=%d).\n",
                    result));
      goto contextExit;
   }

   result = VMCIEvent_Init();
   if (result < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to initialize VMCIEvent (result=%d).\n",
                    result));
      goto datagramExit;
   }

   result = VMCIDoorbell_Init();
   if (result < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to initialize VMCIDoorbell (result=%d).\n",
                    result));
      goto eventExit;
   }

   VMCI_DEBUG_LOG(0, (LGPFX"shared components initialized.\n"));
   return VMCI_SUCCESS;

eventExit:
   VMCIEvent_Exit();
datagramExit:
   VMCIDatagram_Exit();
contextExit:
   VMCIContext_Exit();
resourceExit:
   VMCIResource_Exit();
errorExit:
   return result;
}
コード例 #9
0
int
VMCIDatagram_Dispatch(VMCIId contextID,
                      VMCIDatagram *dg,
                      Bool fromGuest)
{
   int retval;
   VMCIRoute route;

   ASSERT(dg);
   ASSERT_ON_COMPILE(sizeof(VMCIDatagram) == 24);

   if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
      VMCI_DEBUG_LOG(4, (LGPFX"Payload (size=%"FMT64"u bytes) too big to "
                         "send.\n", dg->payloadSize));
      return VMCI_ERROR_INVALID_ARGS;
   }

   retval = VMCI_Route(&dg->src, &dg->dst, fromGuest, &route);
   if (retval < VMCI_SUCCESS) {
      VMCI_DEBUG_LOG(4, (LGPFX"Failed to route datagram (src=0x%x, dst=0x%x, "
                         "err=%d)\n.", dg->src.context, dg->dst.context,
                         retval));
      return retval;
   }

   if (VMCI_ROUTE_AS_HOST == route) {
      if (VMCI_INVALID_ID == contextID) {
         contextID = VMCI_HOST_CONTEXT_ID;
      }
      return VMCIDatagramDispatchAsHost(contextID, dg);
   }

   if (VMCI_ROUTE_AS_GUEST == route) {
      return VMCIDatagramDispatchAsGuest(dg);
   }

   VMCI_WARNING((LGPFX"Unknown route (%d) for datagram.\n", route));
   return VMCI_ERROR_DST_UNREACHABLE;
}
コード例 #10
0
Bool
VMCI_CheckHostCapabilities(void)
{
   Bool result = VMCIEvent_CheckHostCapabilities();
   result &= VMCIDatagram_CheckHostCapabilities();
   result &= VMCIUtilCheckHostCapabilities();

   if (!result) {
      /* If it failed, then make sure this goes to the system event log. */
      VMCI_WARNING((LGPFX"Host capability checked failed.\n"));
   } else {
      VMCI_DEBUG_LOG(0, (LGPFX"Host capability check passed.\n"));
   }

   return result;
}
コード例 #11
0
void
VPageChannel_Destroy(VPageChannel *channel) // IN/OUT
{
   ASSERT(channel);

   VPageChannelDestroyQueuePair(channel);

   if (!VMCI_HANDLE_INVALID(channel->doorbellHandle)) {
      vmci_doorbell_destroy(channel->doorbellHandle);
   }

   if (!VMCI_HANDLE_INVALID(channel->dgHandle)) {
      vmci_datagram_destroy_handle(channel->dgHandle);
   }

   channel->state = VPCState_Free;
   VMCI_FreeKernelMem(channel, sizeof *channel);

   VMCI_DEBUG_LOG(10,
                  (LGPFX"Destroyed (channel=%p).\n",
                   channel));
}
コード例 #12
0
static void
VPageChannelPeerDetachCB(VMCIId subId,             // IN
                         VMCI_EventData *eData,    // IN
                         void *clientData)         // IN
{
   VPageChannel *channel;
   VMCIEventPayload_QP *ePayload;

   ASSERT(eData);
   ASSERT(clientData);

   channel = (VPageChannel *)clientData;
   ePayload = VMCIEventDataPayload(eData);

   if (VMCI_HANDLE_EQUAL(channel->qpHandle, ePayload->handle)) {
      VMCI_DEBUG_LOG(10,
                     (LGPFX"Peer detached (channel=%p) "
                      "(qp handle=0x%x:0x%x).\n",
                      channel,
                      ePayload->handle.context,
                      ePayload->handle.resource));
      channel->state = VPCState_Disconnected;
   }
}
コード例 #13
0
int
VPageChannel_CreateInVM(VPageChannel **channel,              // IN/OUT
                        VMCIId resourceId,                   // IN
                        VMCIId peerResourceId,               // IN
                        uint64 produceQSize,                 // IN
                        uint64 consumeQSize,                 // IN
                        uint32 channelFlags,                 // IN
                        VPageChannelRecvCB recvCB,           // IN
                        void *clientRecvData,                // IN
                        VPageChannelAllocElemFn elemAllocFn, // IN
                        void *allocClientData,               // IN
                        VPageChannelFreeElemFn elemFreeFn,   // IN
                        void *freeClientData,                // IN
                        int defaultRecvBuffers,              // IN
                        int maxRecvBuffers)                  // IN
{
   int retval;
   int flags;
   VPageChannel *pageChannel;

   ASSERT(channel);
   ASSERT(VMCI_INVALID_ID != resourceId);
   ASSERT(VMCI_INVALID_ID != peerResourceId);
   ASSERT(recvCB);

   if (channelFlags & ~(VPAGECHANNEL_FLAGS_ALL)) {
      VMCI_WARNING((LGPFX"Invalid argument (flags=0x%x).\n",
                    channelFlags));
      return VMCI_ERROR_INVALID_ARGS;
   }

   pageChannel =
      VMCI_AllocKernelMem(sizeof *pageChannel, VMCI_MEMORY_NONPAGED);
   if (!pageChannel) {
      VMCI_WARNING((LGPFX"Failed to allocate channel memory.\n"));
      return VMCI_ERROR_NO_MEM;
   }

   /*
    * XXX, we should support a default internal allocation function.
    */

   memset(pageChannel, 0, sizeof *pageChannel);
   pageChannel->state = VPCState_Unconnected;
   pageChannel->dgHandle = VMCI_INVALID_HANDLE;
   pageChannel->attachSubId = VMCI_INVALID_ID;
   pageChannel->detachSubId = VMCI_INVALID_ID;
   pageChannel->qpHandle = VMCI_INVALID_HANDLE;
   pageChannel->qpair = NULL;
   pageChannel->doorbellHandle = VMCI_INVALID_HANDLE;
   pageChannel->peerDoorbellHandle = VMCI_INVALID_HANDLE;
   pageChannel->flags = channelFlags;
   pageChannel->recvCB = recvCB;
   pageChannel->clientRecvData = clientRecvData;
   pageChannel->elemAllocFn = elemAllocFn;
   pageChannel->allocClientData = allocClientData;
   pageChannel->elemFreeFn = elemFreeFn;
   pageChannel->freeClientData = freeClientData;
   pageChannel->resourceId = resourceId;
   pageChannel->peerDgHandle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID,
                                                  peerResourceId);
   Atomic_Write32(&pageChannel->curRecvBufs, 0);
   pageChannel->recvBufsTarget = defaultRecvBuffers;
   pageChannel->defaultRecvBufs = defaultRecvBuffers;
   pageChannel->maxRecvBufs = maxRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
   pageChannel->produceQSize = produceQSize;
   pageChannel->consumeQSize = consumeQSize;

   /*
    * Create a datagram handle over which we will connection handshake packets
    * (once the queuepair is created we can send packets over that instead).
    * This handle has a delayed callback regardless of the channel flags,
    * because we may have to create a queuepair inside the callback.
    */

   flags = VMCI_FLAG_DG_DELAYED_CB;
   retval = vmci_datagram_create_handle(resourceId, flags,
                                        VPageChannelDgRecvFunc, pageChannel,
                                        &pageChannel->dgHandle);
   if (retval < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to create datagram handle "
                    "(channel=%p) (err=%d).\n",
                    channel,
                    retval));
      goto error;
   }

   VMCI_DEBUG_LOG(10,
                  (LGPFX"Created datagram (channel=%p) "
                   "(handle=0x%x:0x%x).\n",
                   channel,
                   pageChannel->dgHandle.context,
                   pageChannel->dgHandle.resource));

   /*
    * Create a doorbell handle.  This is used by the peer to signal the
    * arrival of packets in the queuepair.  This handle has a delayed
    * callback depending on the channel flags.
    */

   flags = channelFlags & VPAGECHANNEL_FLAGS_RECV_DELAYED ?
      VMCI_FLAG_DELAYED_CB : 0;
   retval = vmci_doorbell_create(&pageChannel->doorbellHandle,
                                 flags, VMCI_PRIVILEGE_FLAG_RESTRICTED,
                                 VPageChannelDoorbellCallback, pageChannel);
   if (retval < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to create doorbell "
                    "(channel=%p) (err=%d).\n",
                    channel,
                    retval));
      goto error;
   }

   VMCI_DEBUG_LOG(10,
                  (LGPFX"Created doorbell (channel=%p) "
                   "(handle=0x%x:0x%x).\n",
                   channel,
                   pageChannel->doorbellHandle.context,
                   pageChannel->doorbellHandle.resource));

   /*
    * Now create the queuepair, over which we can pass data packets.
    */

   retval = VPageChannelCreateQueuePair(pageChannel);
   if (retval < VMCI_SUCCESS) {
      goto error;
   }

   /*
    * Set the receiving buffers before sending the connection message to
    * avoid a race when the connection is made, but there is no receiving
    * buffer yet.
    */

   if (defaultRecvBuffers) {
      int numElems = defaultRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
      if (0 == VPageChannelAddRecvBuffers(pageChannel, numElems, TRUE)) {
         /*
          * AddRecvBuffers() returns the number of buffers actually added.  If
          * we failed to add any at all, then fail.
          */

         retval = VMCI_ERROR_NO_MEM;
         goto error;
      }
   }

   retval = VPageChannelSendConnectionMessage(pageChannel);
   if (retval < VMCI_SUCCESS) {
      goto error;
   }

   VMCI_DEBUG_LOG(10,
                  (LGPFX"Created (channel=%p) (handle=0x%x:0x%x).\n",
                   pageChannel,
                   pageChannel->dgHandle.context,
                   pageChannel->dgHandle.resource));

   *channel = pageChannel;

   return retval;

 error:
   VPageChannel_Destroy(pageChannel);
   return retval;
}
コード例 #14
0
static int
VPageChannelSendPacket(VPageChannel *channel,         // IN
                       VPageChannelPacket *packet,    // IN
                       Bool needsLock,                // IN
                       Bool signalPending)            // IN
{
   int retval;
   ssize_t totalSize, sentSize;
   ssize_t freeSpace;
   unsigned long flags;

   ASSERT(channel);

   if (VPCState_Connected != channel->state) {
      VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
                    channel));
      return VMCI_ERROR_DST_UNREACHABLE;
   }

   ASSERT(packet);

   totalSize = sizeof(VPageChannelPacket) + packet->msgLen +
      packet->numElems * sizeof(VPageChannelElem);

   if (needsLock) {
      VPageChannelAcquireSendLock(channel, &flags);
   } else {
      flags = 0; /* Silence compiler. */
   }

   freeSpace = vmci_qpair_produce_free_space(channel->qpair);
   if (freeSpace < totalSize) {
      VMCI_WARNING((LGPFX"No free space in queuepair (channel=%p) "
                    "(required=%"FMTSZ"d) (actual=%"FMTSZ"d).\n",
                    channel,
                    totalSize,
                    freeSpace));
      retval = VMCI_ERROR_NO_MEM;
      goto exit;
   }

   sentSize = vmci_qpair_enqueue(channel->qpair, packet, totalSize, 0);

   if (!signalPending) {
      if (sentSize == vmci_qpair_produce_buf_ready(channel->qpair)) {
         retval = VPageChannelSignal(channel);
         if (retval < VMCI_SUCCESS) {
            goto exit;
         }
      }
   }

   if (sentSize < totalSize) {
      /*
       * XXX, deal with partial sending.
       */

      VMCI_WARNING((LGPFX"No free space in queuepair (channel=%p) "
                    "(required=%"FMTSZ"d) (actual=%"FMTSZ"d).\n",
                    channel,
                    totalSize,
                    sentSize));
      retval = VMCI_ERROR_NO_MEM;
      goto exit;
   }

   VMCI_DEBUG_LOG(10,
                  (LGPFX"Sent packet (channel=%p) (size=%"FMTSZ"d).\n",
                   channel,
                   sentSize));

   retval = VMCI_SUCCESS;

exit:
   if (needsLock) {
      VPageChannelReleaseSendLock(channel, flags);
   }
   return retval;
}
コード例 #15
0
static int
VMCIDatagramDispatchAsHost(VMCIId contextID,  // IN:
                           VMCIDatagram *dg)  // IN:
{
   int retval;
   size_t dgSize;
   VMCIPrivilegeFlags srcPrivFlags;

   ASSERT(dg);
   ASSERT(VMCI_HostPersonalityActive());

   dgSize = VMCI_DG_SIZE(dg);

   if (contextID == VMCI_HOST_CONTEXT_ID &&
       dg->dst.context == VMCI_HYPERVISOR_CONTEXT_ID) {
      VMCI_DEBUG_LOG(4, (LGPFX"Host cannot talk to hypervisor\n"));
      return VMCI_ERROR_DST_UNREACHABLE;
   }

   ASSERT(dg->dst.context != VMCI_HYPERVISOR_CONTEXT_ID);

   /* Chatty. */
   // VMCI_DEBUG_LOG(10, (LGPFX"Sending from (handle=0x%x:0x%x) to "
   //                     "(handle=0x%x:0x%x) (size=%u bytes).\n",
   //                     dg->src.context, dg->src.resource,
   //                     dg->dst.context, dg->dst.resource, (uint32)dgSize));

   /*
    * Check that source handle matches sending context.
    */
   if (dg->src.context != contextID) {
      VMCI_DEBUG_LOG(4, (LGPFX"Sender context (ID=0x%x) is not owner of src "
                         "datagram entry (handle=0x%x:0x%x).\n",
                         contextID, dg->src.context, dg->src.resource));
      return VMCI_ERROR_NO_ACCESS;
   }

   /*
    * Get hold of privileges of sending endpoint.
    */

   retval = VMCIDatagramGetPrivFlagsInt(contextID, dg->src, &srcPrivFlags);
   if (retval != VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Couldn't get privileges (handle=0x%x:0x%x).\n",
                    dg->src.context, dg->src.resource));
      return retval;
   }

   /* Determine if we should route to host or guest destination. */
   if (dg->dst.context == VMCI_HOST_CONTEXT_ID) {
      /* Route to host datagram entry. */
      DatagramEntry *dstEntry;
      VMCIResource *resource;

      if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
          dg->dst.resource == VMCI_EVENT_HANDLER) {
         return VMCIEvent_Dispatch(dg);
      }

      resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM);
      if (resource == NULL) {
         VMCI_DEBUG_LOG(4, (LGPFX"Sending to invalid destination "
                            "(handle=0x%x:0x%x).\n",
                            dg->dst.context, dg->dst.resource));
         return VMCI_ERROR_INVALID_RESOURCE;
      }
      dstEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
      if (VMCIDenyInteraction(srcPrivFlags, dstEntry->privFlags)) {
         VMCIResource_Release(resource);
         return VMCI_ERROR_NO_ACCESS;
      }
      ASSERT(dstEntry->recvCB);

      /*
       * If a VMCI datagram destined for the host is also sent by the
       * host, we always run it delayed. This ensures that no locks
       * are held when the datagram callback runs.
       */

      if (dstEntry->runDelayed ||
          (dg->src.context == VMCI_HOST_CONTEXT_ID &&
           VMCI_CanScheduleDelayedWork())) {
         VMCIDelayedDatagramInfo *dgInfo;

         if (Atomic_FetchAndAdd(&delayedDGHostQueueSize, 1) ==
             VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE) {
            Atomic_Dec(&delayedDGHostQueueSize);
            VMCIResource_Release(resource);
            return VMCI_ERROR_NO_MEM;
         }

         dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)dg->payloadSize,
                                      (VMCI_MEMORY_ATOMIC |
                                       VMCI_MEMORY_NONPAGED));
         if (NULL == dgInfo) {
            Atomic_Dec(&delayedDGHostQueueSize);
            VMCIResource_Release(resource);
            return VMCI_ERROR_NO_MEM;
         }

         dgInfo->inDGHostQueue = TRUE;
         dgInfo->entry = dstEntry;
         memcpy(&dgInfo->msg, dg, dgSize);

         retval = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo);
         if (retval < VMCI_SUCCESS) {
            VMCI_WARNING((LGPFX"Failed to schedule delayed work for datagram "
                          "(result=%d).\n", retval));
            VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dg->payloadSize);
            VMCIResource_Release(resource);
            Atomic_Dec(&delayedDGHostQueueSize);
            return retval;
         }
      } else {
         retval = dstEntry->recvCB(dstEntry->clientData, dg);
         VMCIResource_Release(resource);
         if (retval < VMCI_SUCCESS) {
            return retval;
         }
      }
   } else {
      /*
       * Route to destination VM context.
       */

      VMCIDatagram *newDG;

      if (contextID != dg->dst.context) {
         if (VMCIDenyInteraction(srcPrivFlags,
                              vmci_context_get_priv_flags(dg->dst.context))) {
            VMCI_DEBUG_LOG(4, (LGPFX"Interaction denied (%X/%X - %X/%X)\n",
                           contextID, srcPrivFlags,
                           dg->dst.context,
                           vmci_context_get_priv_flags(dg->dst.context)));
            return VMCI_ERROR_NO_ACCESS;
         } else if (VMCI_CONTEXT_IS_VM(contextID)) {
            /*
             * If the sending context is a VM, it cannot reach another VM.
             */

            if (!vmkernel) {
               VMCI_DEBUG_LOG(4, (LGPFX"Datagram communication between VMs not "
                                  "supported (src=0x%x, dst=0x%x).\n",
                                  contextID, dg->dst.context));
               return VMCI_ERROR_DST_UNREACHABLE;
            }
         }
      }

      /* We make a copy to enqueue. */
      newDG = VMCI_AllocKernelMem(dgSize, VMCI_MEMORY_NORMAL);
      if (newDG == NULL) {
         VMCI_DEBUG_LOG(4, (LGPFX"No memory for datagram\n"));
         return VMCI_ERROR_NO_MEM;
      }
      memcpy(newDG, dg, dgSize);
      retval = VMCIContext_EnqueueDatagram(dg->dst.context, newDG);
      if (retval < VMCI_SUCCESS) {
         VMCI_FreeKernelMem(newDG, dgSize);
         VMCI_DEBUG_LOG(4, (LGPFX"Enqueue failed\n"));
         return retval;
      }
   }

   /* The datagram is freed when the context reads it. */

   /* Chatty. */
   // VMCI_DEBUG_LOG(10, (LGPFX"Sent datagram (size=%u bytes).\n",
   //                     (uint32)dgSize));

   /*
    * We currently truncate the size to signed 32 bits. This doesn't
    * matter for this handler as it only support 4Kb messages.
    */

   return (int)dgSize;
}
コード例 #16
0
static int
VPageChannelRecvPacket(VPageChannel *channel,         // IN
                       VPageChannelPacket *packet)    // IN
{
   int curRecvBufs;
   int recvBufsTarget;

   ASSERT(channel);
   ASSERT(packet);

   if (packet->type != VPCPacket_Data &&
       packet->type != VPCPacket_Completion_Notify &&
       packet->type != VPCPacket_RequestBuffer &&
       packet->type != VPCPacket_HyperConnect &&
       packet->type != VPCPacket_HyperDisconnect) {
      VMCI_WARNING((LGPFX"Received invalid packet (channel=%p) "
                    "(type=%d).\n",
                    channel,
                    packet->type));
      return VMCI_ERROR_INVALID_ARGS;
   }

   VMCI_DEBUG_LOG(10,
                  (LGPFX"Received packet (channel=%p) (type=%d) "
                   "(elems=%d).\n",
                   channel,
                   packet->type,
                   packet->numElems));

   if (packet->type == VPCPacket_HyperConnect) {
      VPageChannelHyperConnectMessage *message;

      if (packet->msgLen < sizeof *message) {
         VMCI_WARNING((LGPFX"Received invalid hypervisor connection message "
                       "(channel=%p) (size=%u).\n",
                       channel,
                       packet->msgLen));
         return VMCI_ERROR_INVALID_ARGS;
      }

      message = (VPageChannelHyperConnectMessage *)
         VPAGECHANNEL_PACKET_MESSAGE(packet);
      channel->peerDoorbellHandle = message->doorbellHandle;

      VMCI_DEBUG_LOG(10,
                     (LGPFX"Connected to peer (channel=%p) "
                      "(db handle=0x%x:0x%x).\n",
                      channel,
                      channel->peerDoorbellHandle.context,
                      channel->peerDoorbellHandle.resource));

      return VMCI_SUCCESS;
   }

   recvBufsTarget = channel->recvBufsTarget;

   switch (packet->type) {
   case VPCPacket_RequestBuffer:
      /*
       * Increase the number of receive buffers by channel->defaultRecvBufs
       * if the hypervisor requests it.
       */

      VMCI_DEBUG_LOG(10,
                     (LGPFX"Requested more buffers (channel=%p) "
                      "(cur=%d) (target=%d) (max=%d).\n",
                      channel,
                      Atomic_Read32(&channel->curRecvBufs),
                      channel->recvBufsTarget,
                      channel->maxRecvBufs));

      if (channel->recvBufsTarget < channel->maxRecvBufs) {
         recvBufsTarget = channel->recvBufsTarget + channel->defaultRecvBufs;
      }
      break;

   case VPCPacket_Data:
      channel->recvCB(channel->clientRecvData, packet);
      Atomic_Sub32(&channel->curRecvBufs, packet->numElems);
      ASSERT(Atomic_Read32(&channel->curRecvBufs) > 0);
      break;

   case VPCPacket_Completion_Notify:
      channel->recvCB(channel->clientRecvData, packet);
      break;

   case VPCPacket_HyperDisconnect:
      VMCI_DEBUG_LOG(10,
                     (LGPFX"Hypervisor requested disconnection "
                      "(channel=%p) (numElems=%d).\n",
                      channel,
                      packet->numElems));
      if (packet->numElems > 0) {
         channel->elemFreeFn(channel->freeClientData,
                             VPAGECHANNEL_PACKET_ELEMS(packet),
                             packet->numElems);
      }
      (void)VPageChannelSendControl(channel, VPCPacket_GuestDisconnect,
                                    NULL, 0, 0, NULL);
      if (channel->state < VPCState_Disconnecting) {
         channel->state = VPCState_Disconnecting;
      }
      return VMCI_SUCCESS;

   default:
      ASSERT_NOT_IMPLEMENTED(FALSE);
      break;
   }

   /*
    * Set more receive buffers if it is below the threshold.  We bump it up
    * here even when not requested to do so.  This is to account for buffers
    * being in-flight, i.e., in packets that have not yet been processed by
    * the other side.  When we increase here, we also tack on extra threshold,
    * in the hope that we won't hit this again.
    */

   curRecvBufs = Atomic_Read32(&channel->curRecvBufs);
   if (curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) {
      int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD - curRecvBufs;

      (void)VPageChannelAddRecvBuffers(channel, numElems, FALSE);
      channel->recvBufsTarget = recvBufsTarget;
   }

   return VMCI_SUCCESS;
}
コード例 #17
0
static int
VPageChannelCreateQueuePair(VPageChannel *channel) // IN/OUT
{
   int err;
   uint32 flags;

   ASSERT(channel);
   ASSERT(VMCI_HANDLE_INVALID(channel->qpHandle));
   ASSERT(NULL == channel->qpair);
   ASSERT(VMCI_INVALID_ID == channel->detachSubId);
   ASSERT(VMCI_INVALID_ID == channel->attachSubId);

   if (channel->flags & VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC ||
       !(channel->flags & VPAGECHANNEL_FLAGS_RECV_DELAYED)) {
      channel->useSpinLock = TRUE;
      spin_lock_init(&channel->qpSendLock);
      spin_lock_init(&channel->qpRecvLock);
   } else {
      sema_init(&channel->qpSendMutex, 1);
      sema_init(&channel->qpRecvMutex, 1);
   }

   err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_ATTACH,
#if !defined(linux) || defined(VMKERNEL)
                              VMCI_FLAG_EVENT_NONE,
#endif // !linux || VMKERNEL
                              VPageChannelPeerAttachCB,
                              channel, &channel->attachSubId);
   if (err < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to subscribe to attach event "
                    "(channel=%p) (err=%d).\n",
                    channel,
                    err));
      goto error;
   }

   err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH,
#if !defined(linux) || defined(VMKERNEL)
                              VMCI_FLAG_EVENT_NONE,
#endif // !linux || VMKERNEL
                              VPageChannelPeerDetachCB,
                              channel, &channel->detachSubId);
   if (err < VMCI_SUCCESS) {
      VMCI_WARNING((LGPFX"Failed to subscribe to detach event "
                    "(channel=%p) (err=%d).\n",
                    channel,
                    err));
      goto error;
   }

   if (channel->useSpinLock) {
      flags = VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED;
   } else {
      flags = 0;
   }
   err = vmci_qpair_alloc(&channel->qpair, &channel->qpHandle,
                          channel->produceQSize, channel->consumeQSize,
                          VMCI_HOST_CONTEXT_ID, flags,
                          VMCI_NO_PRIVILEGE_FLAGS);
   if (err < 0) {
      VMCI_WARNING((LGPFX"Could not create queue pair (err=%d).\n",
                    err));
      goto error;
   }

   VMCI_DEBUG_LOG(10,
                  (LGPFX"Allocated queuepair (channel=%p) "
                   "(qp handle=0x%x:0x%x) "
                   "(produce=%"FMT64"u) (consume=%"FMT64"u).\n",
                   channel,
                   channel->qpHandle.context,
                   channel->qpHandle.resource,
                   channel->produceQSize,
                   channel->consumeQSize));

   return VMCI_SUCCESS;

error:
   VPageChannelDestroyQueuePair(channel);
   return err;
}
コード例 #18
0
void
VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle,  // IN
                           VMCIIoPort dgInPort,    // IN
                           uint8 *dgInBuffer,      // IN
                           size_t dgInBufferSize)  // IN
{
   VMCIDatagram *dg;
   size_t currentDgInBufferSize = PAGE_SIZE;
   size_t remainingBytes;

   ASSERT(dgInBufferSize >= PAGE_SIZE);

   VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
   dg = (VMCIDatagram *)dgInBuffer;
   remainingBytes = currentDgInBufferSize;

   while (dg->dst.resource != VMCI_INVALID_ID || remainingBytes > PAGE_SIZE) {
      unsigned dgInSize;

      /*
       * When the input buffer spans multiple pages, a datagram can
       * start on any page boundary in the buffer.
       */

      if (dg->dst.resource == VMCI_INVALID_ID) {
         ASSERT(remainingBytes > PAGE_SIZE);
         dg = (VMCIDatagram *)ROUNDUP((uintptr_t)dg + 1, PAGE_SIZE);
         ASSERT((uint8 *)dg < dgInBuffer + currentDgInBufferSize);
         remainingBytes = (size_t)(dgInBuffer + currentDgInBufferSize - (uint8 *)dg);
         continue;
      }

      dgInSize = VMCI_DG_SIZE_ALIGNED(dg);

      if (dgInSize <= dgInBufferSize) {
         int result;

         /*
          * If the remaining bytes in the datagram buffer doesn't
          * contain the complete datagram, we first make sure we have
          * enough room for it and then we read the reminder of the
          * datagram and possibly any following datagrams.
          */

         if (dgInSize > remainingBytes) {

            if (remainingBytes != currentDgInBufferSize) {

               /*
                * We move the partial datagram to the front and read
                * the reminder of the datagram and possibly following
                * calls into the following bytes.
                */

               memmove(dgInBuffer, dgInBuffer + currentDgInBufferSize - remainingBytes,
                       remainingBytes);

               dg = (VMCIDatagram *)dgInBuffer;
            }

            if (currentDgInBufferSize != dgInBufferSize) {
               currentDgInBufferSize = dgInBufferSize;
            }

            VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer + remainingBytes,
                               currentDgInBufferSize - remainingBytes);
         }

         /* We special case event datagrams from the hypervisor. */
         if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
             dg->dst.resource == VMCI_EVENT_HANDLER) {
            result = VMCIEvent_Dispatch(dg);
         } else {
            result = VMCIDatagram_InvokeGuestHandler(dg);
         }
         if (result < VMCI_SUCCESS) {
            VMCI_DEBUG_LOG(4, (LGPFX"Datagram with resource (ID=0x%x) failed "
                               "(err=%d).\n", dg->dst.resource, result));
         }

         /* On to the next datagram. */
         dg = (VMCIDatagram *)((uint8 *)dg + dgInSize);
      } else {
         size_t bytesToSkip;

         /*
          * Datagram doesn't fit in datagram buffer of maximal size. We drop it.
          */

         VMCI_DEBUG_LOG(4, (LGPFX"Failed to receive datagram (size=%u bytes).\n",
                            dgInSize));

         bytesToSkip = dgInSize - remainingBytes;
         if (currentDgInBufferSize != dgInBufferSize) {
            currentDgInBufferSize = dgInBufferSize;
         }
         for (;;) {
            VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
            if (bytesToSkip <= currentDgInBufferSize) {
               break;
            }
            bytesToSkip -= currentDgInBufferSize;
         }
         dg = (VMCIDatagram *)(dgInBuffer + bytesToSkip);
      }

      remainingBytes = (size_t) (dgInBuffer + currentDgInBufferSize - (uint8 *)dg);

      if (remainingBytes < VMCI_DG_HEADERSIZE) {
         /* Get the next batch of datagrams. */

         VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
         dg = (VMCIDatagram *)dgInBuffer;
         remainingBytes = currentDgInBufferSize;
      }
   }
}