608
683
return VMCIQPBrokerAllocInt(handle, peer, flags, privFlags,
609
684
produceSize, consumeSize,
610
pageStore, context, NULL);
615
*-----------------------------------------------------------------------------
617
* VMCIQPBrokerAllocInt --
619
* QueuePair_Alloc for use when setting up queue pair endpoints
620
* on the host. Like QueuePair_Alloc, but returns a pointer to
621
* the QPBrokerEntry on success.
624
* Success or failure.
627
* Memory may be allocated.
629
*-----------------------------------------------------------------------------
633
VMCIQPBrokerAllocInt(VMCIHandle handle, // IN
636
VMCIPrivilegeFlags privFlags, // IN
637
uint64 produceSize, // IN
638
uint64 consumeSize, // IN
639
QueuePairPageStore *pageStore, // IN/OUT
640
VMCIContext *context, // IN: Caller
641
QPBrokerEntry **ent) // OUT
643
QPBrokerEntry *entry = NULL;
645
const VMCIId contextId = VMCIContext_GetId(context);
646
Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
648
if (VMCI_HANDLE_INVALID(handle) ||
649
(flags & ~VMCI_QP_ALL_FLAGS) ||
650
(isLocal && (!vmkernel || contextId != VMCI_HOST_CONTEXT_ID ||
651
handle.context != contextId)) ||
652
!(produceSize || consumeSize) ||
653
!context || contextId == VMCI_INVALID_ID ||
654
handle.context == VMCI_INVALID_ID) {
655
return VMCI_ERROR_INVALID_ARGS;
659
if (!pageStore || (!pageStore->shared && !isLocal)) {
660
return VMCI_ERROR_INVALID_ARGS;
664
* On hosted, pageStore can be NULL if the caller doesn't want the
667
if (pageStore && !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore)) {
668
return VMCI_ERROR_INVALID_ARGS;
674
* In the initial argument check, we ensure that non-vmkernel hosts
675
* are not allowed to create local queue pairs.
678
ASSERT(vmkernel || !isLocal);
680
if (!isLocal && VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
681
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) already attached to queue pair "
682
"(handle=0x%x:0x%x).\n",
683
contextId, handle.context, handle.resource));
684
result = VMCI_ERROR_ALREADY_EXISTS;
688
entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
689
if (!entry) { /* Create case. */
691
* Do not create if the caller asked not to.
694
if (flags & VMCI_QPFLAG_ATTACH_ONLY) {
695
result = VMCI_ERROR_NOT_FOUND;
700
* Creator's context ID should match handle's context ID or the creator
701
* must allow the context in handle's context ID as the "peer".
704
if (handle.context != contextId && handle.context != peer) {
705
result = VMCI_ERROR_NO_ACCESS;
710
* Check if we should allow this QueuePair connection.
713
if (QueuePairDenyConnection(contextId, peer)) {
714
result = VMCI_ERROR_NO_ACCESS;
718
entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_ATOMIC);
720
result = VMCI_ERROR_NO_MEM;
724
memset(entry, 0, sizeof *entry);
725
entry->qp.handle = handle;
726
entry->qp.peer = peer;
727
entry->qp.flags = flags;
728
entry->qp.produceSize = produceSize;
729
entry->qp.consumeSize = consumeSize;
730
entry->qp.refCount = 1;
731
entry->createId = contextId;
732
entry->attachId = VMCI_INVALID_ID;
733
entry->pageStoreSet = FALSE;
734
entry->allowAttach = TRUE;
735
entry->requireTrustedAttach =
736
(context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) ? TRUE : FALSE;
737
entry->createdByTrusted =
738
(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED) ? TRUE : FALSE;
742
uint64 numProducePages;
743
uint64 numConsumePages;
745
entry->produceQ = VMCIHost_AllocQueue(produceSize);
746
if (entry->produceQ == NULL) {
747
result = VMCI_ERROR_NO_MEM;
751
entry->consumeQ = VMCIHost_AllocQueue(consumeSize);
752
if (entry->consumeQ == NULL) {
753
result = VMCI_ERROR_NO_MEM;
757
entry->attachInfo = VMCI_AllocKernelMem(sizeof *entry->attachInfo,
759
if (entry->attachInfo == NULL) {
760
result = VMCI_ERROR_NO_MEM;
763
memset(entry->attachInfo, 0, sizeof *entry->attachInfo);
765
VMCI_InitQueueMutex(entry->produceQ, entry->consumeQ);
767
numProducePages = CEILING(produceSize, PAGE_SIZE) + 1;
768
numConsumePages = CEILING(consumeSize, PAGE_SIZE) + 1;
770
entry->attachInfo->numProducePages = numProducePages;
771
entry->attachInfo->numConsumePages = numConsumePages;
773
#endif /* !VMKERNEL */
775
VMCIList_InitEntry(&entry->qp.listItem);
777
QueuePairList_AddEntry(&qpBrokerList, &entry->qp);
778
result = VMCI_SUCCESS_QUEUEPAIR_CREATE;
779
} else { /* Attach case. */
782
* Check for failure conditions.
786
if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
787
contextId != entry->createId) {
788
result = VMCI_ERROR_INVALID_ARGS;
791
} else if (contextId == entry->createId || contextId == entry->attachId) {
792
result = VMCI_ERROR_ALREADY_EXISTS;
797
* QueuePairs are create/destroy entities. There's no notion of
798
* disconnecting/re-attaching, so once a queue pair entry has
799
* been attached to, no further attaches are allowed. This
800
* guards against both re-attaching and attaching to a queue
801
* pair that already has two peers.
804
if (!entry->allowAttach) {
805
result = VMCI_ERROR_UNAVAILABLE;
808
ASSERT(entry->qp.refCount < 2);
809
ASSERT(entry->attachId == VMCI_INVALID_ID);
812
* If we are attaching from a restricted context then the queuepair
813
* must have been created by a trusted endpoint.
816
if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
817
if (!entry->createdByTrusted) {
818
result = VMCI_ERROR_NO_ACCESS;
824
* If we are attaching to a queuepair that was created by a restricted
825
* context then we must be trusted.
828
if (entry->requireTrustedAttach) {
829
if (!(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) {
830
result = VMCI_ERROR_NO_ACCESS;
836
* If the creator specifies VMCI_INVALID_ID in "peer" field, access
837
* control check is not performed.
840
if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != contextId) {
841
result = VMCI_ERROR_NO_ACCESS;
847
* VMKernel doesn't need to check the capabilities because the
848
* whole system is installed as the kernel and matching VMX.
851
if (entry->createId == VMCI_HOST_CONTEXT_ID) {
853
* Do not attach if the caller doesn't support Host Queue Pairs
854
* and a host created this queue pair.
857
if (!VMCIContext_SupportsHostQP(context)) {
858
result = VMCI_ERROR_INVALID_RESOURCE;
861
} else if (contextId == VMCI_HOST_CONTEXT_ID) {
862
VMCIContext *createContext;
866
* Do not attach a host to a user created queue pair if that
867
* user doesn't support host queue pair end points.
870
createContext = VMCIContext_Get(entry->createId);
871
supportsHostQP = VMCIContext_SupportsHostQP(createContext);
872
VMCIContext_Release(createContext);
874
if (!supportsHostQP) {
875
result = VMCI_ERROR_INVALID_RESOURCE;
881
if (entry->qp.produceSize != consumeSize ||
882
entry->qp.consumeSize != produceSize ||
883
entry->qp.flags != (flags & ~VMCI_QPFLAG_ATTACH_ONLY)) {
884
result = VMCI_ERROR_QUEUEPAIR_MISMATCH;
889
* On VMKERNEL (e.g., ESX) we don't allow an attach until
890
* the page store information has been set.
892
* However, on hosted products we support an attach to a
893
* QueuePair that hasn't had its page store established yet. In
894
* fact, that's how a VMX guest will approach a host-created
895
* QueuePair. After the VMX guest does the attach, VMX will
896
* receive the CREATE status code to indicate that it should
897
* create the page files for the QueuePair contents. It will
898
* then issue a separate call down to set the page store. That
899
* will complete the attach case.
901
if (vmkernel && !entry->pageStoreSet) {
902
result = VMCI_ERROR_QUEUEPAIR_NOTSET;
907
* Check if we should allow this QueuePair connection.
910
if (QueuePairDenyConnection(contextId, entry->createId)) {
911
result = VMCI_ERROR_NO_ACCESS;
916
pageStore->store = entry->store.store;
918
if (pageStore && entry->pageStoreSet) {
919
ASSERT(entry->producePageFile[0] && entry->consumePageFile[0]);
920
if (pageStore->producePageFileSize < sizeof entry->consumePageFile) {
921
result = VMCI_ERROR_NO_MEM;
924
if (pageStore->consumePageFileSize < sizeof entry->producePageFile) {
925
result = VMCI_ERROR_NO_MEM;
929
if (pageStore->user) {
930
if (VMCI_CopyToUser(pageStore->producePageFile,
931
entry->consumePageFile,
932
sizeof entry->consumePageFile)) {
933
result = VMCI_ERROR_GENERIC;
937
if (VMCI_CopyToUser(pageStore->consumePageFile,
938
entry->producePageFile,
939
sizeof entry->producePageFile)) {
940
result = VMCI_ERROR_GENERIC;
944
memcpy(VMCIVA64ToPtr(pageStore->producePageFile),
945
entry->consumePageFile,
946
sizeof entry->consumePageFile);
947
memcpy(VMCIVA64ToPtr(pageStore->consumePageFile),
948
entry->producePageFile,
949
sizeof entry->producePageFile);
955
* We only send notification if the other end of the QueuePair
956
* is not the host (in hosted products). In the case that a
957
* host created the QueuePair, we'll send notification when the
958
* guest issues the SetPageStore() (see next function). The
959
* reason is that the host can't use the QueuePair until the
960
* SetPageStore() is complete.
962
* Note that in ESX we always send the notification now
963
* because the host can begin to enqueue immediately.
966
if (vmkernel || entry->createId != VMCI_HOST_CONTEXT_ID) {
967
result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
968
if (result < VMCI_SUCCESS) {
973
entry->attachId = contextId;
974
entry->qp.refCount++;
975
entry->allowAttach = FALSE;
978
* Default response to an attach is _ATTACH. However, if a host
979
* created the QueuePair then we're a guest (because
980
* host-to-host isn't supported). And thus, the guest's VMX
981
* needs to create the backing for the port. So, we send up a
985
if (!vmkernel && entry->createId == VMCI_HOST_CONTEXT_ID) {
986
result = VMCI_SUCCESS_QUEUEPAIR_CREATE;
988
result = VMCI_SUCCESS_QUEUEPAIR_ATTACH;
996
* Cleanup is only necessary on hosted
1000
if (entry->produceQ != NULL) {
1001
VMCI_FreeKernelMem(entry->produceQ, sizeof *entry->produceQ);
1003
if (entry->consumeQ != NULL) {
1004
VMCI_FreeKernelMem(entry->consumeQ, sizeof *entry->consumeQ);
1006
if (entry->attachInfo != NULL) {
1007
VMCI_FreeKernelMem(entry->attachInfo, sizeof *entry->attachInfo);
1009
VMCI_FreeKernelMem(entry, sizeof *entry);
1013
if (result >= VMCI_SUCCESS) {
1020
* When attaching to local queue pairs, the context already has
1021
* an entry tracking the queue pair, so don't add another one.
1024
if (!isLocal || result == VMCI_SUCCESS_QUEUEPAIR_CREATE) {
1025
ASSERT(!VMCIHandleArray_HasEntry(context->queuePairArray, handle));
1026
VMCIHandleArray_AppendEntry(&context->queuePairArray, handle);
1028
ASSERT(VMCIHandleArray_HasEntry(context->queuePairArray, handle));
1036
*-----------------------------------------------------------------------------
1038
* VMCIQPBroker_SetPageStore --
1040
* The creator of a queue pair uses this to regsiter the page
1041
* store for a given queue pair. Assumes that the queue pair
1042
* broker lock is held.
1044
* Note now that sometimes the client that attaches to a queue
1045
* pair will set the page store. This happens on hosted products
1046
* because the host doesn't have a mechanism for creating the
1047
* backing memory for queue contents. ESX does and so this is a
1048
* moot point there. For example, note that in
1049
* VMCIQPBrokerAllocInt() an attaching guest receives the _CREATE
1050
* result code (instead of _ATTACH) on hosted products only, not
1053
* As a result, this routine now always creates the host
1054
* information even if the queue pair is only used by guests. At
1055
* the time a guest creates a queue pair it doesn't know if a
1056
* host or guest will attach. So, the host information always
1057
* has to be created.
1060
* Success or failure.
1065
*-----------------------------------------------------------------------------
1069
VMCIQPBroker_SetPageStore(VMCIHandle handle, // IN
1070
QueuePairPageStore *pageStore, // IN
1071
VMCIContext *context) // IN: Caller
1073
QPBrokerEntry *entry;
1075
const VMCIId contextId = VMCIContext_GetId(context);
1077
QueuePairPageStore normalizedPageStore;
1080
if (VMCI_HANDLE_INVALID(handle) || !pageStore ||
1081
!VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore) ||
1082
!context || contextId == VMCI_INVALID_ID) {
1083
return VMCI_ERROR_INVALID_ARGS;
1086
if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
1087
VMCI_WARNING((LGPFX"Context (ID=0x%x) not attached to queue pair "
1088
"(handle=0x%x:0x%x).\n", contextId, handle.context,
1090
result = VMCI_ERROR_NOT_FOUND;
1096
* If the client supports Host QueuePairs then it must provide the
1097
* UVA's of the mmap()'d files backing the QueuePairs.
1100
if (VMCIContext_SupportsHostQP(context) &&
1101
(pageStore->producePageUVA == 0 ||
1102
pageStore->consumePageUVA == 0)) {
1103
return VMCI_ERROR_INVALID_ARGS;
1107
entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
1109
result = VMCI_ERROR_NOT_FOUND;
1114
* If I'm the owner then I can set the page store.
1116
* Or, if a host created the QueuePair and I'm the attached peer
1117
* then I can set the page store.
1120
if (entry->createId != contextId &&
1121
(entry->createId != VMCI_HOST_CONTEXT_ID ||
1122
entry->attachId != contextId)) {
1123
result = VMCI_ERROR_QUEUEPAIR_NOTOWNER;
1126
if (entry->pageStoreSet) {
1127
result = VMCI_ERROR_UNAVAILABLE;
1131
entry->store = *pageStore;
1134
* Normalize the page store information from the point of view of
1135
* the VMX process with respect to the QueuePair. If VMX has
1136
* attached to a host-created QueuePair and is passing down
1137
* PageStore information then we must switch the produce/consume
1138
* queue information before applying it to the QueuePair.
1140
* In other words, the QueuePair structure (entry->state) is
1141
* oriented with respect to the host that created it. However, VMX
1142
* is sending down information relative to its view of the world
1143
* which is opposite of the host's.
1146
if (entry->createId == contextId) {
1147
normalizedPageStore.producePageFile = pageStore->producePageFile;
1148
normalizedPageStore.consumePageFile = pageStore->consumePageFile;
1149
normalizedPageStore.producePageFileSize = pageStore->producePageFileSize;
1150
normalizedPageStore.consumePageFileSize = pageStore->consumePageFileSize;
1151
normalizedPageStore.producePageUVA = pageStore->producePageUVA;
1152
normalizedPageStore.consumePageUVA = pageStore->consumePageUVA;
1154
normalizedPageStore.producePageFile = pageStore->consumePageFile;
1155
normalizedPageStore.consumePageFile = pageStore->producePageFile;
1156
normalizedPageStore.producePageFileSize = pageStore->consumePageFileSize;
1157
normalizedPageStore.consumePageFileSize = pageStore->producePageFileSize;
1158
normalizedPageStore.producePageUVA = pageStore->consumePageUVA;
1159
normalizedPageStore.consumePageUVA = pageStore->producePageUVA;
1162
if (normalizedPageStore.producePageFileSize > sizeof entry->producePageFile) {
1163
result = VMCI_ERROR_NO_MEM;
1166
if (normalizedPageStore.consumePageFileSize > sizeof entry->consumePageFile) {
1167
result = VMCI_ERROR_NO_MEM;
1170
if (pageStore->user) {
1171
if (VMCI_CopyFromUser(entry->producePageFile,
1172
normalizedPageStore.producePageFile,
1173
(size_t)normalizedPageStore.producePageFileSize)) {
1174
result = VMCI_ERROR_GENERIC;
1178
if (VMCI_CopyFromUser(entry->consumePageFile,
1179
normalizedPageStore.consumePageFile,
1180
(size_t)normalizedPageStore.consumePageFileSize)) {
1181
result = VMCI_ERROR_GENERIC;
1185
memcpy(entry->consumePageFile,
1186
VMCIVA64ToPtr(normalizedPageStore.consumePageFile),
1187
(size_t)normalizedPageStore.consumePageFileSize);
1188
memcpy(entry->producePageFile,
1189
VMCIVA64ToPtr(normalizedPageStore.producePageFile),
1190
(size_t)normalizedPageStore.producePageFileSize);
1194
* Copy the data into the attachInfo structure
1197
memcpy(&entry->attachInfo->producePageFile[0],
1198
&entry->producePageFile[0],
1199
(size_t)normalizedPageStore.producePageFileSize);
1200
memcpy(&entry->attachInfo->consumePageFile[0],
1201
&entry->consumePageFile[0],
1202
(size_t)normalizedPageStore.consumePageFileSize);
1205
* NOTE: The UVAs that follow may be 0. In this case an older VMX has
1206
* issued a SetPageFile call without mapping the backing files for the
1207
* queue contents. The result of this is that the queue pair cannot
1208
* be connected by host.
1211
entry->attachInfo->produceBuffer = normalizedPageStore.producePageUVA;
1212
entry->attachInfo->consumeBuffer = normalizedPageStore.consumePageUVA;
1214
if (VMCIContext_SupportsHostQP(context)) {
1215
result = VMCIHost_GetUserMemory(entry->attachInfo,
1219
if (result < VMCI_SUCCESS) {
1226
* In the event that the QueuePair was created by a host in a
1227
* hosted kernel, then we send notification now that the QueuePair
1228
* contents backing files are attached to the Queues. Note in
1229
* VMCIQPBrokerAllocInt(), above, we skipped this step when the
1230
* creator was a host (on hosted).
1233
if (!vmkernel && entry->createId == VMCI_HOST_CONTEXT_ID) {
1234
result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
1235
if (result < VMCI_SUCCESS) {
1240
entry->pageStoreSet = TRUE;
1241
result = VMCI_SUCCESS;
1249
*-----------------------------------------------------------------------------
1251
* VMCIQPBroker_Detach --
1253
* Informs the VMCI queue pair broker that a context has detached
1254
* from a given QueuePair handle. Assumes that the queue pair
1255
* broker lock is held. If the "detach" input parameter is
1256
* FALSE, the queue pair entry is not removed from the list of
1257
* queue pairs registered with the queue pair broker, and the
1258
* context is not detached from the given handle. If "detach" is
1259
* TRUE, the detach operation really happens. With "detach" set
1260
* to FALSE, the caller can query if the "actual" detach
1261
* operation would succeed or not. The return value from this
1262
* function remains the same irrespective of the value of the
1265
* Also note that the result code for a VM detaching from a
1266
* VM-host queue pair is always VMCI_SUCCESS_LAST_DETACH. This
1267
* is so that VMX can unlink the backing files. On the host side
1268
* the files are either locked (Mac OS/Linux) or the contents are
1272
* Success or failure.
1277
*-----------------------------------------------------------------------------
1281
VMCIQPBroker_Detach(VMCIHandle handle, // IN
1282
VMCIContext *context, // IN
1283
Bool detach) // IN: Really detach?
1285
QPBrokerEntry *entry;
1287
const VMCIId contextId = VMCIContext_GetId(context);
1289
Bool isLocal = FALSE;
1291
if (VMCI_HANDLE_INVALID(handle) ||
1292
!context || contextId == VMCI_INVALID_ID) {
1293
return VMCI_ERROR_INVALID_ARGS;
1296
if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
1297
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
1298
"(handle=0x%x:0x%x).\n",
1299
contextId, handle.context, handle.resource));
1300
result = VMCI_ERROR_NOT_FOUND;
1304
entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
1306
result = VMCI_ERROR_NOT_FOUND;
1310
isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
1312
ASSERT(vmkernel || !isLocal);
1314
if (contextId != entry->createId && contextId != entry->attachId) {
1315
result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
1319
if (contextId == entry->createId) {
1320
peerId = entry->attachId;
1322
peerId = entry->createId;
1326
/* Do not update the queue pair entry. */
1328
ASSERT(entry->qp.refCount == 1 || entry->qp.refCount == 2);
1330
if (entry->qp.refCount == 1 ||
1331
(!vmkernel && peerId == VMCI_HOST_CONTEXT_ID)) {
1332
result = VMCI_SUCCESS_LAST_DETACH;
1334
result = VMCI_SUCCESS;
1340
if (contextId == entry->createId) {
1341
entry->createId = VMCI_INVALID_ID;
1343
entry->attachId = VMCI_INVALID_ID;
1345
entry->qp.refCount--;
1349
* If the caller detaching is a usermode process (e.g., VMX), then
1350
* we must detach the mappings now. On Windows.
1352
* VMCIHost_SaveProduceQ() will save the guest's produceQ so that
1353
* the host can pick up the data after the guest is gone.
1355
* We save the ProduceQ whenever the guest detaches (even if VMX
1356
* continues to run). If we didn't do this, then we'd have the
1357
* problem of finding and releasing the memory when the client goes
1358
* away because we won't be able to find the client in the list of
1359
* QueuePair entries. The detach code path (has already) set the
1360
* contextId for detached end-point to VMCI_INVALID_ID. (See just
1361
* a few lines above where that happens.) Sure, we could fix that,
1362
* and then we could look at all entries finding ones where the
1363
* contextId of either creator or attach matches the going away
1364
* context's Id. But, if we just copy out the guest's produceQ
1365
* -always- then we reduce the logic changes elsewhere.
1369
* Some example paths through this code:
1371
* Guest-to-guest: the code will call ReleaseUserMemory() once when
1372
* the first guest detaches. And then a second time when the
1373
* second guest detaches. That's OK. Nobody is using the user
1374
* memory (because there is no host attached) and
1375
* ReleaseUserMemory() tracks its resources.
1377
* Host detaches first: the code will not call anything because
1378
* contextId == VMCI_HOST_CONTEXT_ID and because (in the second if
1379
* () clause below) refCount > 0.
1381
* Guest detaches second: the first if clause, below, will not be
1382
* taken because refCount is already 0. The second if () clause
1383
* (below) will be taken and it will simply call
1384
* ReleaseUserMemory().
1386
* Guest detaches first: the code will call SaveProduceQ().
1388
* Host detaches second: the code will call ReleaseUserMemory()
1389
* which will free the kernel allocated Q memory.
1392
if (entry->pageStoreSet &&
1393
contextId != VMCI_HOST_CONTEXT_ID &&
1394
VMCIContext_SupportsHostQP(context) &&
1395
entry->qp.refCount) {
1397
* It's important to pass down produceQ and consumeQ in the
1398
* correct order because the produceQ that is to be saved is the
1399
* guest's, so we have to be sure that the routine sees the
1400
* guest's produceQ as (in this case) the first Q parameter.
1403
if (entry->attachId == VMCI_HOST_CONTEXT_ID) {
1404
VMCIHost_SaveProduceQ(entry->attachInfo,
1407
entry->qp.produceSize);
1408
} else if (entry->createId == VMCI_HOST_CONTEXT_ID) {
1409
VMCIHost_SaveProduceQ(entry->attachInfo,
1412
entry->qp.consumeSize);
1414
VMCIHost_ReleaseUserMemory(entry->attachInfo,
1421
if (!entry->qp.refCount) {
1422
QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
1425
if (entry->pageStoreSet &&
1426
VMCIContext_SupportsHostQP(context)) {
1427
VMCIHost_ReleaseUserMemory(entry->attachInfo,
1431
if (entry->attachInfo) {
1432
VMCI_FreeKernelMem(entry->attachInfo, sizeof *entry->attachInfo);
1434
if (entry->produceQ) {
1435
VMCI_FreeKernelMem(entry->produceQ, sizeof *entry->produceQ);
1437
if (entry->consumeQ) {
1438
VMCI_FreeKernelMem(entry->consumeQ, sizeof *entry->consumeQ);
1442
VMCI_FreeKernelMem(entry, sizeof *entry);
1443
result = VMCI_SUCCESS_LAST_DETACH;
1446
* XXX: If we ever allow the creator to detach and attach again
1447
* to the same queue pair, we need to handle the mapping of the
1448
* shared memory region in vmkernel differently. Currently, we
1449
* assume that an attaching VM always needs to swap the two
1453
ASSERT(peerId != VMCI_INVALID_ID);
1454
QueuePairNotifyPeer(FALSE, handle, contextId, peerId);
1455
if (!vmkernel && peerId == VMCI_HOST_CONTEXT_ID) {
1456
result = VMCI_SUCCESS_LAST_DETACH;
1458
result = VMCI_SUCCESS;
1463
if (result >= VMCI_SUCCESS && detach) {
1464
if (!isLocal || result == VMCI_SUCCESS_LAST_DETACH) {
1465
VMCIHandleArray_RemoveEntry(context->queuePairArray, handle);
685
pageStore, context, NULL, NULL,
1654
868
*-----------------------------------------------------------------------------
870
* VMCIQPBrokerAllocInt --
872
* QueuePair_Alloc for use when setting up queue pair endpoints
873
* on the host. Like QueuePair_Alloc, but returns a pointer to
874
* the QPBrokerEntry on success.
877
* Success or failure.
880
* Memory may be allocated.
882
*-----------------------------------------------------------------------------
886
VMCIQPBrokerAllocInt(VMCIHandle handle, // IN
889
VMCIPrivilegeFlags privFlags, // IN
890
uint64 produceSize, // IN
891
uint64 consumeSize, // IN
892
QueuePairPageStore *pageStore, // IN/OUT
893
VMCIContext *context, // IN: Caller
894
VMCIEventReleaseCB wakeupCB, // IN
895
void *clientData, // IN
896
QPBrokerEntry **ent, // OUT
897
Bool *swap) // OUT: swap queues?
899
const VMCIId contextId = VMCIContext_GetId(context);
901
QPBrokerEntry *entry;
902
Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
905
if (VMCI_HANDLE_INVALID(handle) ||
906
(flags & ~VMCI_QP_ALL_FLAGS) ||
907
(isLocal && (!vmkernel || contextId != VMCI_HOST_CONTEXT_ID ||
908
handle.context != contextId)) ||
909
!(produceSize || consumeSize) ||
910
!context || contextId == VMCI_INVALID_ID ||
911
handle.context == VMCI_INVALID_ID) {
912
return VMCI_ERROR_INVALID_ARGS;
915
if (pageStore && !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore)) {
916
return VMCI_ERROR_INVALID_ARGS;
920
* In the initial argument check, we ensure that non-vmkernel hosts
921
* are not allowed to create local queue pairs.
924
ASSERT(vmkernel || !isLocal);
928
if (!isLocal && VMCIContext_QueuePairExists(context, handle)) {
929
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) already attached to queue pair "
930
"(handle=0x%x:0x%x).\n",
931
contextId, handle.context, handle.resource));
932
VMCIQPBrokerUnlock();
933
return VMCI_ERROR_ALREADY_EXISTS;
936
entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
939
result = VMCIQPBrokerCreate(handle, peer, flags, privFlags, produceSize,
940
consumeSize, pageStore, context, wakeupCB,
944
result = VMCIQPBrokerAttach(entry, peer, flags, privFlags, produceSize,
945
consumeSize, pageStore, context, wakeupCB,
949
VMCIQPBrokerUnlock();
952
*swap = (contextId == VMCI_HOST_CONTEXT_ID) && !(create && isLocal);
960
*-----------------------------------------------------------------------------
962
* VMCIQPBrokerCreate --
964
* The first endpoint issuing a queue pair allocation will create the state
965
* of the queue pair in the queue pair broker.
967
* If the creator is a guest, it will associate a VMX virtual address range
968
* with the queue pair as specified by the pageStore. For compatibility with
969
* older VMX'en, that would use a separate step to set the VMX virtual
970
* address range, the virtual address range can be registered later using
971
* VMCIQPBroker_SetPageStore. In that case, a pageStore of NULL should be
974
* If the creator is the host, a pageStore of NULL should be used as well,
975
* since the host is not able to supply a page store for the queue pair.
977
* For older VMX and host callers, the queue pair will be created in the
978
* VMCIQPB_CREATED_NO_MEM state, and for current VMX callers, it will be
979
* created in VMCOQPB_CREATED_MEM state.
982
* VMCI_SUCCESS on success, appropriate error code otherwise.
985
* Memory will be allocated, and pages may be pinned.
987
*-----------------------------------------------------------------------------
991
VMCIQPBrokerCreate(VMCIHandle handle, // IN
994
VMCIPrivilegeFlags privFlags, // IN
995
uint64 produceSize, // IN
996
uint64 consumeSize, // IN
997
QueuePairPageStore *pageStore, // IN
998
VMCIContext *context, // IN: Caller
999
VMCIEventReleaseCB wakeupCB, // IN
1000
void *clientData, // IN
1001
QPBrokerEntry **ent) // OUT
1003
QPBrokerEntry *entry = NULL;
1004
const VMCIId contextId = VMCIContext_GetId(context);
1005
Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
1007
uint64 guestProduceSize;
1008
uint64 guestConsumeSize;
1011
* Do not create if the caller asked not to.
1014
if (flags & VMCI_QPFLAG_ATTACH_ONLY) {
1015
return VMCI_ERROR_NOT_FOUND;
1019
* Creator's context ID should match handle's context ID or the creator
1020
* must allow the context in handle's context ID as the "peer".
1023
if (handle.context != contextId && handle.context != peer) {
1024
return VMCI_ERROR_NO_ACCESS;
1027
if (VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(peer)) {
1028
return VMCI_ERROR_DST_UNREACHABLE;
1032
* Creator's context ID for local queue pairs should match the
1033
* peer, if a peer is specified.
1036
if (isLocal && peer != VMCI_INVALID_ID && contextId != peer) {
1037
return VMCI_ERROR_NO_ACCESS;
1040
entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_ATOMIC);
1042
return VMCI_ERROR_NO_MEM;
1045
if (VMCIContext_GetId(context) == VMCI_HOST_CONTEXT_ID && !isLocal) {
1047
* The queue pair broker entry stores values from the guest
1048
* point of view, so a creating host side endpoint should swap
1049
* produce and consume values -- unless it is a local queue
1050
* pair, in which case no swapping is necessary, since the local
1051
* attacher will swap queues.
1054
guestProduceSize = consumeSize;
1055
guestConsumeSize = produceSize;
1057
guestProduceSize = produceSize;
1058
guestConsumeSize = consumeSize;
1061
memset(entry, 0, sizeof *entry);
1062
entry->qp.handle = handle;
1063
entry->qp.peer = peer;
1064
entry->qp.flags = flags;
1065
entry->qp.produceSize = guestProduceSize;
1066
entry->qp.consumeSize = guestConsumeSize;
1067
entry->qp.refCount = 1;
1068
entry->createId = contextId;
1069
entry->attachId = VMCI_INVALID_ID;
1070
entry->state = VMCIQPB_NEW;
1071
entry->requireTrustedAttach =
1072
(context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) ? TRUE : FALSE;
1073
entry->createdByTrusted =
1074
(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED) ? TRUE : FALSE;
1075
entry->vmciPageFiles = FALSE;
1076
entry->wakeupCB = wakeupCB;
1077
entry->clientData = clientData;
1078
entry->produceQ = VMCIHost_AllocQueue(guestProduceSize);
1079
if (entry->produceQ == NULL) {
1080
result = VMCI_ERROR_NO_MEM;
1083
entry->consumeQ = VMCIHost_AllocQueue(guestConsumeSize);
1084
if (entry->consumeQ == NULL) {
1085
result = VMCI_ERROR_NO_MEM;
1089
VMCI_InitQueueMutex(entry->produceQ, entry->consumeQ);
1091
VMCIList_InitEntry(&entry->qp.listItem);
1094
ASSERT(pageStore == NULL);
1096
entry->localMem = VMCI_AllocKernelMem(QPE_NUM_PAGES(entry->qp) * PAGE_SIZE,
1097
VMCI_MEMORY_NONPAGED);
1098
if (entry->localMem == NULL) {
1099
result = VMCI_ERROR_NO_MEM;
1102
entry->state = VMCIQPB_CREATED_MEM;
1103
entry->produceQ->qHeader = entry->localMem;
1104
entry->consumeQ->qHeader =
1105
(VMCIQueueHeader *)((uint8 *)entry->localMem +
1106
(CEILING(entry->qp.produceSize, PAGE_SIZE) + 1) * PAGE_SIZE);
1107
VMCIQueueHeader_Init(entry->produceQ->qHeader, handle);
1108
VMCIQueueHeader_Init(entry->consumeQ->qHeader, handle);
1109
} else if (pageStore) {
1110
ASSERT(entry->createId != VMCI_HOST_CONTEXT_ID || isLocal);
1113
* The VMX already initialized the queue pair headers, so no
1114
* need for the kernel side to do that.
1117
result = VMCIHost_RegisterUserMemory(pageStore,
1120
if (result < VMCI_SUCCESS) {
1123
VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
1124
entry->state = VMCIQPB_CREATED_MEM;
1127
* A create without a pageStore may be either a host side create (in which
1128
* case we are waiting for the guest side to supply the memory) or an old
1129
* style queue pair create (in which case we will expect a set page store
1130
* call as the next step).
1133
entry->state = VMCIQPB_CREATED_NO_MEM;
1136
QueuePairList_AddEntry(&qpBrokerList, &entry->qp);
1141
VMCIContext_QueuePairCreate(context, handle);
1143
return VMCI_SUCCESS;
1146
if (entry != NULL) {
1147
if (entry->produceQ != NULL) {
1148
VMCIHost_FreeQueue(entry->produceQ, guestProduceSize);
1150
if (entry->consumeQ != NULL) {
1151
VMCIHost_FreeQueue(entry->consumeQ, guestConsumeSize);
1153
VMCI_FreeKernelMem(entry, sizeof *entry);
1160
*-----------------------------------------------------------------------------
1162
* VMCIQPBrokerAttach --
1164
* The second endpoint issuing a queue pair allocation will attach to the
1165
* queue pair registered with the queue pair broker.
1167
* If the attacher is a guest, it will associate a VMX virtual address range
1168
* with the queue pair as specified by the pageStore. At this point, the
1169
* already attach host endpoint may start using the queue pair, and an
1170
* attach event is sent to it. For compatibility with older VMX'en, that
1171
* used a separate step to set the VMX virtual address range, the virtual
1172
* address range can be registered later using VMCIQPBroker_SetPageStore. In
1173
* that case, a pageStore of NULL should be used, and the attach event will
1174
* be generated once the actual page store has been set.
1176
* If the attacher is the host, a pageStore of NULL should be used as well,
1177
* since the page store information is already set by the guest.
1179
* For new VMX and host callers, the queue pair will be moved to the
1180
* VMCIQPB_ATTACHED_MEM state, and for older VMX callers, it will be
1181
* moved to the VMCOQPB_ATTACHED_NO_MEM state.
1184
* VMCI_SUCCESS on success, appropriate error code otherwise.
1187
* Memory will be allocated, and pages may be pinned.
1189
*-----------------------------------------------------------------------------
1193
VMCIQPBrokerAttach(QPBrokerEntry *entry, // IN
1196
VMCIPrivilegeFlags privFlags, // IN
1197
uint64 produceSize, // IN
1198
uint64 consumeSize, // IN
1199
QueuePairPageStore *pageStore, // IN/OUT
1200
VMCIContext *context, // IN: Caller
1201
VMCIEventReleaseCB wakeupCB, // IN
1202
void *clientData, // IN
1203
QPBrokerEntry **ent) // OUT
1205
const VMCIId contextId = VMCIContext_GetId(context);
1206
Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
1209
if (entry->state != VMCIQPB_CREATED_NO_MEM &&
1210
entry->state != VMCIQPB_CREATED_MEM) {
1211
return VMCI_ERROR_UNAVAILABLE;
1215
if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
1216
contextId != entry->createId) {
1217
return VMCI_ERROR_INVALID_ARGS;
1219
} else if (contextId == entry->createId || contextId == entry->attachId) {
1220
return VMCI_ERROR_ALREADY_EXISTS;
1223
ASSERT(entry->qp.refCount < 2);
1224
ASSERT(entry->attachId == VMCI_INVALID_ID);
1226
if (VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(entry->createId)) {
1227
return VMCI_ERROR_DST_UNREACHABLE;
1231
* If we are attaching from a restricted context then the queuepair
1232
* must have been created by a trusted endpoint.
1235
if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
1236
if (!entry->createdByTrusted) {
1237
return VMCI_ERROR_NO_ACCESS;
1242
* If we are attaching to a queuepair that was created by a restricted
1243
* context then we must be trusted.
1246
if (entry->requireTrustedAttach) {
1247
if (!(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) {
1248
return VMCI_ERROR_NO_ACCESS;
1253
* If the creator specifies VMCI_INVALID_ID in "peer" field, access
1254
* control check is not performed.
1257
if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != contextId) {
1258
return VMCI_ERROR_NO_ACCESS;
1261
if (entry->createId == VMCI_HOST_CONTEXT_ID) {
1263
* Do not attach if the caller doesn't support Host Queue Pairs
1264
* and a host created this queue pair.
1267
if (!VMCIContext_SupportsHostQP(context)) {
1268
return VMCI_ERROR_INVALID_RESOURCE;
1270
} else if (contextId == VMCI_HOST_CONTEXT_ID) {
1271
VMCIContext *createContext;
1272
Bool supportsHostQP;
1275
* Do not attach a host to a user created queue pair if that
1276
* user doesn't support host queue pair end points.
1279
createContext = VMCIContext_Get(entry->createId);
1280
supportsHostQP = VMCIContext_SupportsHostQP(createContext);
1281
VMCIContext_Release(createContext);
1283
if (!supportsHostQP) {
1284
return VMCI_ERROR_INVALID_RESOURCE;
1288
if ((entry->qp.flags & ~VMCI_QP_ASYMM) != (flags & ~VMCI_QP_ASYMM_PEER)) {
1289
return VMCI_ERROR_QUEUEPAIR_MISMATCH;
1292
if (contextId != VMCI_HOST_CONTEXT_ID) {
1294
* The queue pair broker entry stores values from the guest
1295
* point of view, so an attaching guest should match the values
1296
* stored in the entry.
1299
if (entry->qp.produceSize != produceSize ||
1300
entry->qp.consumeSize != consumeSize) {
1301
return VMCI_ERROR_QUEUEPAIR_MISMATCH;
1303
} else if (entry->qp.produceSize != consumeSize ||
1304
entry->qp.consumeSize != produceSize) {
1305
return VMCI_ERROR_QUEUEPAIR_MISMATCH;
1308
if (contextId != VMCI_HOST_CONTEXT_ID) {
1310
* If a guest attached to a queue pair, it will supply the backing memory.
1311
* If this is a pre NOVMVM vmx, the backing memory will be supplied by
1312
* calling VMCIQPBroker_SetPageStore() following the return of the
1313
* VMCIQPBroker_Alloc() call. If it is a vmx of version NOVMVM or later,
1314
* the page store must be supplied as part of the VMCIQPBroker_Alloc call.
1315
* Under all circumstances must the initially created queue pair not have
1316
* any memory associated with it already.
1319
if (entry->state != VMCIQPB_CREATED_NO_MEM) {
1320
return VMCI_ERROR_INVALID_ARGS;
1323
if (pageStore != NULL) {
1325
* Patch up host state to point to guest supplied memory. The VMX
1326
* already initialized the queue pair headers, so no need for the
1327
* kernel side to do that.
1330
result = VMCIHost_RegisterUserMemory(pageStore,
1333
if (result < VMCI_SUCCESS) {
1336
VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
1337
if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
1338
result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ,
1340
if (result < VMCI_SUCCESS) {
1341
VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
1345
entry->state = VMCIQPB_ATTACHED_MEM;
1347
entry->state = VMCIQPB_ATTACHED_NO_MEM;
1349
} else if (entry->state == VMCIQPB_CREATED_NO_MEM) {
1351
* The host side is attempting to attach to a queue pair that doesn't have
1352
* any memory associated with it. This must be a pre NOVMVM vmx that hasn't
1353
* set the page store information yet, or a quiesced VM.
1356
return VMCI_ERROR_UNAVAILABLE;
1359
* For non-blocking queue pairs, we cannot rely on enqueue/dequeue to map
1360
* in the pages on the host-side, since it may block, so we make an attempt
1364
if (flags & VMCI_QPFLAG_NONBLOCK) {
1365
result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, flags);
1366
if (result < VMCI_SUCCESS) {
1369
entry->qp.flags |= flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED);
1373
* The host side has successfully attached to a queue pair.
1376
entry->state = VMCIQPB_ATTACHED_MEM;
1379
if (entry->state == VMCIQPB_ATTACHED_MEM) {
1380
result = QueuePairNotifyPeer(TRUE, entry->qp.handle, contextId,
1382
if (result < VMCI_SUCCESS) {
1383
VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue "
1384
"pair (handle=0x%x:0x%x).\n", entry->createId,
1385
entry->qp.handle.context, entry->qp.handle.resource));
1389
entry->attachId = contextId;
1390
entry->qp.refCount++;
1392
ASSERT(!entry->wakeupCB);
1393
entry->wakeupCB = wakeupCB;
1394
entry->clientData = clientData;
1398
* When attaching to local queue pairs, the context already has
1399
* an entry tracking the queue pair, so don't add another one.
1403
VMCIContext_QueuePairCreate(context, entry->qp.handle);
1405
ASSERT(VMCIContext_QueuePairExists(context, entry->qp.handle));
1411
return VMCI_SUCCESS;
1416
*-----------------------------------------------------------------------------
1418
* VMCIQPBroker_SetPageStore --
1420
* VMX'en with versions lower than VMCI_VERSION_NOVMVM use a separate
1421
* step to add the UVAs of the VMX mapping of the queue pair. This function
1422
* provides backwards compatibility with such VMX'en, and takes care of
1423
* registering the page store for a queue pair previously allocated by the
1424
* VMX during create or attach. This function will move the queue pair state
1425
* to either from VMCIQBP_CREATED_NO_MEM to VMCIQBP_CREATED_MEM or
1426
* VMCIQBP_ATTACHED_NO_MEM to VMCIQBP_ATTACHED_MEM. If moving to the
1427
* attached state with memory, the queue pair is ready to be used by the
1428
* host peer, and an attached event will be generated.
1430
* Assumes that the queue pair broker lock is held.
1432
* This function is only used by the hosted platform, since there is no
1433
* issue with backwards compatibility for vmkernel.
1436
* VMCI_SUCCESS on success, appropriate error code otherwise.
1439
* Pages may get pinned.
1441
*-----------------------------------------------------------------------------
1445
VMCIQPBroker_SetPageStore(VMCIHandle handle, // IN
1446
VA64 produceUVA, // IN
1447
VA64 consumeUVA, // IN
1448
VMCIContext *context) // IN: Caller
1450
QPBrokerEntry *entry;
1452
const VMCIId contextId = VMCIContext_GetId(context);
1454
if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
1455
return VMCI_ERROR_INVALID_ARGS;
1459
* We only support guest to host queue pairs, so the VMX must
1460
* supply UVAs for the mapped page files.
1463
if (produceUVA == 0 || consumeUVA == 0) {
1464
return VMCI_ERROR_INVALID_ARGS;
1469
if (!VMCIContext_QueuePairExists(context, handle)) {
1470
VMCI_WARNING((LGPFX"Context (ID=0x%x) not attached to queue pair "
1471
"(handle=0x%x:0x%x).\n", contextId, handle.context,
1473
result = VMCI_ERROR_NOT_FOUND;
1477
entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
1479
result = VMCI_ERROR_NOT_FOUND;
1484
* If I'm the owner then I can set the page store.
1486
* Or, if a host created the QueuePair and I'm the attached peer
1487
* then I can set the page store.
1490
if (entry->createId != contextId &&
1491
(entry->createId != VMCI_HOST_CONTEXT_ID ||
1492
entry->attachId != contextId)) {
1493
result = VMCI_ERROR_QUEUEPAIR_NOTOWNER;
1497
if (entry->state != VMCIQPB_CREATED_NO_MEM &&
1498
entry->state != VMCIQPB_ATTACHED_NO_MEM) {
1499
result = VMCI_ERROR_UNAVAILABLE;
1503
result = VMCIHost_GetUserMemory(produceUVA, consumeUVA,
1504
entry->produceQ, entry->consumeQ);
1505
if (result < VMCI_SUCCESS) {
1508
VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
1509
result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, FALSE);
1510
if (result < VMCI_SUCCESS) {
1511
VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
1515
if (entry->state == VMCIQPB_CREATED_NO_MEM) {
1516
entry->state = VMCIQPB_CREATED_MEM;
1518
ASSERT(entry->state == VMCIQPB_ATTACHED_NO_MEM);
1519
entry->state = VMCIQPB_ATTACHED_MEM;
1521
entry->vmciPageFiles = TRUE;
1523
if (entry->state == VMCIQPB_ATTACHED_MEM) {
1524
result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
1525
if (result < VMCI_SUCCESS) {
1526
VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue "
1527
"pair (handle=0x%x:0x%x).\n", entry->createId,
1528
entry->qp.handle.context, entry->qp.handle.resource));
1532
result = VMCI_SUCCESS;
1534
VMCIQPBrokerUnlock();
1540
*-----------------------------------------------------------------------------
1542
* VMCIQPBroker_Detach --
1544
* The main entry point for detaching from a queue pair registered with the
1545
* queue pair broker. If more than one endpoint is attached to the queue
1546
* pair, the first endpoint will mainly decrement a reference count and
1547
* generate a notification to its peer. The last endpoint will clean up
1548
* the queue pair state registered with the broker.
1550
* When a guest endpoint detaches, it will unmap and unregister the guest
1551
* memory backing the queue pair. If the host is still attached, it will
1552
* no longer be able to access the queue pair content.
1554
* If the queue pair is already in a state where there is no memory
1555
* registered for the queue pair (any *_NO_MEM state), it will transition to
1556
* the VMCIQPB_SHUTDOWN_NO_MEM state. This will also happen, if a guest
1557
* endpoint is the first of two endpoints to detach. If the host endpoint is
1558
* the first out of two to detach, the queue pair will move to the
1559
* VMCIQPB_SHUTDOWN_MEM state.
1562
* VMCI_SUCCESS on success, appropriate error code otherwise.
1565
* Memory may be freed, and pages may be unpinned.
1567
*-----------------------------------------------------------------------------
1571
VMCIQPBroker_Detach(VMCIHandle handle, // IN
1572
VMCIContext *context) // IN
1574
QPBrokerEntry *entry;
1575
const VMCIId contextId = VMCIContext_GetId(context);
1577
Bool isLocal = FALSE;
1580
if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
1581
return VMCI_ERROR_INVALID_ARGS;
1586
if (!VMCIContext_QueuePairExists(context, handle)) {
1587
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
1588
"(handle=0x%x:0x%x).\n",
1589
contextId, handle.context, handle.resource));
1590
result = VMCI_ERROR_NOT_FOUND;
1594
entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
1596
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
1597
"(handle=0x%x:0x%x) that isn't present in broker.\n",
1598
contextId, handle.context, handle.resource));
1599
result = VMCI_ERROR_NOT_FOUND;
1603
if (contextId != entry->createId && contextId != entry->attachId) {
1604
result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
1608
if (contextId == entry->createId) {
1609
peerId = entry->attachId;
1610
entry->createId = VMCI_INVALID_ID;
1612
peerId = entry->createId;
1613
entry->attachId = VMCI_INVALID_ID;
1615
entry->qp.refCount--;
1617
isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
1619
if (contextId != VMCI_HOST_CONTEXT_ID) {
1626
* Pre NOVMVM vmx'en may detach from a queue pair before setting the page
1627
* store, and in that case there is no user memory to detach from. Also,
1628
* more recent VMX'en may detach from a queue pair in the quiesced state.
1631
VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
1632
headersMapped = entry->produceQ->qHeader || entry->consumeQ->qHeader;
1633
if (QPBROKERSTATE_HAS_MEM(entry)) {
1634
result = VMCIHost_UnmapQueues(INVALID_VMCI_GUEST_MEM_ID,
1637
if (result < VMCI_SUCCESS) {
1638
VMCI_WARNING((LGPFX"Failed to unmap queue headers for queue pair "
1639
"(handle=0x%x:0x%x,result=%d).\n", handle.context,
1640
handle.resource, result));
1642
VMCIHost_MarkQueuesUnavailable(entry->produceQ, entry->consumeQ);
1643
if (entry->vmciPageFiles) {
1644
VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
1646
VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ);
1649
if (!headersMapped) {
1650
QueuePairResetSavedHeaders(entry);
1652
VMCI_ReleaseQueueMutex(entry->produceQ);
1653
if (!headersMapped && entry->wakeupCB) {
1654
entry->wakeupCB(entry->clientData);
1657
if (entry->wakeupCB) {
1658
entry->wakeupCB = NULL;
1659
entry->clientData = NULL;
1663
if (entry->qp.refCount == 0) {
1664
QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
1667
VMCI_FreeKernelMem(entry->localMem, QPE_NUM_PAGES(entry->qp) * PAGE_SIZE);
1669
VMCI_CleanupQueueMutex(entry->produceQ, entry->consumeQ);
1670
VMCIHost_FreeQueue(entry->produceQ, entry->qp.produceSize);
1671
VMCIHost_FreeQueue(entry->consumeQ, entry->qp.consumeSize);
1672
VMCI_FreeKernelMem(entry, sizeof *entry);
1674
VMCIContext_QueuePairDestroy(context, handle);
1676
ASSERT(peerId != VMCI_INVALID_ID);
1677
QueuePairNotifyPeer(FALSE, handle, contextId, peerId);
1678
if (contextId == VMCI_HOST_CONTEXT_ID && QPBROKERSTATE_HAS_MEM(entry)) {
1679
entry->state = VMCIQPB_SHUTDOWN_MEM;
1681
entry->state = VMCIQPB_SHUTDOWN_NO_MEM;
1684
VMCIContext_QueuePairDestroy(context, handle);
1687
result = VMCI_SUCCESS;
1689
VMCIQPBrokerUnlock();
1695
*-----------------------------------------------------------------------------
1697
* VMCIQPBroker_Map --
1699
* Establishes the necessary mappings for a queue pair given a
1700
* reference to the queue pair guest memory. This is usually
1701
* called when a guest is unquiesced and the VMX is allowed to
1702
* map guest memory once again.
1705
* VMCI_SUCCESS on success, appropriate error code otherwise.
1708
* Memory may be allocated, and pages may be pinned.
1710
*-----------------------------------------------------------------------------
1714
VMCIQPBroker_Map(VMCIHandle handle, // IN
1715
VMCIContext *context, // IN
1716
VMCIQPGuestMem guestMem) // IN
1718
QPBrokerEntry *entry;
1719
const VMCIId contextId = VMCIContext_GetId(context);
1720
Bool isLocal = FALSE;
1723
if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
1724
return VMCI_ERROR_INVALID_ARGS;
1729
if (!VMCIContext_QueuePairExists(context, handle)) {
1730
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
1731
"(handle=0x%x:0x%x).\n",
1732
contextId, handle.context, handle.resource));
1733
result = VMCI_ERROR_NOT_FOUND;
1737
entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
1739
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
1740
"(handle=0x%x:0x%x) that isn't present in broker.\n",
1741
contextId, handle.context, handle.resource));
1742
result = VMCI_ERROR_NOT_FOUND;
1746
if (contextId != entry->createId && contextId != entry->attachId) {
1747
result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
1751
isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
1755
* On vmkernel, the readiness of the queue pair can be signalled
1756
* immediately since the guest memory is already registered.
1759
VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
1760
VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
1761
if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
1762
result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ,
1765
result = VMCI_SUCCESS;
1767
if (result == VMCI_SUCCESS) {
1768
QueuePairResetSavedHeaders(entry);
1770
VMCI_ReleaseQueueMutex(entry->produceQ);
1771
if (result == VMCI_SUCCESS) {
1772
if (entry->wakeupCB) {
1773
entry->wakeupCB(entry->clientData);
1776
} else if (contextId != VMCI_HOST_CONTEXT_ID) {
1777
QueuePairPageStore pageStore;
1779
ASSERT(entry->state == VMCIQPB_CREATED_NO_MEM ||
1780
entry->state == VMCIQPB_SHUTDOWN_NO_MEM ||
1781
entry->state == VMCIQPB_ATTACHED_NO_MEM);
1784
pageStore.pages = guestMem;
1785
pageStore.len = QPE_NUM_PAGES(entry->qp);
1787
VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
1788
QueuePairResetSavedHeaders(entry);
1789
result = VMCIHost_RegisterUserMemory(&pageStore, entry->produceQ, entry->consumeQ);
1790
VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
1791
VMCI_ReleaseQueueMutex(entry->produceQ);
1792
if (result == VMCI_SUCCESS) {
1794
* Move state from *_NO_MEM to *_MEM.
1799
ASSERT(entry->state == VMCIQPB_CREATED_MEM ||
1800
entry->state == VMCIQPB_SHUTDOWN_MEM ||
1801
entry->state == VMCIQPB_ATTACHED_MEM);
1803
if (entry->wakeupCB) {
1804
entry->wakeupCB(entry->clientData);
1808
result = VMCI_SUCCESS;
1812
VMCIQPBrokerUnlock();
1818
*-----------------------------------------------------------------------------
1820
* QueuePairSaveHeaders --
1822
* Saves a snapshot of the queue headers for the given QP broker
1823
* entry. Should be used when guest memory is unmapped.
1826
* VMCI_SUCCESS on success, appropriate error code if guest memory
1827
* can't be accessed..
1832
*-----------------------------------------------------------------------------
1836
QueuePairSaveHeaders(QPBrokerEntry *entry) // IN
1840
if (entry->produceQ->savedHeader != NULL &&
1841
entry->consumeQ->savedHeader != NULL) {
1843
* If the headers have already been saved, we don't need to do
1844
* it again, and we don't want to map in the headers
1848
return VMCI_SUCCESS;
1850
if (NULL == entry->produceQ->qHeader || NULL == entry->consumeQ->qHeader) {
1851
result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, FALSE);
1852
if (result < VMCI_SUCCESS) {
1856
memcpy(&entry->savedProduceQ, entry->produceQ->qHeader,
1857
sizeof entry->savedProduceQ);
1858
entry->produceQ->savedHeader = &entry->savedProduceQ;
1859
memcpy(&entry->savedConsumeQ, entry->consumeQ->qHeader,
1860
sizeof entry->savedConsumeQ);
1861
entry->consumeQ->savedHeader = &entry->savedConsumeQ;
1863
return VMCI_SUCCESS;
1868
*-----------------------------------------------------------------------------
1870
* QueuePairResetSavedHeaders --
1872
* Resets saved queue headers for the given QP broker
1873
* entry. Should be used when guest memory becomes available
1874
* again, or the guest detaches.
1882
*-----------------------------------------------------------------------------
1886
QueuePairResetSavedHeaders(QPBrokerEntry *entry) // IN
1889
VMCI_LockQueueHeader(entry->produceQ);
1891
entry->produceQ->savedHeader = NULL;
1892
entry->consumeQ->savedHeader = NULL;
1894
VMCI_UnlockQueueHeader(entry->produceQ);
1900
*-----------------------------------------------------------------------------
1902
* VMCIQPBroker_Unmap --
1904
* Removes all references to the guest memory of a given queue pair, and
1905
* will move the queue pair from state *_MEM to *_NO_MEM. It is usually
1906
* called when a VM is being quiesced where access to guest memory should
1910
* VMCI_SUCCESS on success, appropriate error code otherwise.
1913
* Memory may be freed, and pages may be unpinned.
1915
*-----------------------------------------------------------------------------
1919
VMCIQPBroker_Unmap(VMCIHandle handle, // IN
1920
VMCIContext *context, // IN
1921
VMCIGuestMemID gid) // IN
1923
QPBrokerEntry *entry;
1924
const VMCIId contextId = VMCIContext_GetId(context);
1925
Bool isLocal = FALSE;
1928
if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
1929
return VMCI_ERROR_INVALID_ARGS;
1933
if (!VMCIContext_QueuePairExists(context, handle)) {
1934
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
1935
"(handle=0x%x:0x%x).\n",
1936
contextId, handle.context, handle.resource));
1937
result = VMCI_ERROR_NOT_FOUND;
1941
entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
1943
VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
1944
"(handle=0x%x:0x%x) that isn't present in broker.\n",
1945
contextId, handle.context, handle.resource));
1946
result = VMCI_ERROR_NOT_FOUND;
1950
if (contextId != entry->createId && contextId != entry->attachId) {
1951
result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
1955
isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
1957
if (contextId != VMCI_HOST_CONTEXT_ID) {
1958
ASSERT(entry->state != VMCIQPB_CREATED_NO_MEM &&
1959
entry->state != VMCIQPB_SHUTDOWN_NO_MEM &&
1960
entry->state != VMCIQPB_ATTACHED_NO_MEM);
1963
VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
1964
result = QueuePairSaveHeaders(entry);
1965
if (result < VMCI_SUCCESS) {
1966
VMCI_WARNING((LGPFX"Failed to save queue headers for queue pair "
1967
"(handle=0x%x:0x%x,result=%d).\n", handle.context,
1968
handle.resource, result));
1970
VMCIHost_UnmapQueues(gid, entry->produceQ, entry->consumeQ);
1971
VMCIHost_MarkQueuesUnavailable(entry->produceQ, entry->consumeQ);
1974
* On hosted, when we unmap queue pairs, the VMX will also
1975
* unmap the guest memory, so we invalidate the previously
1976
* registered memory. If the queue pair is mapped again at a
1977
* later point in time, we will need to reregister the user
1978
* memory with a possibly new user VA.
1981
VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ);
1984
* Move state from *_MEM to *_NO_MEM.
1990
VMCI_ReleaseQueueMutex(entry->produceQ);
1993
result = VMCI_SUCCESS;
1995
VMCIQPBrokerUnlock();
1999
#if !defined(VMKERNEL)
2002
*-----------------------------------------------------------------------------
1656
2004
* VMCIQPGuestEndpoints_Init --
1658
2006
* Initalizes data structure state keeping track of queue pair
1659
2007
* guest endpoints.
2010
* VMCI_SUCCESS on success and appropriate failure code otherwise.
1664
2012
* Side effects: