/** * A fallback method in case something goes wrong with the normal * I/O manager. */ DECLCALLBACK(int) pdmacFileAioMgrFailsafe(RTTHREAD hThreadSelf, void *pvUser) { int rc = VINF_SUCCESS; PPDMACEPFILEMGR pAioMgr = (PPDMACEPFILEMGR)pvUser; NOREF(hThreadSelf); while ( (pAioMgr->enmState == PDMACEPFILEMGRSTATE_RUNNING) || (pAioMgr->enmState == PDMACEPFILEMGRSTATE_SUSPENDING)) { ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, true); if (!ASMAtomicReadBool(&pAioMgr->fWokenUp)) rc = RTSemEventWait(pAioMgr->EventSem, pAioMgr->msBwLimitExpired); ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, false); Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); LogFlow(("Got woken up\n")); ASMAtomicWriteBool(&pAioMgr->fWokenUp, false); /* Process endpoint events first. */ PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint = pAioMgr->pEndpointsHead; while (pEndpoint) { pAioMgr->msBwLimitExpired = RT_INDEFINITE_WAIT; rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpoint); AssertRC(rc); pEndpoint = pEndpoint->AioMgr.pEndpointNext; } /* Now check for an external blocking event. */ if (pAioMgr->fBlockingEventPending) { switch (pAioMgr->enmBlockingEvent) { case PDMACEPFILEAIOMGRBLOCKINGEVENT_ADD_ENDPOINT: { PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointNew = pAioMgr->BlockingEventData.AddEndpoint.pEndpoint; AssertMsg(VALID_PTR(pEndpointNew), ("Adding endpoint event without a endpoint to add\n")); pEndpointNew->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE; pEndpointNew->AioMgr.pEndpointNext = pAioMgr->pEndpointsHead; pEndpointNew->AioMgr.pEndpointPrev = NULL; if (pAioMgr->pEndpointsHead) pAioMgr->pEndpointsHead->AioMgr.pEndpointPrev = pEndpointNew; pAioMgr->pEndpointsHead = pEndpointNew; pAioMgr->cEndpoints++; /* * Process the task list the first time. There might be pending requests * if the endpoint was migrated from another endpoint. */ rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpointNew); AssertRC(rc); break; } case PDMACEPFILEAIOMGRBLOCKINGEVENT_REMOVE_ENDPOINT: { PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointRemove = pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint; AssertMsg(VALID_PTR(pEndpointRemove), ("Removing endpoint event without a endpoint to remove\n")); pEndpointRemove->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_REMOVING; PPDMASYNCCOMPLETIONENDPOINTFILE pPrev = pEndpointRemove->AioMgr.pEndpointPrev; PPDMASYNCCOMPLETIONENDPOINTFILE pNext = pEndpointRemove->AioMgr.pEndpointNext; if (pPrev) pPrev->AioMgr.pEndpointNext = pNext; else pAioMgr->pEndpointsHead = pNext; if (pNext) pNext->AioMgr.pEndpointPrev = pPrev; pAioMgr->cEndpoints--; break; } case PDMACEPFILEAIOMGRBLOCKINGEVENT_CLOSE_ENDPOINT: { PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointClose = pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint; AssertMsg(VALID_PTR(pEndpointClose), ("Close endpoint event without a endpoint to Close\n")); pEndpointClose->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_CLOSING; /* Make sure all tasks finished. */ rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpointClose); AssertRC(rc); break; } case PDMACEPFILEAIOMGRBLOCKINGEVENT_SHUTDOWN: pAioMgr->enmState = PDMACEPFILEMGRSTATE_SHUTDOWN; break; case PDMACEPFILEAIOMGRBLOCKINGEVENT_SUSPEND: pAioMgr->enmState = PDMACEPFILEMGRSTATE_SUSPENDING; break; case PDMACEPFILEAIOMGRBLOCKINGEVENT_RESUME: pAioMgr->enmState = PDMACEPFILEMGRSTATE_RUNNING; break; default: AssertMsgFailed(("Invalid event type %d\n", pAioMgr->enmBlockingEvent)); } ASMAtomicWriteBool(&pAioMgr->fBlockingEventPending, false); pAioMgr->enmBlockingEvent = PDMACEPFILEAIOMGRBLOCKINGEVENT_INVALID; /* Release the waiting thread. */ rc = RTSemEventSignal(pAioMgr->EventSemBlock); AssertRC(rc); } } return rc; }
/** * Interprets a string and assigns it to a USBFilter field. * * (This function is also used by HostUSBDeviceFilter.) * * @param aFilter The filter. * @param aIdx The field index. * @param aStr The input string. * @param aName The field name for use in the error string. * @param aErrStr Where to return the error string on failure. * * @return COM status code. * @remark The idea was to have this as a static function, but tr() doesn't wanna work without a class :-/ */ /*static*/ HRESULT USBDeviceFilter::usbFilterFieldFromString(PUSBFILTER aFilter, USBFILTERIDX aIdx, const Utf8Str &aValue, Utf8Str &aErrStr) { int vrc; // Utf8Str str (aStr); if (aValue.isEmpty()) vrc = USBFilterSetIgnore(aFilter, aIdx); else { const char *pcszValue = aValue.c_str(); if (USBFilterIsNumericField(aIdx)) { /* Is it a lonely number? */ char *pszNext; uint64_t u64; vrc = RTStrToUInt64Ex(pcszValue, &pszNext, 16, &u64); if (RT_SUCCESS(vrc)) pszNext = RTStrStripL (pszNext); if ( vrc == VINF_SUCCESS && !*pszNext) { if (u64 > 0xffff) { // there was a bug writing out "-1" values in earlier versions, which got // written as "FFFFFFFF"; make sure we don't fail on those if (u64 == 0xffffffff) u64 = 0xffff; else { aErrStr = Utf8StrFmt(tr("The %s value '%s' is too big (max 0xFFFF)"), describeUSBFilterIdx(aIdx), pcszValue); return E_INVALIDARG; } } vrc = USBFilterSetNumExact(aFilter, aIdx, (uint16_t)u64, true /* fMustBePresent */); } else vrc = USBFilterSetNumExpression(aFilter, aIdx, pcszValue, true /* fMustBePresent */); } else { /* Any wildcard in the string? */ Assert(USBFilterIsStringField(aIdx)); if ( strchr(pcszValue, '*') || strchr(pcszValue, '?') /* || strchr (psz, '[') - later */ ) vrc = USBFilterSetStringPattern(aFilter, aIdx, pcszValue, true /* fMustBePresent */); else vrc = USBFilterSetStringExact(aFilter, aIdx, pcszValue, true /* fMustBePresent */); } } if (RT_FAILURE(vrc)) { if (vrc == VERR_INVALID_PARAMETER) { aErrStr = Utf8StrFmt(tr("The %s filter expression '%s' is not valid"), describeUSBFilterIdx(aIdx), aValue.c_str()); return E_INVALIDARG; } if (vrc == VERR_BUFFER_OVERFLOW) { aErrStr = Utf8StrFmt(tr("Insufficient expression space for the '%s' filter expression '%s'"), describeUSBFilterIdx(aIdx), aValue.c_str()); return E_FAIL; } AssertRC(vrc); aErrStr = Utf8StrFmt(tr("Encountered unexpected status %Rrc when setting '%s' to '%s'"), vrc, describeUSBFilterIdx(aIdx), aValue.c_str()); return E_FAIL; } return S_OK; }
int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) { AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); LogFlowThisFuncEnter(); if (pSvcCbData->mParms < 3) return VERR_INVALID_PARAMETER; int vrc = VINF_SUCCESS; int idx = 1; /* Current parameter index. */ CALLBACKDATA_FILE_NOTIFY dataCb; /* pSvcCb->mpaParms[0] always contains the context ID. */ pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.uType); pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc); FileStatus_T fileStatus = FileStatus_Undefined; int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */ LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n", dataCb.uType, guestRc)); if (RT_FAILURE(guestRc)) { int rc2 = setFileStatus(FileStatus_Error, guestRc); AssertRC(rc2); rc2 = signalWaitEventInternal(pCbCtx, guestRc, NULL /* pPayload */); AssertRC(rc2); return VINF_SUCCESS; /* Report to the guest. */ } switch (dataCb.uType) { case GUEST_FILE_NOTIFYTYPE_ERROR: { int rc2 = setFileStatus(FileStatus_Error, guestRc); AssertRC(rc2); break; } case GUEST_FILE_NOTIFYTYPE_OPEN: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.open.uHandle); { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID), ("File ID %RU32 does not match context ID %RU32\n", mData.mID, VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID))); /* Set the initial offset. On the guest the whole opening operation * would fail if an initial seek isn't possible. */ mData.mOffCurrent = mData.mOpenInfo.mInitialOffset; } /* Set the process status. */ int rc2 = setFileStatus(FileStatus_Open, guestRc); AssertRC(rc2); } else vrc = VERR_NOT_SUPPORTED; break; } case GUEST_FILE_NOTIFYTYPE_CLOSE: { int rc2 = setFileStatus(FileStatus_Closed, guestRc); AssertRC(rc2); break; } case GUEST_FILE_NOTIFYTYPE_READ: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData, &dataCb.u.read.cbData); uint32_t cbRead = dataCb.u.read.cbData; AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mData.mOffCurrent += cbRead; alock.release(); com::SafeArray<BYTE> data((size_t)cbRead); data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead); fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent, cbRead, ComSafeArrayAsInParam(data)); } else vrc = VERR_NOT_SUPPORTED; break; } case GUEST_FILE_NOTIFYTYPE_WRITE: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mData.mOffCurrent += dataCb.u.write.cbWritten; uint64_t uOffCurrent = mData.mOffCurrent; alock.release(); fireGuestFileWriteEvent(mEventSource, mSession, this, uOffCurrent, dataCb.u.write.cbWritten); } else vrc = VERR_NOT_SUPPORTED; break; } case GUEST_FILE_NOTIFYTYPE_SEEK: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mData.mOffCurrent = dataCb.u.seek.uOffActual; alock.release(); fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, dataCb.u.seek.uOffActual, 0 /* Processed */); } else vrc = VERR_NOT_SUPPORTED; break; } case GUEST_FILE_NOTIFYTYPE_TELL: { if (pSvcCbData->mParms == 4) { pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mData.mOffCurrent = dataCb.u.tell.uOffActual; alock.release(); fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, dataCb.u.tell.uOffActual, 0 /* Processed */); } else vrc = VERR_NOT_SUPPORTED; break; } default: vrc = VERR_NOT_SUPPORTED; break; } if (RT_SUCCESS(vrc)) { GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb)); int rc2 = signalWaitEventInternal(pCbCtx, guestRc, &payload); AssertRC(rc2); } LogFlowThisFunc(("uType=%RU32, guestRc=%Rrc\n", dataCb.uType, dataCb.rc)); LogFlowFuncLeaveRC(vrc); return vrc; }
/** * Initialize the network shaper. * * @returns VBox status code * @param pVM Pointer to the VM. */ int pdmR3NetShaperInit(PVM pVM) { LogFlowFunc((": pVM=%p\n", pVM)); VM_ASSERT_EMT(pVM); PPDMNETSHAPER pNetShaper = NULL; int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_NET_SHAPER, sizeof(PDMNETSHAPER), (void **)&pNetShaper); if (RT_SUCCESS(rc)) { PCFGMNODE pCfgRoot = CFGMR3GetRoot(pVM); PCFGMNODE pCfgNetShaper = CFGMR3GetChild(CFGMR3GetChild(pCfgRoot, "PDM"), "NetworkShaper"); pNetShaper->pVM = pVM; rc = RTCritSectInit(&pNetShaper->cs); if (RT_SUCCESS(rc)) { /* Create all bandwidth groups. */ PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNetShaper, "BwGroups"); if (pCfgBwGrp) { for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur)) { uint64_t cbMax; size_t cchName = CFGMR3GetNameLen(pCur) + 1; char *pszBwGrpId = (char *)RTMemAllocZ(cchName); if (!pszBwGrpId) { rc = VERR_NO_MEMORY; break; } rc = CFGMR3GetName(pCur, pszBwGrpId, cchName); AssertRC(rc); if (RT_SUCCESS(rc)) rc = CFGMR3QueryU64(pCur, "Max", &cbMax); if (RT_SUCCESS(rc)) rc = pdmNsBwGroupCreate(pNetShaper, pszBwGrpId, cbMax); RTMemFree(pszBwGrpId); if (RT_FAILURE(rc)) break; } } if (RT_SUCCESS(rc)) { PUVM pUVM = pVM->pUVM; AssertMsg(!pUVM->pdm.s.pNetShaper, ("Network shaper was already initialized\n")); char szDesc[256]; static unsigned iThread; RTStrPrintf(szDesc, sizeof(szDesc), "PDMNSTXThread-%d", ++iThread); rc = PDMR3ThreadCreate(pVM, &pNetShaper->hTxThread, pNetShaper, pdmR3NsTxThread, pdmR3NsTxWakeUp, 0, RTTHREADTYPE_IO, szDesc); if (RT_SUCCESS(rc)) { pUVM->pdm.s.pNetShaper = pNetShaper; return VINF_SUCCESS; } } RTCritSectDelete(&pNetShaper->cs); } MMR3HeapFree(pNetShaper); } LogFlowFunc((": pVM=%p rc=%Rrc\n", pVM, rc)); return rc; }
DECLINLINE(int) vboxPciVmLock(PVBOXRAWPCIDRVVM pThis) { int rc = RTSemFastMutexRequest(pThis->hFastMtx); AssertRC(rc); return rc; }
/** * @interface_method_impl{PDMINVRAMCONNECTOR,pfnVarStoreSeqPut} */ DECLCALLBACK(int) drvNvram_VarStoreSeqPut(PPDMINVRAMCONNECTOR pInterface, int idxVariable, PCRTUUID pVendorUuid, const char *pszName, size_t cchName, uint32_t fAttributes, uint8_t const *pbValue, size_t cbValue) { PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector); int rc = VINF_SUCCESS; if (pThis->fPermanentSave && pThis->pNvram) { char szExtraName[256]; size_t offValueNm = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16, NVRAM_CFGM_OVERLAY_PATH "/%04u/", idxVariable); char szUuid[RTUUID_STR_LENGTH]; int rc2 = RTUuidToStr(pVendorUuid, szUuid, sizeof(szUuid)); AssertRC(rc2); char szAttribs[32]; if (fAttributes != NVRAM_DEFAULT_ATTRIB) RTStrPrintf(szAttribs, sizeof(szAttribs), "%#x", fAttributes); else szAttribs[0] = '\0'; char *pszValue = drvNvram_binaryToCfgmString(pbValue, cbValue); if (pszValue) { const char *apszTodo[] = { "Name", pszName, "Uuid", szUuid, "Value", pszValue, "Attribs", szAttribs, }; for (unsigned i = 0; i < RT_ELEMENTS(apszTodo); i += 2) { if (!apszTodo[i + 1][0]) continue; Assert(strlen(apszTodo[i]) < 16); strcpy(szExtraName + offValueNm, apszTodo[i]); try { HRESULT hrc = pThis->pNvram->getParent()->i_machine()->SetExtraData(Bstr(szExtraName).raw(), Bstr(apszTodo[i + 1]).raw()); if (FAILED(hrc)) { LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) returned %Rhrc\n", szExtraName, apszTodo[i + 1], hrc)); rc = Global::vboxStatusCodeFromCOM(hrc); } } catch (...) { LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) threw exception\n", szExtraName, apszTodo[i + 1])); rc = VERR_UNEXPECTED_EXCEPTION; } } } else rc = VERR_NO_MEMORY; RTMemFree(pszValue); } NOREF(cchName); LogFlowFuncLeaveRC(rc); return rc; }
int main(int argc, char **argv) { RTEXITCODE rcExit; /* * Init globals and such. */ int rc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); g_pszProgName = RTPathFilename(argv[0]); #ifdef DEBUG rc = RTCritSectInit(&g_csLog); AssertRC(rc); #endif #ifdef VBOXSERVICE_TOOLBOX /* * Run toolbox code before all other stuff since these things are simpler * shell/file/text utility like programs that just happens to be inside * VBoxService and shouldn't be subject to /dev/vboxguest, pid-files and * global mutex restrictions. */ if (VBoxServiceToolboxMain(argc, argv, &rcExit)) return rcExit; #endif /* * Connect to the kernel part before daemonizing so we can fail and * complain if there is some kind of problem. We need to initialize the * guest lib *before* we do the pre-init just in case one of services needs * do to some initial stuff with it. */ VBoxServiceVerbose(2, "Calling VbgR3Init()\n"); rc = VbglR3Init(); if (RT_FAILURE(rc)) { if (rc == VERR_ACCESS_DENIED) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n", g_pszProgName); return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc); } #ifdef RT_OS_WINDOWS /* * Check if we're the specially spawned VBoxService.exe process that * handles page fusion. This saves an extra executable. */ if ( argc == 2 && !strcmp(argv[1], "--pagefusionfork")) return VBoxServicePageSharingInitFork(); #endif char szLogFile[RTPATH_MAX + 128] = ""; /* * Parse the arguments. * * Note! This code predates RTGetOpt, thus the manual parsing. */ bool fDaemonize = true; bool fDaemonized = false; for (int i = 1; i < argc; i++) { const char *psz = argv[i]; if (*psz != '-') return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz); psz++; /* translate long argument to short */ if (*psz == '-') { psz++; size_t cch = strlen(psz); #define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \ && !memcmp(psz, strconst, sizeof(strconst) - 1) ) if (MATCHES("foreground")) psz = "f"; else if (MATCHES("verbose")) psz = "v"; else if (MATCHES("version")) psz = "V"; else if (MATCHES("help")) psz = "h"; else if (MATCHES("interval")) psz = "i"; #ifdef RT_OS_WINDOWS else if (MATCHES("register")) psz = "r"; else if (MATCHES("unregister")) psz = "u"; #endif else if (MATCHES("logfile")) psz = "l"; else if (MATCHES("daemonized")) { fDaemonized = true; continue; } else { bool fFound = false; if (cch > sizeof("enable-") && !memcmp(psz, "enable-", sizeof("enable-") - 1)) for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName))) g_aServices[j].fEnabled = true; if (cch > sizeof("disable-") && !memcmp(psz, "disable-", sizeof("disable-") - 1)) for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName))) g_aServices[j].fEnabled = false; if (cch > sizeof("only-") && !memcmp(psz, "only-", sizeof("only-") - 1)) for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName); if (g_aServices[j].fEnabled) fFound = true; } if (!fFound) { rcExit = vboxServiceLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) { rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i); fFound = rc == VINF_SUCCESS; if (fFound) break; if (rc != -1) return rc; } } if (!fFound) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]); continue; } #undef MATCHES } /* handle the string of short options. */ do { switch (*psz) { case 'i': rc = VBoxServiceArgUInt32(argc, argv, psz + 1, &i, &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1); if (rc) return rc; psz = NULL; break; case 'f': fDaemonize = false; break; case 'v': g_cVerbosity++; break; case 'V': RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr()); return RTEXITCODE_SUCCESS; case 'h': case '?': return vboxServiceUsage(); #ifdef RT_OS_WINDOWS case 'r': return VBoxServiceWinInstall(); case 'u': return VBoxServiceWinUninstall(); #endif case 'l': { rc = VBoxServiceArgString(argc, argv, psz + 1, &i, szLogFile, sizeof(szLogFile)); if (rc) return rc; psz = NULL; break; } default: { rcExit = vboxServiceLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; bool fFound = false; for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i); fFound = rc == VINF_SUCCESS; if (fFound) break; if (rc != -1) return rc; } if (!fFound) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%c' (%s)\n", *psz, argv[i]); break; } } } while (psz && *++psz); } /* Check that at least one service is enabled. */ if (vboxServiceCountEnabledServices() == 0) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n"); rc = VBoxServiceLogCreate(strlen(szLogFile) ? szLogFile : NULL); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)", strlen(szLogFile) ? szLogFile : "<None>", rc); /* Call pre-init if we didn't do it already. */ rcExit = vboxServiceLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; #ifdef RT_OS_WINDOWS /* * Make sure only one instance of VBoxService runs at a time. Create a * global mutex for that. * * Note! The \\Global\ namespace was introduced with Win2K, thus the * version check. * Note! If the mutex exists CreateMutex will open it and set last error to * ERROR_ALREADY_EXISTS. */ OSVERSIONINFOEX OSInfoEx; RT_ZERO(OSInfoEx); OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); SetLastError(NO_ERROR); HANDLE hMutexAppRunning; if ( GetVersionEx((LPOSVERSIONINFO)&OSInfoEx) && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT && OSInfoEx.dwMajorVersion >= 5 /* NT 5.0 a.k.a W2K */) hMutexAppRunning = CreateMutex(NULL, FALSE, "Global\\" VBOXSERVICE_NAME); else hMutexAppRunning = CreateMutex(NULL, FALSE, VBOXSERVICE_NAME); if (hMutexAppRunning == NULL) { DWORD dwErr = GetLastError(); if ( dwErr == ERROR_ALREADY_EXISTS || dwErr == ERROR_ACCESS_DENIED) { VBoxServiceError("%s is already running! Terminating.", g_pszProgName); return RTEXITCODE_FAILURE; } VBoxServiceError("CreateMutex failed with last error %u! Terminating", GetLastError()); return RTEXITCODE_FAILURE; } #else /* !RT_OS_WINDOWS */ /** @todo Add PID file creation here? */ #endif /* !RT_OS_WINDOWS */ VBoxServiceVerbose(0, "%s r%s started. Verbose level = %d\n", RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity); /* * Daemonize if requested. */ if (fDaemonize && !fDaemonized) { #ifdef RT_OS_WINDOWS VBoxServiceVerbose(2, "Starting service dispatcher ...\n"); rcExit = VBoxServiceWinEnterCtrlDispatcher(); #else VBoxServiceVerbose(1, "Daemonizing...\n"); rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */); if (RT_FAILURE(rc)) return VBoxServiceError("Daemon failed: %Rrc\n", rc); /* in-child */ #endif } #ifdef RT_OS_WINDOWS else #endif { /* * Windows: We're running the service as a console application now. Start the * services, enter the main thread's run loop and stop them again * when it returns. * * POSIX: This is used for both daemons and console runs. Start all services * and return immediately. */ #ifdef RT_OS_WINDOWS # ifndef RT_OS_NT4 /* Install console control handler. */ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)VBoxServiceConsoleControlHandler, TRUE /* Add handler */)) { VBoxServiceError("Unable to add console control handler, error=%ld\n", GetLastError()); /* Just skip this error, not critical. */ } # endif /* !RT_OS_NT4 */ #endif /* RT_OS_WINDOWS */ rc = VBoxServiceStartServices(); rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; if (RT_SUCCESS(rc)) VBoxServiceMainWait(); #ifdef RT_OS_WINDOWS # ifndef RT_OS_NT4 /* Uninstall console control handler. */ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)NULL, FALSE /* Remove handler */)) { VBoxServiceError("Unable to remove console control handler, error=%ld\n", GetLastError()); /* Just skip this error, not critical. */ } # endif /* !RT_OS_NT4 */ #else /* !RT_OS_WINDOWS */ /* On Windows - since we're running as a console application - we already stopped all services * through the console control handler. So only do the stopping of services here on other platforms * where the break/shutdown/whatever signal was just received. */ VBoxServiceStopServices(); #endif /* RT_OS_WINDOWS */ } VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminated); #ifdef RT_OS_WINDOWS /* * Cleanup mutex. */ CloseHandle(hMutexAppRunning); #endif VBoxServiceVerbose(0, "Ended.\n"); #ifdef DEBUG RTCritSectDelete(&g_csLog); //RTMemTrackerDumpAllToStdOut(); #endif VBoxServiceLogDestroy(); return rcExit; }
static DWORD WINAPI vboxServiceWinCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) #endif { DWORD rcRet = NO_ERROR; #ifdef TARGET_NT4 VBoxServiceVerbose(2, "Control handler: Control=%#x\n", dwControl); #else VBoxServiceVerbose(2, "Control handler: Control=%#x, EventType=%#x\n", dwControl, dwEventType); #endif switch (dwControl) { case SERVICE_CONTROL_INTERROGATE: vboxServiceWinSetStatus(g_dwWinServiceLastStatus, 0); break; case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: { vboxServiceWinSetStatus(SERVICE_STOP_PENDING, 0); int rc2 = VBoxServiceStopServices(); if (RT_FAILURE(rc2)) rcRet = ERROR_GEN_FAILURE; else { rc2 = VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminated); AssertRC(rc2); } vboxServiceWinSetStatus(SERVICE_STOPPED, 0); break; } # ifndef TARGET_NT4 case SERVICE_CONTROL_SESSIONCHANGE: /* Only Windows 2000 and up. */ { AssertPtr(lpEventData); PWTSSESSION_NOTIFICATION pNotify = (PWTSSESSION_NOTIFICATION)lpEventData; Assert(pNotify->cbSize == sizeof(WTSSESSION_NOTIFICATION)); VBoxServiceVerbose(1, "Control handler: %s (Session=%ld, Event=%#x)\n", vboxServiceWTSStateToString(dwEventType), pNotify->dwSessionId, dwEventType); /* Handle all events, regardless of dwEventType. */ int rc2 = VBoxServiceVMInfoSignal(); AssertRC(rc2); break; } # endif /* !TARGET_NT4 */ default: VBoxServiceVerbose(1, "Control handler: Function not implemented: %#x\n", dwControl); rcRet = ERROR_CALL_NOT_IMPLEMENTED; break; } #ifndef TARGET_NT4 return rcRet; #endif }
VBoxDbgConsole::VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent/* = NULL*/, IVirtualBox *a_pVirtualBox/* = NULL */) : VBoxDbgBaseWindow(a_pDbgGui, a_pParent, "Console"), m_pOutput(NULL), m_pInput(NULL), m_fInputRestoreFocus(false), m_pszInputBuf(NULL), m_cbInputBuf(0), m_cbInputBufAlloc(0), m_pszOutputBuf(NULL), m_cbOutputBuf(0), m_cbOutputBufAlloc(0), m_pTimer(NULL), m_fUpdatePending(false), m_Thread(NIL_RTTHREAD), m_EventSem(NIL_RTSEMEVENT), m_fTerminate(false), m_fThreadTerminated(false) { /* * Create the output text box. */ m_pOutput = new VBoxDbgConsoleOutput(this, a_pVirtualBox); /* try figure a suitable size */ QLabel *pLabel = new QLabel( "11111111111111111111111111111111111111111111111111111111111111111111111111111112222222222", this); pLabel->setFont(m_pOutput->font()); QSize Size = pLabel->sizeHint(); delete pLabel; Size.setWidth((int)(Size.width() * 1.10)); Size.setHeight(Size.width() / 2); resize(Size); /* * Create the input combo box (with a label). */ QHBoxLayout *pLayout = new QHBoxLayout(); //pLayout->setSizeConstraint(QLayout::SetMaximumSize); pLabel = new QLabel(" Command "); pLayout->addWidget(pLabel); pLabel->setMaximumSize(pLabel->sizeHint()); pLabel->setAlignment(Qt::AlignCenter); m_pInput = new VBoxDbgConsoleInput(NULL); pLayout->addWidget(m_pInput); m_pInput->setDuplicatesEnabled(false); connect(m_pInput, SIGNAL(commandSubmitted(const QString &)), this, SLOT(commandSubmitted(const QString &))); # if 0//def Q_WS_MAC pLabel = new QLabel(" "); pLayout->addWidget(pLabel); pLabel->setMaximumSize(20, m_pInput->sizeHint().height() + 6); pLabel->setMinimumSize(20, m_pInput->sizeHint().height() + 6); # endif QWidget *pHBox = new QWidget(this); pHBox->setLayout(pLayout); m_pInput->setEnabled(false); /* (we'll get a ready notification) */ /* * Vertical layout box on the whole widget. */ QVBoxLayout *pVLayout = new QVBoxLayout(); pVLayout->setContentsMargins(0, 0, 0, 0); pVLayout->setSpacing(5); pVLayout->addWidget(m_pOutput); pVLayout->addWidget(pHBox); setLayout(pVLayout); /* * The tab order is from input to output, not the other way around as it is by default. */ setTabOrder(m_pInput, m_pOutput); m_fInputRestoreFocus = true; /* hack */ /* * Setup the timer. */ m_pTimer = new QTimer(this); connect(m_pTimer, SIGNAL(timeout()), SLOT(updateOutput())); /* * Init the backend structure. */ m_Back.Core.pfnInput = backInput; m_Back.Core.pfnRead = backRead; m_Back.Core.pfnWrite = backWrite; m_Back.Core.pfnSetReady = backSetReady; m_Back.pSelf = this; /* * Create the critical section, the event semaphore and the debug console thread. */ int rc = RTCritSectInit(&m_Lock); AssertRC(rc); rc = RTSemEventCreate(&m_EventSem); AssertRC(rc); rc = RTThreadCreate(&m_Thread, backThread, this, 0, RTTHREADTYPE_DEBUGGER, RTTHREADFLAGS_WAITABLE, "VBoxDbgC"); AssertRC(rc); if (RT_FAILURE(rc)) m_Thread = NIL_RTTHREAD; /* * Shortcuts. */ m_pFocusToInput = new QAction("", this); m_pFocusToInput->setShortcut(QKeySequence("Ctrl+L")); addAction(m_pFocusToInput); connect(m_pFocusToInput, SIGNAL(triggered(bool)), this, SLOT(actFocusToInput())); m_pFocusToOutput = new QAction("", this); m_pFocusToOutput->setShortcut(QKeySequence("Ctrl+O")); addAction(m_pFocusToOutput); connect(m_pFocusToOutput, SIGNAL(triggered(bool)), this, SLOT(actFocusToOutput())); addAction(m_pOutput->m_pBlackOnWhiteAction); addAction(m_pOutput->m_pGreenOnBlackAction); addAction(m_pOutput->m_pCourierFontAction); addAction(m_pOutput->m_pMonospaceFontAction); }
/** * Sets up a test file creating the I/O thread. * * @returns VBox status code. * @param pVM Pointer to the shared VM instance structure. * @param pTestFile Pointer to the uninitialized test file structure. * @param iTestId Unique test id. */ static int tstPDMACStressTestFileOpen(PVM pVM, PPDMACTESTFILE pTestFile, unsigned iTestId) { int rc = VERR_NO_MEMORY; /* Size is a multiple of 512 */ pTestFile->cbFileMax = RTRandU64Ex(FILE_SIZE_MIN, FILE_SIZE_MAX) & ~(511UL); pTestFile->cbFileCurr = 0; pTestFile->cbFileSegment = RTRandU32Ex(SEGMENT_SIZE_MIN, RT_MIN(pTestFile->cbFileMax, SEGMENT_SIZE_MAX)) & ~((size_t)511); Assert(pTestFile->cbFileMax >= pTestFile->cbFileSegment); /* Set up the segments array. */ pTestFile->cSegments = pTestFile->cbFileMax / pTestFile->cbFileSegment; pTestFile->cSegments += ((pTestFile->cbFileMax % pTestFile->cbFileSegment) > 0) ? 1 : 0; pTestFile->paSegs = (PPDMACTESTFILESEG)RTMemAllocZ(pTestFile->cSegments * sizeof(PDMACTESTFILESEG)); if (pTestFile->paSegs) { /* Init the segments */ for (unsigned i = 0; i < pTestFile->cSegments; i++) { PPDMACTESTFILESEG pSeg = &pTestFile->paSegs[i]; pSeg->off = (RTFOFF)i * pTestFile->cbFileSegment; pSeg->cbSegment = pTestFile->cbFileSegment; /* Let the buffer point to a random position in the test pattern. */ uint32_t offTestPattern = RTRandU64Ex(0, g_cbTestPattern - pSeg->cbSegment); pSeg->pbData = g_pbTestPattern + offTestPattern; } /* Init task array. */ pTestFile->cTasksActiveMax = RTRandU32Ex(1, TASK_ACTIVE_MAX); pTestFile->paTasks = (PPDMACTESTFILETASK)RTMemAllocZ(pTestFile->cTasksActiveMax * sizeof(PDMACTESTFILETASK)); if (pTestFile->paTasks) { /* Create the template */ char szDesc[256]; RTStrPrintf(szDesc, sizeof(szDesc), "Template-%d", iTestId); rc = PDMR3AsyncCompletionTemplateCreateInternal(pVM, &pTestFile->pTemplate, tstPDMACStressTestFileTaskCompleted, pTestFile, szDesc); if (RT_SUCCESS(rc)) { /* Open the endpoint now. Because async completion endpoints cannot create files we have to do it before. */ char szFile[RTPATH_MAX]; RTStrPrintf(szFile, sizeof(szFile), "tstPDMAsyncCompletionStress-%d.tmp", iTestId); RTFILE FileTmp; rc = RTFileOpen(&FileTmp, szFile, RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE); if (RT_SUCCESS(rc)) { RTFileClose(FileTmp); rc = PDMR3AsyncCompletionEpCreateForFile(&pTestFile->hEndpoint, szFile, 0, pTestFile->pTemplate); if (RT_SUCCESS(rc)) { char szThreadDesc[256]; pTestFile->fRunning = true; /* Create the thread creating the I/O for the given file. */ RTStrPrintf(szThreadDesc, sizeof(szThreadDesc), "PDMACThread-%d", iTestId); rc = PDMR3ThreadCreate(pVM, &pTestFile->hThread, pTestFile, tstPDMACTestFileThread, NULL, 0, RTTHREADTYPE_IO, szThreadDesc); if (RT_SUCCESS(rc)) { rc = PDMR3ThreadResume(pTestFile->hThread); AssertRC(rc); RTPrintf(TESTCASE ": Created test file %s cbFileMax=%llu cbFileSegment=%u cSegments=%u cTasksActiveMax=%u\n", szFile, pTestFile->cbFileMax, pTestFile->cbFileSegment, pTestFile->cSegments, pTestFile->cTasksActiveMax); return VINF_SUCCESS; } PDMR3AsyncCompletionEpClose(pTestFile->hEndpoint); } RTFileDelete(szFile); } PDMR3AsyncCompletionTemplateDestroy(pTestFile->pTemplate); } RTMemFree(pTestFile->paTasks); } else rc = VERR_NO_MEMORY; RTMemFree(pTestFile->paSegs); } else rc = VERR_NO_MEMORY; RTPrintf(TESTCASE ": Opening test file with id %d failed rc=%Rrc\n", iTestId, rc); return rc; }
static uint32_t parallel_ioport_read(void *opaque, uint32_t addr, int *pRC) { ParallelState *s = (ParallelState *)opaque; uint32_t ret = ~0U; *pRC = VINF_SUCCESS; addr &= 7; switch(addr) { default: case 0: if (!(s->reg_control & LPT_CONTROL_ENABLE_BIDIRECT)) ret = s->reg_data; else { #ifndef IN_RING3 *pRC = VINF_IOM_HC_IOPORT_READ; #else if (RT_LIKELY(s->pDrvHostParallelConnector)) { size_t cbRead; int rc = s->pDrvHostParallelConnector->pfnRead(s->pDrvHostParallelConnector, &s->reg_data, &cbRead); Log(("parallel_io_port_read: read 0x%X\n", s->reg_data)); AssertRC(rc); } ret = s->reg_data; #endif } break; case 1: #ifndef IN_RING3 *pRC = VINF_IOM_HC_IOPORT_READ; #else if (RT_LIKELY(s->pDrvHostParallelConnector)) { int rc = s->pDrvHostParallelConnector->pfnReadStatus(s->pDrvHostParallelConnector, &s->reg_status); AssertRC(rc); } ret = s->reg_status; parallel_clear_irq(s); #endif break; case 2: ret = s->reg_control; break; case 3: ret = s->reg_epp_addr; break; case 4: ret = s->reg_epp_data; break; case 5: break; case 6: break; case 7: break; } LogFlow(("parallel: read addr=0x%02x val=0x%02x\n", addr, ret)); return ret; }
/** * Resolve APIs not present on older windows versions. */ void VGSvcWinResolveApis(void) { RTLDRMOD hLdrMod; #define RESOLVE_SYMBOL(a_fn) do { RT_CONCAT(g_pfn, a_fn) = (decltype(a_fn) *)RTLdrGetFunction(hLdrMod, #a_fn); } while (0) /* From ADVAPI32.DLL: */ int rc = RTLdrLoadSystem("advapi32.dll", true /*fNoUnload*/, &hLdrMod); AssertRC(rc); if (RT_SUCCESS(rc)) { RESOLVE_SYMBOL(RegisterServiceCtrlHandlerExA); RESOLVE_SYMBOL(ChangeServiceConfig2A); RESOLVE_SYMBOL(GetNamedSecurityInfoA); RESOLVE_SYMBOL(SetEntriesInAclA); RESOLVE_SYMBOL(SetNamedSecurityInfoA); RESOLVE_SYMBOL(LsaNtStatusToWinError); RTLdrClose(hLdrMod); } /* From KERNEL32.DLL: */ rc = RTLdrLoadSystem("kernel32.dll", true /*fNoUnload*/, &hLdrMod); AssertRC(rc); if (RT_SUCCESS(rc)) { RESOLVE_SYMBOL(CreateToolhelp32Snapshot); RESOLVE_SYMBOL(Process32First); RESOLVE_SYMBOL(Process32Next); RESOLVE_SYMBOL(Module32First); RESOLVE_SYMBOL(Module32Next); RESOLVE_SYMBOL(GetSystemTimeAdjustment); RESOLVE_SYMBOL(SetSystemTimeAdjustment); RTLdrClose(hLdrMod); } /* From NTDLL.DLL: */ rc = RTLdrLoadSystem("ntdll.dll", true /*fNoUnload*/, &hLdrMod); AssertRC(rc); if (RT_SUCCESS(rc)) { RESOLVE_SYMBOL(ZwQuerySystemInformation); RTLdrClose(hLdrMod); } /* From IPHLPAPI.DLL: */ rc = RTLdrLoadSystem("iphlpapi.dll", true /*fNoUnload*/, &hLdrMod); if (RT_SUCCESS(rc)) { RESOLVE_SYMBOL(GetAdaptersInfo); RTLdrClose(hLdrMod); } /* From WS2_32.DLL: */ rc = RTLdrLoadSystem("ws2_32.dll", true /*fNoUnload*/, &hLdrMod); if (RT_SUCCESS(rc)) { RESOLVE_SYMBOL(WSAStartup); RESOLVE_SYMBOL(WSACleanup); RESOLVE_SYMBOL(WSASocketA); RESOLVE_SYMBOL(WSAIoctl); RESOLVE_SYMBOL(WSAGetLastError); RESOLVE_SYMBOL(closesocket); RESOLVE_SYMBOL(inet_ntoa); RTLdrClose(hLdrMod); } }
RTDECL(int) RTUriFileCreateEx(const char *pszPath, uint32_t fPathStyle, char **ppszUri, size_t cbUri, size_t *pcchUri) { /* * Validate and adjust input. (RTPathParse check pszPath out for us) */ if (pcchUri) { AssertPtrReturn(pcchUri, VERR_INVALID_POINTER); *pcchUri = ~(size_t)0; } AssertPtrReturn(ppszUri, VERR_INVALID_POINTER); AssertReturn(!(fPathStyle & ~RTPATH_STR_F_STYLE_MASK) && fPathStyle != RTPATH_STR_F_STYLE_RESERVED, VERR_INVALID_FLAGS); if (fPathStyle == RTPATH_STR_F_STYLE_HOST) fPathStyle = RTPATH_STYLE; /* * Let the RTPath code parse the stuff (no reason to duplicate path parsing * and get it slightly wrong here). */ RTPATHPARSED ParsedPath; int rc = RTPathParse(pszPath, &ParsedPath, sizeof(ParsedPath), fPathStyle); if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) { /* Skip leading slashes. */ if (ParsedPath.fProps & RTPATH_PROP_ROOT_SLASH) { if (fPathStyle == RTPATH_STR_F_STYLE_DOS) while (pszPath[0] == '/' || pszPath[0] == '\\') pszPath++; else while (pszPath[0] == '/') pszPath++; } const size_t cchPath = strlen(pszPath); /* * Calculate the encoded length and figure destination buffering. */ static const char s_szPrefix[] = "file:///"; size_t const cchPrefix = sizeof(s_szPrefix) - (ParsedPath.fProps & RTPATH_PROP_UNC ? 2 : 1); size_t cchEncoded = rtUriCalcEncodedLength(pszPath, cchPath, fPathStyle != RTPATH_STR_F_STYLE_DOS); if (pcchUri) *pcchUri = cchEncoded; char *pszDst; char *pszFreeMe = NULL; if (!cbUri || *ppszUri == NULL) { cbUri = RT_MAX(cbUri, cchPrefix + cchEncoded + 1); *ppszUri = pszFreeMe = pszDst = RTStrAlloc(cbUri); AssertReturn(pszDst, VERR_NO_STR_MEMORY); } else if (cchEncoded < cbUri) pszDst = *ppszUri; else return VERR_BUFFER_OVERFLOW; /* * Construct the URI. */ memcpy(pszDst, s_szPrefix, cchPrefix); pszDst[cchPrefix] = '\0'; rc = rtUriEncodeIntoBuffer(pszPath, cchPath, fPathStyle != RTPATH_STR_F_STYLE_DOS, &pszDst[cchPrefix], cbUri - cchPrefix); if (RT_SUCCESS(rc)) { Assert(strlen(pszDst) == cbUri - 1); if (fPathStyle == RTPATH_STR_F_STYLE_DOS) RTPathChangeToUnixSlashes(pszDst, true /*fForce*/); return VINF_SUCCESS; } AssertRC(rc); /* Impossible! rtUriCalcEncodedLength or something above is busted! */ if (pszFreeMe) RTStrFree(pszFreeMe); } return rc; }
/** * Open a USB device and create a backend instance for it. * * @returns VBox status code. */ static DECLCALLBACK(int) usbProxyWinOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend) { PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32); int rc = VINF_SUCCESS; pPriv->cAllocatedUrbs = 32; pPriv->paHandles = (PHANDLE)RTMemAllocZ(sizeof(pPriv->paHandles[0]) * pPriv->cAllocatedUrbs); pPriv->paQueuedUrbs = (PQUEUED_URB *)RTMemAllocZ(sizeof(pPriv->paQueuedUrbs[0]) * pPriv->cAllocatedUrbs); if ( pPriv->paQueuedUrbs && pPriv->paHandles) { /* * Open the device. */ pPriv->hDev = CreateFile(pszAddress, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, // no SECURITY_ATTRIBUTES structure OPEN_EXISTING, // No special create flags FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, // overlapped IO NULL); // No template file if (pPriv->hDev != INVALID_HANDLE_VALUE) { Log(("usbProxyWinOpen: hDev=%p\n", pPriv->hDev)); /* * Check the version */ USBSUP_VERSION version = {0}; DWORD cbReturned = 0; if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_GET_VERSION, NULL, 0, &version, sizeof(version), &cbReturned, NULL)) { if (!( version.u32Major != USBDRV_MAJOR_VERSION || version.u32Minor < USBDRV_MINOR_VERSION)) { USBSUP_CLAIMDEV in; in.bInterfaceNumber = 0; cbReturned = 0; if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_CLAIM_DEVICE, &in, sizeof(in), &in, sizeof(in), &cbReturned, NULL)) { if (in.fClaimed) { pPriv->fClaimed = true; #if 0 /** @todo this needs to be enabled if windows chooses a default config. Test with the TrekStor GO Stick. */ pProxyDev->iActiveCfg = 1; pProxyDev->cIgnoreSetConfigs = 1; #endif rc = RTCritSectInit(&pPriv->CritSect); AssertRC(rc); pPriv->hEventWakeup = CreateEvent(NULL, FALSE, FALSE, NULL); Assert(pPriv->hEventWakeup); pPriv->paHandles[0] = pPriv->hEventWakeup; return VINF_SUCCESS; } rc = VERR_GENERAL_FAILURE; Log(("usbproxy: unable to claim device %x (%s)!!\n", pPriv->hDev, pszAddress)); } } else { rc = VERR_VERSION_MISMATCH; Log(("usbproxy: Version mismatch: %d.%d != %d.%d (cur)\n", version.u32Major, version.u32Minor, USBDRV_MAJOR_VERSION, USBDRV_MINOR_VERSION)); } } /* Convert last error if necessary */ if (RT_SUCCESS(rc)) { DWORD dwErr = GetLastError(); Log(("usbproxy: last error %d\n", dwErr)); rc = RTErrConvertFromWin32(dwErr); } CloseHandle(pPriv->hDev); pPriv->hDev = INVALID_HANDLE_VALUE; } else { Log(("usbproxy: FAILED to open '%s'! last error %d\n", pszAddress, GetLastError())); rc = VERR_FILE_NOT_FOUND; } } else rc = VERR_NO_MEMORY; RTMemFree(pPriv->paQueuedUrbs); RTMemFree(pPriv->paHandles); return rc; }
/** * Leaves a critical section entered with PDMCritSectEnter(). * * @returns Indication whether we really exited the critical section. * @retval VINF_SUCCESS if we really exited. * @retval VINF_SEM_NESTED if we only reduced the nesting count. * @retval VERR_NOT_OWNER if you somehow ignore release assertions. * * @param pCritSect The PDM critical section to leave. */ VMMDECL(int) PDMCritSectLeave(PPDMCRITSECT pCritSect) { AssertMsg(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, ("%p %RX32\n", pCritSect, pCritSect->s.Core.u32Magic)); Assert(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC); /* Check for NOP sections before asserting ownership. */ if (pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NOP) return VINF_SUCCESS; /* * Always check that the caller is the owner (screw performance). */ RTNATIVETHREAD const hNativeSelf = pdmCritSectGetNativeSelf(pCritSect); AssertReleaseMsgReturn(pCritSect->s.Core.NativeThreadOwner == hNativeSelf, ("%p %s: %p != %p; cLockers=%d cNestings=%d\n", pCritSect, R3STRING(pCritSect->s.pszName), pCritSect->s.Core.NativeThreadOwner, hNativeSelf, pCritSect->s.Core.cLockers, pCritSect->s.Core.cNestings), VERR_NOT_OWNER); Assert(pCritSect->s.Core.cNestings >= 1); /* * Nested leave. */ if (pCritSect->s.Core.cNestings > 1) { ASMAtomicDecS32(&pCritSect->s.Core.cNestings); Assert(pCritSect->s.Core.cNestings >= 1); ASMAtomicDecS32(&pCritSect->s.Core.cLockers); Assert(pCritSect->s.Core.cLockers >= 0); return VINF_SEM_NESTED; } #ifdef IN_RING0 # if 0 /** @todo Make SUPSemEventSignal interrupt safe (handle table++) and enable this for: defined(RT_OS_LINUX) || defined(RT_OS_OS2) */ if (1) /* SUPSemEventSignal is safe */ # else if (ASMIntAreEnabled()) # endif #endif #if defined(IN_RING3) || defined(IN_RING0) { /* * Leave for real. */ /* update members. */ SUPSEMEVENT hEventToSignal = pCritSect->s.hEventToSignal; pCritSect->s.hEventToSignal = NIL_SUPSEMEVENT; # ifdef IN_RING3 # if defined(PDMCRITSECT_STRICT) if (pCritSect->s.Core.pValidatorRec->hThread != NIL_RTTHREAD) RTLockValidatorRecExclReleaseOwnerUnchecked(pCritSect->s.Core.pValidatorRec); # endif Assert(!pCritSect->s.Core.pValidatorRec || pCritSect->s.Core.pValidatorRec->hThread == NIL_RTTHREAD); # endif ASMAtomicAndU32(&pCritSect->s.Core.fFlags, ~PDMCRITSECT_FLAGS_PENDING_UNLOCK); ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, NIL_RTNATIVETHREAD); ASMAtomicDecS32(&pCritSect->s.Core.cNestings); Assert(pCritSect->s.Core.cNestings == 0); /* stop and decrement lockers. */ STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l); ASMCompilerBarrier(); if (ASMAtomicDecS32(&pCritSect->s.Core.cLockers) >= 0) { /* Someone is waiting, wake up one of them. */ SUPSEMEVENT hEvent = (SUPSEMEVENT)pCritSect->s.Core.EventSem; PSUPDRVSESSION pSession = pCritSect->s.CTX_SUFF(pVM)->pSession; int rc = SUPSemEventSignal(pSession, hEvent); AssertRC(rc); } /* Signal exit event. */ if (hEventToSignal != NIL_SUPSEMEVENT) { Log8(("Signalling %#p\n", hEventToSignal)); int rc = SUPSemEventSignal(pCritSect->s.CTX_SUFF(pVM)->pSession, hEventToSignal); AssertRC(rc); } # if defined(DEBUG_bird) && defined(IN_RING0) VMMTrashVolatileXMMRegs(); # endif } #endif /* IN_RING3 || IN_RING0 */ #ifdef IN_RING0 else #endif #if defined(IN_RING0) || defined(IN_RC) { /* * Try leave it. */ if (pCritSect->s.Core.cLockers == 0) { ASMAtomicWriteS32(&pCritSect->s.Core.cNestings, 0); RTNATIVETHREAD hNativeThread = pCritSect->s.Core.NativeThreadOwner; ASMAtomicAndU32(&pCritSect->s.Core.fFlags, ~PDMCRITSECT_FLAGS_PENDING_UNLOCK); STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l); ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, NIL_RTNATIVETHREAD); if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, -1, 0)) return VINF_SUCCESS; /* darn, someone raced in on us. */ ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, hNativeThread); STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l); Assert(pCritSect->s.Core.cNestings == 0); ASMAtomicWriteS32(&pCritSect->s.Core.cNestings, 1); } ASMAtomicOrU32(&pCritSect->s.Core.fFlags, PDMCRITSECT_FLAGS_PENDING_UNLOCK); /* * Queue the request. */ PVM pVM = pCritSect->s.CTX_SUFF(pVM); AssertPtr(pVM); PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu); uint32_t i = pVCpu->pdm.s.cQueuedCritSectLeaves++; LogFlow(("PDMCritSectLeave: [%d]=%p => R3\n", i, pCritSect)); AssertFatal(i < RT_ELEMENTS(pVCpu->pdm.s.apQueuedCritSectLeaves)); pVCpu->pdm.s.apQueuedCritSectLeaves[i] = MMHyperCCToR3(pVM, pCritSect); VMCPU_FF_SET(pVCpu, VMCPU_FF_PDM_CRITSECT); VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3); STAM_REL_COUNTER_INC(&pVM->pdm.s.StatQueuedCritSectLeaves); STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZUnlock); } #endif /* IN_RING0 || IN_RC */ return VINF_SUCCESS; }
/** * Deregister one(/all) info handler(s) owned by a driver. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param pDrvIns Driver instance. * @param pszName The identifier of the info. If NULL all owned by the driver. */ VMMR3DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName) { LogFlow(("DBGFR3InfoDeregisterDriver: pDrvIns=%p pszName=%p:{%s}\n", pDrvIns, pszName, pszName)); /* * Validate input. */ if (!pDrvIns) { AssertMsgFailed(("!pDrvIns\n")); return VERR_INVALID_PARAMETER; } size_t cchName = pszName ? strlen(pszName) : 0; /* * Enumerate the info handlers and free the requested entries. */ int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect); AssertRC(rc); rc = VERR_FILE_NOT_FOUND; PDBGFINFO pPrev = NULL; PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; if (pszName) { /* * Free a specific one. */ for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext) if ( pInfo->enmType == DBGFINFOTYPE_DRV && pInfo->u.Drv.pDrvIns == pDrvIns && pInfo->cchName == cchName && !strcmp(pInfo->szName, pszName)) { if (pPrev) pPrev->pNext = pInfo->pNext; else pVM->dbgf.s.pInfoFirst = pInfo->pNext; MMR3HeapFree(pInfo); rc = VINF_SUCCESS; break; } } else { /* * Free all owned by the driver. */ for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext) if ( pInfo->enmType == DBGFINFOTYPE_DRV && pInfo->u.Drv.pDrvIns == pDrvIns) { if (pPrev) pPrev->pNext = pInfo->pNext; else pVM->dbgf.s.pInfoFirst = pInfo->pNext; MMR3HeapFree(pInfo); pInfo = pPrev; } rc = VINF_SUCCESS; } int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect); AssertRC(rc2); AssertRC(rc); LogFlow(("DBGFR3InfoDeregisterDriver: returns %Rrc\n", rc)); return rc; }
/** * Entry point. */ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp) { int rcRet = 0; /* error count */ PPDMASYNCCOMPLETIONENDPOINT pEndpointSrc, pEndpointDst; RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); if (argc != 3) { RTPrintf(TESTCASE ": Usage is ./tstPDMAsyncCompletion <source> <dest>\n"); return 1; } PVM pVM; PUVM pUVM; int rc = VMR3Create(1, NULL, NULL, NULL, NULL, NULL, &pVM, &pUVM); if (RT_SUCCESS(rc)) { /* * Little hack to avoid the VM_ASSERT_EMT assertion. */ RTTlsSet(pVM->pUVM->vm.s.idxTLS, &pVM->pUVM->aCpus[0]); pVM->pUVM->aCpus[0].pUVM = pVM->pUVM; pVM->pUVM->aCpus[0].vm.s.NativeThreadEMT = RTThreadNativeSelf(); /* * Create the template. */ PPDMASYNCCOMPLETIONTEMPLATE pTemplate; rc = PDMR3AsyncCompletionTemplateCreateInternal(pVM, &pTemplate, AsyncTaskCompleted, NULL, "Test"); if (RT_FAILURE(rc)) { RTPrintf(TESTCASE ": Error while creating the template!! rc=%d\n", rc); return 1; } /* * Create event semaphore. */ rc = RTSemEventCreate(&g_FinishedEventSem); AssertRC(rc); /* * Create the temporary buffers. */ for (unsigned i=0; i < NR_TASKS; i++) { g_AsyncCompletionTasksBuffer[i] = (uint8_t *)RTMemAllocZ(BUFFER_SIZE); if (!g_AsyncCompletionTasksBuffer[i]) { RTPrintf(TESTCASE ": out of memory!\n"); return ++rcRet; } } /* Create the destination as the async completion API can't do this. */ RTFILE FileTmp; rc = RTFileOpen(&FileTmp, argv[2], RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_NONE); if (RT_FAILURE(rc)) { RTPrintf(TESTCASE ": Error while creating the destination!! rc=%d\n", rc); return ++rcRet; } RTFileClose(FileTmp); /* Create our file endpoint */ rc = PDMR3AsyncCompletionEpCreateForFile(&pEndpointSrc, argv[1], 0, pTemplate); if (RT_SUCCESS(rc)) { rc = PDMR3AsyncCompletionEpCreateForFile(&pEndpointDst, argv[2], 0, pTemplate); if (RT_SUCCESS(rc)) { PDMR3PowerOn(pVM); /* Wait for all threads to finish initialization. */ RTThreadSleep(100); int fReadPass = true; uint64_t cbSrc; size_t offSrc = 0; size_t offDst = 0; uint32_t cTasksUsed = 0; rc = PDMR3AsyncCompletionEpGetSize(pEndpointSrc, &cbSrc); if (RT_SUCCESS(rc)) { /* Copy the data. */ for (;;) { if (fReadPass) { cTasksUsed = (BUFFER_SIZE * NR_TASKS) <= (cbSrc - offSrc) ? NR_TASKS : ((cbSrc - offSrc) / BUFFER_SIZE) + ((cbSrc - offSrc) % BUFFER_SIZE) > 0 ? 1 : 0; g_cTasksLeft = cTasksUsed; for (uint32_t i = 0; i < cTasksUsed; i++) { size_t cbRead = ((size_t)offSrc + BUFFER_SIZE) <= cbSrc ? BUFFER_SIZE : cbSrc - offSrc; RTSGSEG DataSeg; DataSeg.pvSeg = g_AsyncCompletionTasksBuffer[i]; DataSeg.cbSeg = cbRead; rc = PDMR3AsyncCompletionEpRead(pEndpointSrc, offSrc, &DataSeg, 1, cbRead, NULL, &g_AsyncCompletionTasks[i]); AssertRC(rc); offSrc += cbRead; if (offSrc == cbSrc) break; } } else { g_cTasksLeft = cTasksUsed; for (uint32_t i = 0; i < cTasksUsed; i++) { size_t cbWrite = (offDst + BUFFER_SIZE) <= cbSrc ? BUFFER_SIZE : cbSrc - offDst; RTSGSEG DataSeg; DataSeg.pvSeg = g_AsyncCompletionTasksBuffer[i]; DataSeg.cbSeg = cbWrite; rc = PDMR3AsyncCompletionEpWrite(pEndpointDst, offDst, &DataSeg, 1, cbWrite, NULL, &g_AsyncCompletionTasks[i]); AssertRC(rc); offDst += cbWrite; if (offDst == cbSrc) break; } } rc = RTSemEventWait(g_FinishedEventSem, RT_INDEFINITE_WAIT); AssertRC(rc); if (!fReadPass && (offDst == cbSrc)) break; else if (fReadPass) fReadPass = false; else { cTasksUsed = 0; fReadPass = true; } } } else { RTPrintf(TESTCASE ": Error querying size of the endpoint!! rc=%d\n", rc); rcRet++; } PDMR3PowerOff(pVM); PDMR3AsyncCompletionEpClose(pEndpointDst); } PDMR3AsyncCompletionEpClose(pEndpointSrc); } rc = VMR3Destroy(pUVM); AssertMsg(rc == VINF_SUCCESS, ("%s: Destroying VM failed rc=%Rrc!!\n", __FUNCTION__, rc)); VMR3ReleaseUVM(pUVM); /* * Clean up. */ for (uint32_t i = 0; i < NR_TASKS; i++) { RTMemFree(g_AsyncCompletionTasksBuffer[i]); } } else { RTPrintf(TESTCASE ": failed to create VM!! rc=%Rrc\n", rc); rcRet++; } return rcRet; }
/** * Worker for DBGFR3Info and DBGFR3InfoEx. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param idCpu Which CPU to run EMT bound handlers on. * VMCPUID_ANY or a valid CPU ID. * @param pszName What to dump. * @param pszArgs Arguments, optional. * @param pHlp Output helper, optional. */ static DECLCALLBACK(int) dbgfR3Info(PVM pVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp) { /* * Validate input. */ AssertPtrReturn(pszName, VERR_INVALID_POINTER); if (pHlp) { if ( !pHlp->pfnPrintf || !pHlp->pfnPrintfV) { AssertMsgFailed(("A pHlp member is missing!\n")); return VERR_INVALID_PARAMETER; } } else pHlp = &g_dbgfR3InfoLogHlp; /* * Find the info handler. */ size_t cchName = strlen(pszName); int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect); AssertRC(rc); PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; for (; pInfo; pInfo = pInfo->pNext) if ( pInfo->cchName == cchName && !memcmp(pInfo->szName, pszName, cchName)) break; if (pInfo) { /* * Found it. * Make a copy of it on the stack so we can leave the crit sect. * Switch on the type and invoke the handler. */ DBGFINFO Info = *pInfo; rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect); AssertRC(rc); rc = VINF_SUCCESS; switch (Info.enmType) { case DBGFINFOTYPE_DEV: if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT) rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Dev.pfnHandler, 3, Info.u.Dev.pDevIns, pHlp, pszArgs); else Info.u.Dev.pfnHandler(Info.u.Dev.pDevIns, pHlp, pszArgs); break; case DBGFINFOTYPE_DRV: if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT) rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Drv.pfnHandler, 3, Info.u.Drv.pDrvIns, pHlp, pszArgs); else Info.u.Drv.pfnHandler(Info.u.Drv.pDrvIns, pHlp, pszArgs); break; case DBGFINFOTYPE_INT: if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT) rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Int.pfnHandler, 3, pVM, pHlp, pszArgs); else Info.u.Int.pfnHandler(pVM, pHlp, pszArgs); break; case DBGFINFOTYPE_EXT: if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT) rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Ext.pfnHandler, 3, Info.u.Ext.pvUser, pHlp, pszArgs); else Info.u.Ext.pfnHandler(Info.u.Ext.pvUser, pHlp, pszArgs); break; default: AssertMsgFailedReturn(("Invalid info type enmType=%d\n", Info.enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE); } } else { rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect); AssertRC(rc); rc = VERR_FILE_NOT_FOUND; } return rc; }
/** * Stops and terminates the services. * * This should be called even when VBoxServiceStartServices fails so it can * clean up anything that we succeeded in starting. */ int VBoxServiceStopServices(void) { VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminating); /* * Signal all the services. */ for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) ASMAtomicWriteBool(&g_aServices[j].fShutdown, true); /* * Do the pfnStop callback on all running services. */ for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) if (g_aServices[j].fStarted) { VBoxServiceVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName); g_aServices[j].pDesc->pfnStop(); } /* * Wait for all the service threads to complete. */ int rc = VINF_SUCCESS; for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { if (!g_aServices[j].fEnabled) /* Only stop services which were started before. */ continue; if (g_aServices[j].Thread != NIL_RTTHREAD) { VBoxServiceVerbose(2, "Waiting for service '%s' to stop ...\n", g_aServices[j].pDesc->pszName); int rc2 = VINF_SUCCESS; for (int i = 0; i < 30; i++) /* Wait 30 seconds in total */ { rc2 = RTThreadWait(g_aServices[j].Thread, 1000 /* Wait 1 second */, NULL); if (RT_SUCCESS(rc2)) break; #ifdef RT_OS_WINDOWS /* Notify SCM that it takes a bit longer ... */ VBoxServiceWinSetStopPendingStatus(i + j*32); #endif } if (RT_FAILURE(rc2)) { VBoxServiceError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc2); rc = rc2; } } VBoxServiceVerbose(3, "Terminating service '%s' (%d) ...\n", g_aServices[j].pDesc->pszName, j); g_aServices[j].pDesc->pfnTerm(); } #ifdef RT_OS_WINDOWS /* * Wake up and tell the main() thread that we're shutting down (it's * sleeping in VBoxServiceMainWait). */ ASMAtomicWriteBool(&g_fWindowsServiceShutdown, true); if (g_hEvtWindowsService != NIL_RTSEMEVENT) { VBoxServiceVerbose(3, "Stopping the main thread...\n"); int rc2 = RTSemEventSignal(g_hEvtWindowsService); AssertRC(rc2); } #endif VBoxServiceVerbose(2, "Stopping services returning: %Rrc\n", rc); VBoxServiceReportStatus(RT_SUCCESS(rc) ? VBoxGuestFacilityStatus_Paused : VBoxGuestFacilityStatus_Failed); return rc; }
/** * Display several info items. * * This is intended used by the fatal error dump only. * * @returns * @param pVM Pointer to the VM. * @param pszIncludePat Simple string pattern of info items to include. * @param pszExcludePat Simple string pattern of info items to exclude. * @param pszSepFmt Item separator format string. The item name will be * given as parameter. * @param pHlp The output helper functions. If NULL the logger * will be used. * * @threads EMT */ VMMR3DECL(int) DBGFR3InfoMulti(PVM pVM, const char *pszIncludePat, const char *pszExcludePat, const char *pszSepFmt, PCDBGFINFOHLP pHlp) { /* * Validate input. */ VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); AssertPtrReturn(pszIncludePat, VERR_INVALID_POINTER); AssertPtrReturn(pszExcludePat, VERR_INVALID_POINTER); if (pHlp) { AssertPtrReturn(pHlp->pfnPrintf, VERR_INVALID_POINTER); AssertPtrReturn(pHlp->pfnPrintfV, VERR_INVALID_POINTER); } else pHlp = &g_dbgfR3InfoLogHlp; size_t const cchIncludePat = strlen(pszIncludePat); size_t const cchExcludePat = strlen(pszExcludePat); const char *pszArgs = ""; /* * Enumerate the info handlers and call the ones matching. * Note! We won't leave the critical section here... */ int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect); AssertRC(rc); rc = VWRN_NOT_FOUND; for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext) { if ( RTStrSimplePatternMultiMatch(pszIncludePat, cchIncludePat, pInfo->szName, pInfo->cchName, NULL) && !RTStrSimplePatternMultiMatch(pszExcludePat, cchExcludePat, pInfo->szName, pInfo->cchName, NULL)) { pHlp->pfnPrintf(pHlp, pszSepFmt, pInfo->szName); rc = VINF_SUCCESS; switch (pInfo->enmType) { case DBGFINFOTYPE_DEV: if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT) rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Dev.pfnHandler, 3, pInfo->u.Dev.pDevIns, pHlp, pszArgs); else pInfo->u.Dev.pfnHandler(pInfo->u.Dev.pDevIns, pHlp, pszArgs); break; case DBGFINFOTYPE_DRV: if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT) rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Drv.pfnHandler, 3, pInfo->u.Drv.pDrvIns, pHlp, pszArgs); else pInfo->u.Drv.pfnHandler(pInfo->u.Drv.pDrvIns, pHlp, pszArgs); break; case DBGFINFOTYPE_INT: if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT) rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Int.pfnHandler, 3, pVM, pHlp, pszArgs); else pInfo->u.Int.pfnHandler(pVM, pHlp, pszArgs); break; case DBGFINFOTYPE_EXT: if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT) rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Ext.pfnHandler, 3, pInfo->u.Ext.pvUser, pHlp, pszArgs); else pInfo->u.Ext.pfnHandler(pInfo->u.Ext.pvUser, pHlp, pszArgs); break; default: AssertMsgFailedReturn(("Invalid info type enmType=%d\n", pInfo->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE); } } } int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect); AssertRC(rc2); return rc; }
/** * Executes command from debugger. * The caller is responsible for waiting or resuming execution based on the * value returned in the *pfResumeExecution indicator. * * @returns VBox status. (clearify!) * @param pVM Pointer to the VM. * @param enmCmd The command in question. * @param pCmdData Pointer to the command data. * @param pfResumeExecution Where to store the resume execution / continue waiting indicator. */ static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution) { bool fSendEvent; bool fResume; int rc = VINF_SUCCESS; NOREF(pCmdData); /* for later */ switch (enmCmd) { /* * Halt is answered by an event say that we've halted. */ case DBGFCMD_HALT: { pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_HALT_DONE; pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM); fSendEvent = true; fResume = false; break; } /* * Resume is not answered we'll just resume execution. */ case DBGFCMD_GO: { fSendEvent = false; fResume = true; break; } /** @todo implement (and define) the rest of the commands. */ /* * Disable breakpoints and stuff. * Send an everythings cool event to the debugger thread and resume execution. */ case DBGFCMD_DETACH_DEBUGGER: { ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false); pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_DETACH_DONE; pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER; fSendEvent = true; fResume = true; break; } /* * The debugger has detached successfully. * There is no reply to this event. */ case DBGFCMD_DETACHED_DEBUGGER: { fSendEvent = false; fResume = true; break; } /* * Single step, with trace into. */ case DBGFCMD_SINGLE_STEP: { Log2(("Single step\n")); rc = VINF_EM_DBG_STEP; /** @todo SMP */ PVMCPU pVCpu = VMMGetCpu0(pVM); pVCpu->dbgf.s.fSingleSteppingRaw = true; fSendEvent = false; fResume = true; break; } /* * Default is to send an invalid command event. */ default: { pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_INVALID_COMMAND; pVM->dbgf.s.DbgEvent.enmCtx = dbgfR3FigureEventCtx(pVM); fSendEvent = true; fResume = false; break; } } /* * Send pending event. */ if (fSendEvent) { Log2(("DBGF: Emulation thread: sending event %d\n", pVM->dbgf.s.DbgEvent.enmType)); int rc2 = RTSemPing(&pVM->dbgf.s.PingPong); if (RT_FAILURE(rc2)) { AssertRC(rc2); *pfResumeExecution = true; return rc2; } } /* * Return. */ *pfResumeExecution = fResume; return rc; }
/** * Initialize a new thread, this actually creates the thread. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param ppThread Where the thread instance data handle is. * @param cbStack The stack size, see RTThreadCreate(). * @param enmType The thread type, see RTThreadCreate(). * @param pszName The thread name, see RTThreadCreate(). */ static int pdmR3ThreadInit(PVM pVM, PPPDMTHREAD ppThread, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) { PPDMTHREAD pThread = *ppThread; PUVM pUVM = pVM->pUVM; /* * Initialize the remainder of the structure. */ pThread->Internal.s.pVM = pVM; int rc = RTSemEventMultiCreate(&pThread->Internal.s.BlockEvent); if (RT_SUCCESS(rc)) { rc = RTSemEventMultiCreate(&pThread->Internal.s.SleepEvent); if (RT_SUCCESS(rc)) { /* * Create the thread and wait for it to initialize. * The newly created thread will set the PDMTHREAD::Thread member. */ RTTHREAD Thread; rc = RTThreadCreate(&Thread, pdmR3ThreadMain, pThread, cbStack, enmType, RTTHREADFLAGS_WAITABLE, pszName); if (RT_SUCCESS(rc)) { rc = RTThreadUserWait(Thread, 60*1000); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = VERR_PDM_THREAD_IPE_2; if (RT_SUCCESS(rc)) { /* * Insert it into the thread list. */ RTCritSectEnter(&pUVM->pdm.s.ListCritSect); pThread->Internal.s.pNext = NULL; if (pUVM->pdm.s.pThreadsTail) pUVM->pdm.s.pThreadsTail->Internal.s.pNext = pThread; else pUVM->pdm.s.pThreads = pThread; pUVM->pdm.s.pThreadsTail = pThread; RTCritSectLeave(&pUVM->pdm.s.ListCritSect); rc = RTThreadUserReset(Thread); AssertRC(rc); return rc; } /* bailout */ RTThreadWait(Thread, 60*1000, NULL); } RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent); pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI; } RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent); pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI; } MMHyperFree(pVM, pThread); *ppThread = NULL; return rc; }
/** @copydoc VBOXSERVICE::pfnInit */ static DECLCALLBACK(int) VBoxServiceTimeSyncInit(void) { /* * If not specified, find the right interval default. * Then create the event sem to block on. */ if (!g_TimeSyncInterval) g_TimeSyncInterval = g_DefaultInterval * 1000; if (!g_TimeSyncInterval) g_TimeSyncInterval = 10 * 1000; VbglR3GetSessionId(&g_idTimeSyncSession); /* The status code is ignored as this information is not available with VBox < 3.2.10. */ int rc = RTSemEventMultiCreate(&g_TimeSyncEvent); AssertRC(rc); #ifdef RT_OS_WINDOWS if (RT_SUCCESS(rc)) { /* * Adjust privileges of this process so we can make system time adjustments. */ if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &g_hTokenProcess)) { TOKEN_PRIVILEGES tkPriv; RT_ZERO(tkPriv); tkPriv.PrivilegeCount = 1; tkPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkPriv.Privileges[0].Luid)) { DWORD cbRet = sizeof(g_TkOldPrivileges); if (AdjustTokenPrivileges(g_hTokenProcess, FALSE, &tkPriv, sizeof(TOKEN_PRIVILEGES), &g_TkOldPrivileges, &cbRet)) rc = VINF_SUCCESS; else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VBoxServiceError("VBoxServiceTimeSyncInit: Adjusting token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); } } else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VBoxServiceError("VBoxServiceTimeSyncInit: Looking up token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); } if (RT_FAILURE(rc)) { CloseHandle(g_hTokenProcess); g_hTokenProcess = NULL; } } else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VBoxServiceError("VBoxServiceTimeSyncInit: Opening process token (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); g_hTokenProcess = NULL; } } if (GetSystemTimeAdjustment(&g_dwWinTimeAdjustment, &g_dwWinTimeIncrement, &g_bWinTimeAdjustmentDisabled)) VBoxServiceVerbose(3, "VBoxServiceTimeSyncInit: Initially %ld (100ns) units per %ld (100 ns) units interval, disabled=%d\n", g_dwWinTimeAdjustment, g_dwWinTimeIncrement, g_bWinTimeAdjustmentDisabled ? 1 : 0); else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VBoxServiceError("VBoxServiceTimeSyncInit: Could not get time adjustment values! Last error: %ld!\n", dwErr); } #endif /* RT_OS_WINDOWS */ return rc; }
/** * Destroys a PDM thread. * * This will wakeup the thread, tell it to terminate, and wait for it terminate. * * @returns VBox status code. * This reflects the success off destroying the thread and not the exit code * of the thread as this is stored in *pRcThread. * @param pThread The thread to destroy. * @param pRcThread Where to store the thread exit code. Optional. * @thread The emulation thread (EMT). */ VMMR3DECL(int) PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread) { /* * Assert sanity. */ AssertPtrReturn(pThread, VERR_INVALID_POINTER); AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC); Assert(pThread->Thread != RTThreadSelf()); AssertPtrNullReturn(pRcThread, VERR_INVALID_POINTER); PVM pVM = pThread->Internal.s.pVM; VM_ASSERT_EMT(pVM); PUVM pUVM = pVM->pUVM; /* * Advance the thread to the terminating state. */ int rc = VINF_SUCCESS; if (pThread->enmState <= PDMTHREADSTATE_TERMINATING) { for (;;) { PDMTHREADSTATE enmState = pThread->enmState; switch (enmState) { case PDMTHREADSTATE_RUNNING: if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) continue; rc = pdmR3ThreadWakeUp(pThread); break; case PDMTHREADSTATE_SUSPENDED: case PDMTHREADSTATE_SUSPENDING: case PDMTHREADSTATE_RESUMING: case PDMTHREADSTATE_INITIALIZING: if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) continue; break; case PDMTHREADSTATE_TERMINATING: case PDMTHREADSTATE_TERMINATED: break; default: AssertMsgFailed(("enmState=%d\n", enmState)); rc = VERR_PDM_THREAD_IPE_2; break; } break; } } int rc2 = RTSemEventMultiSignal(pThread->Internal.s.BlockEvent); AssertRC(rc2); /* * Wait for it to terminate and the do cleanups. */ rc2 = RTThreadWait(pThread->Thread, RT_SUCCESS(rc) ? 60*1000 : 150, pRcThread); if (RT_SUCCESS(rc2)) { /* make it invalid. */ pThread->u32Version = 0xffffffff; pThread->enmState = PDMTHREADSTATE_INVALID; pThread->Thread = NIL_RTTHREAD; /* unlink */ RTCritSectEnter(&pUVM->pdm.s.ListCritSect); if (pUVM->pdm.s.pThreads == pThread) { pUVM->pdm.s.pThreads = pThread->Internal.s.pNext; if (!pThread->Internal.s.pNext) pUVM->pdm.s.pThreadsTail = NULL; } else { PPDMTHREAD pPrev = pUVM->pdm.s.pThreads; while (pPrev && pPrev->Internal.s.pNext != pThread) pPrev = pPrev->Internal.s.pNext; Assert(pPrev); if (pPrev) pPrev->Internal.s.pNext = pThread->Internal.s.pNext; if (!pThread->Internal.s.pNext) pUVM->pdm.s.pThreadsTail = pPrev; } pThread->Internal.s.pNext = NULL; RTCritSectLeave(&pUVM->pdm.s.ListCritSect); /* free the resources */ RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent); pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI; RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent); pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI; MMR3HeapFree(pThread); } else if (RT_SUCCESS(rc)) rc = rc2; return rc; }
DECLINLINE(int) vboxPciGlobalsLock(PVBOXRAWPCIGLOBALS pGlobals) { int rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc); return rc; }
/** * The PDM thread function. * * @returns return from pfnThread. * * @param Thread The thread handle. * @param pvUser Pointer to the PDMTHREAD structure. */ static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser) { PPDMTHREAD pThread = (PPDMTHREAD)pvUser; Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread))); pThread->Thread = Thread; PUVM pUVM = pThread->Internal.s.pVM->pUVM; if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtInit) pUVM->pVmm2UserMethods->pfnNotifyPdmtInit(pUVM->pVmm2UserMethods, pUVM); /* * The run loop. * * It handles simple thread functions which returns when they see a suspending * request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning * parts to us. */ int rc; for (;;) { switch (pThread->Internal.s.enmType) { case PDMTHREADTYPE_DEVICE: rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread); break; case PDMTHREADTYPE_USB: rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread); break; case PDMTHREADTYPE_DRIVER: rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread); break; case PDMTHREADTYPE_INTERNAL: rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread); break; case PDMTHREADTYPE_EXTERNAL: rc = pThread->u.Ext.pfnThread(pThread); break; default: AssertMsgFailed(("%d\n", pThread->Internal.s.enmType)); rc = VERR_PDM_THREAD_IPE_1; break; } if (RT_FAILURE(rc)) break; /* * If this is a simple thread function, the state will be suspending * or initializing now. If it isn't we're supposed to terminate. */ if ( pThread->enmState != PDMTHREADSTATE_SUSPENDING && pThread->enmState != PDMTHREADSTATE_INITIALIZING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmSuspending(pThread); if (RT_FAILURE(rc)) break; if (pThread->enmState != PDMTHREADSTATE_RESUMING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmRunning(pThread); if (RT_FAILURE(rc)) break; } if (RT_FAILURE(rc)) LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc)); /* * Advance the state to terminating and then on to terminated. */ for (;;) { PDMTHREADSTATE enmState = pThread->enmState; if ( enmState == PDMTHREADSTATE_TERMINATING || pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) break; } ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED); int rc2 = RTThreadUserSignal(Thread); AssertRC(rc2); if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm) pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm(pUVM->pVmm2UserMethods, pUVM); Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc)); return rc; }
RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies) { LogFlow(("RTReqProcess %x\n", hQueue)); /* * Check input. */ PRTREQQUEUEINT pQueue = hQueue; AssertPtrReturn(pQueue, VERR_INVALID_HANDLE); AssertReturn(pQueue->u32Magic == RTREQQUEUE_MAGIC, VERR_INVALID_HANDLE); /* * Process loop. * * We do not repeat the outer loop if we've got an informational status code * since that code needs processing by our caller. */ int rc = VINF_SUCCESS; while (rc <= VINF_SUCCESS) { /* * Get pending requests. */ PRTREQ pReqs = ASMAtomicXchgPtrT(&pQueue->pReqs, NULL, PRTREQ); if (!pReqs) { ASMAtomicWriteBool(&pQueue->fBusy, false); /* this aint 100% perfect, but it's good enough for now... */ /** @todo We currently don't care if the entire time wasted here is larger than * cMillies */ rc = RTSemEventWait(pQueue->EventSem, cMillies); if (rc != VINF_SUCCESS) break; continue; } ASMAtomicWriteBool(&pQueue->fBusy, true); /* * Reverse the list to process it in FIFO order. */ PRTREQ pReq = pReqs; if (pReq->pNext) Log2(("RTReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext)); pReqs = NULL; while (pReq) { Assert(pReq->enmState == RTREQSTATE_QUEUED); Assert(pReq->uOwner.hQueue == pQueue); PRTREQ pCur = pReq; pReq = pReq->pNext; pCur->pNext = pReqs; pReqs = pCur; } /* * Process the requests. */ while (pReqs) { /* Unchain the first request and advance the list. */ pReq = pReqs; pReqs = pReqs->pNext; pReq->pNext = NULL; /* Process the request */ rc = rtReqProcessOne(pReq); AssertRC(rc); if (rc != VINF_SUCCESS) break; /** @todo r=bird: we're dropping requests here! Add 2nd queue that can hold them. (will fix when writing a testcase) */ } } LogFlow(("RTReqProcess: returns %Rrc\n", rc)); return rc; }
/** * Deals with the contended case in ring-3 and ring-0. * * @retval VINF_SUCCESS on success. * @retval VERR_SEM_DESTROYED if destroyed. * * @param pCritSect The critsect. * @param hNativeSelf The native thread handle. */ static int pdmR3R0CritSectEnterContended(PPDMCRITSECT pCritSect, RTNATIVETHREAD hNativeSelf, PCRTLOCKVALSRCPOS pSrcPos) { /* * Start waiting. */ if (ASMAtomicIncS32(&pCritSect->s.Core.cLockers) == 0) return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos); # ifdef IN_RING3 STAM_COUNTER_INC(&pCritSect->s.StatContentionR3); # else STAM_COUNTER_INC(&pCritSect->s.StatContentionRZLock); # endif /* * The wait loop. */ PSUPDRVSESSION pSession = pCritSect->s.CTX_SUFF(pVM)->pSession; SUPSEMEVENT hEvent = (SUPSEMEVENT)pCritSect->s.Core.EventSem; # ifdef IN_RING3 # ifdef PDMCRITSECT_STRICT RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt(); int rc2 = RTLockValidatorRecExclCheckOrder(pCritSect->s.Core.pValidatorRec, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT); if (RT_FAILURE(rc2)) return rc2; # else RTTHREAD hThreadSelf = RTThreadSelf(); # endif # endif for (;;) { /* * Do the wait. * * In ring-3 this gets cluttered by lock validation and thread state * maintainence. * * In ring-0 we have to deal with the possibility that the thread has * been signalled and the interruptible wait function returning * immediately. In that case we do normal R0/RC rcBusy handling. */ # ifdef IN_RING3 # ifdef PDMCRITSECT_STRICT int rc9 = RTLockValidatorRecExclCheckBlocking(pCritSect->s.Core.pValidatorRec, hThreadSelf, pSrcPos, !(pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NO_NESTING), RT_INDEFINITE_WAIT, RTTHREADSTATE_CRITSECT, true); if (RT_FAILURE(rc9)) return rc9; # else RTThreadBlocking(hThreadSelf, RTTHREADSTATE_CRITSECT, true); # endif int rc = SUPSemEventWaitNoResume(pSession, hEvent, RT_INDEFINITE_WAIT); RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_CRITSECT); # else /* IN_RING0 */ int rc = SUPSemEventWaitNoResume(pSession, hEvent, RT_INDEFINITE_WAIT); # endif /* IN_RING0 */ /* * Deal with the return code and critsect destruction. */ if (RT_UNLIKELY(pCritSect->s.Core.u32Magic != RTCRITSECT_MAGIC)) return VERR_SEM_DESTROYED; if (rc == VINF_SUCCESS) return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos); AssertMsg(rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc)); # ifdef IN_RING0 /* Something is pending (signal, APC, debugger, whatever), just go back to ring-3 so the kernel can deal with it when leaving kernel context. Note! We've incremented cLockers already and cannot safely decrement it without creating a race with PDMCritSectLeave, resulting in spurious wakeups. */ PVM pVM = pCritSect->s.CTX_SUFF(pVM); AssertPtr(pVM); PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu); rc = VMMRZCallRing3(pVM, pVCpu, VMMCALLRING3_VM_R0_PREEMPT, NULL); AssertRC(rc); # endif } /* won't get here */ }
/** * Construct a disk integrity driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { int rc = VINF_SUCCESS; PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY); LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); /* * Validate configuration. */ if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0" "TraceRequests\0" "CheckIntervalMs\0" "ExpireIntervalMs\0" "CheckDoubleCompletions\0" "HistorySize\0" "IoLog\0")) return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES; rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false); AssertRC(rc); rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false); AssertRC(rc); rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */ AssertRC(rc); rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */ AssertRC(rc); rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false); AssertRC(rc); rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512); AssertRC(rc); char *pszIoLogFilename = NULL; rc = CFGMR3QueryStringAlloc(pCfg, "IoLog", &pszIoLogFilename); Assert(RT_SUCCESS(rc) || rc == VERR_CFGM_VALUE_NOT_FOUND); /* * Initialize most of the data members. */ pThis->pDrvIns = pDrvIns; /* IBase. */ pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface; /* IMedia */ pThis->IMedia.pfnRead = drvdiskintRead; pThis->IMedia.pfnWrite = drvdiskintWrite; pThis->IMedia.pfnFlush = drvdiskintFlush; pThis->IMedia.pfnGetSize = drvdiskintGetSize; pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly; pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry; pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry; pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry; pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry; pThis->IMedia.pfnGetUuid = drvdiskintGetUuid; /* IMediaAsync */ pThis->IMediaAsync.pfnStartRead = drvdiskintStartRead; pThis->IMediaAsync.pfnStartWrite = drvdiskintStartWrite; pThis->IMediaAsync.pfnStartFlush = drvdiskintStartFlush; /* IMediaAsyncPort. */ pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvdiskintAsyncTransferCompleteNotify; /* IMediaPort. */ pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation; /* Query the media port interface above us. */ pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT); if (!pThis->pDrvMediaPort) return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, N_("No media port inrerface above")); /* Try to attach async media port interface above.*/ pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT); /* * Try attach driver below and query it's media interface. */ PPDMIBASE pBase; rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Failed to attach driver below us! %Rrc"), rc); pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA); if (!pThis->pDrvMedia) return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, N_("No media or async media interface below")); pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC); if (pThis->pDrvMedia->pfnDiscard) pThis->IMedia.pfnDiscard = drvdiskintDiscard; if (pThis->fCheckConsistency) { /* Create the AVL tree. */ pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE)); if (!pThis->pTreeSegments) rc = VERR_NO_MEMORY; } if (pThis->fTraceRequests) { for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++) { pThis->apReqActive[i].pIoReq = NULL; pThis->apReqActive[i].tsStart = 0; } pThis->iNextFreeSlot = 0; /* Init event semaphore. */ rc = RTSemEventCreate(&pThis->SemEvent); AssertRC(rc); pThis->fRunning = true; rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis, 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity"); AssertRC(rc); } if (pThis->fCheckDoubleCompletion) { pThis->iEntry = 0; pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ)); AssertPtr(pThis->papIoReq); } if (pszIoLogFilename) { rc = VDDbgIoLogCreate(&pThis->hIoLogger, pszIoLogFilename, VDDBG_IOLOG_LOG_DATA); MMR3HeapFree(pszIoLogFilename); } return rc; }
/** * Initializes the COM runtime. * * This method must be called on each thread of the client application that * wants to access COM facilities. The initialization must be performed before * calling any other COM method or attempting to instantiate COM objects. * * On platforms using XPCOM, this method uses the following scheme to search for * XPCOM runtime: * * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies * is used to search XPCOM libraries and components. If this method fails to * initialize XPCOM runtime using this path, it will immediately return a * failure and will NOT check for other paths as described below. * * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the * given order: * * a) Compiled-in application data directory (as returned by * RTPathAppPrivateArch()) * b) "/usr/lib/virtualbox" (Linux only) * c) "/opt/VirtualBox" (Linux only) * * The first path for which the initialization succeeds will be used. * * On MS COM platforms, the COM runtime is provided by the system and does not * need to be searched for. * * Once the COM subsystem is no longer necessary on a given thread, Shutdown() * must be called to free resources allocated for it. Note that a thread may * call Initialize() several times but for each of tese calls there must be a * corresponding Shutdown() call. * * @return S_OK on success and a COM result code in case of failure. */ HRESULT Initialize(bool fGui) { HRESULT rc = E_FAIL; #if !defined(VBOX_WITH_XPCOM) /* * We initialize COM in GUI thread in STA, to be compliant with QT and * OLE requirments (for example to allow D&D), while other threads * initialized in regular MTA. To allow fast proxyless access from * GUI thread to COM objects, we explicitly provide our COM objects * with free threaded marshaller. * !!!!! Please think twice before touching this code !!!!! */ DWORD flags = fGui ? COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY : COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY; rc = CoInitializeEx(NULL, flags); /* the overall result must be either S_OK or S_FALSE (S_FALSE means * "already initialized using the same apartment model") */ AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc)); /* To be flow compatible with the XPCOM case, we return here if this isn't * the main thread or if it isn't its first initialization call. * Note! CoInitializeEx and CoUninitialize does it's own reference * counting, so this exercise is entirely for the EventQueue init. */ bool fRc; RTTHREAD hSelf = RTThreadSelf(); if (hSelf != NIL_RTTHREAD) ASMAtomicCmpXchgHandle(&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc); else fRc = false; if (fGui) Assert(RTThreadIsMain(hSelf)); if (!fRc) { if ( gCOMMainThread == hSelf && SUCCEEDED(rc)) gCOMMainInitCount++; AssertComRC(rc); return rc; } Assert(RTThreadIsMain(hSelf)); /* this is the first main thread initialization */ Assert(gCOMMainInitCount == 0); if (SUCCEEDED(rc)) gCOMMainInitCount = 1; #else /* !defined (VBOX_WITH_XPCOM) */ /* Unused here */ NOREF(fGui); if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true) { /* XPCOM is already initialized on the main thread, no special * initialization is necessary on additional threads. Just increase * the init counter if it's a main thread again (to correctly support * nested calls to Initialize()/Shutdown() for compatibility with * Win32). */ nsCOMPtr<nsIEventQueue> eventQ; rc = NS_GetMainEventQ(getter_AddRefs(eventQ)); if (NS_SUCCEEDED(rc)) { PRBool isOnMainThread = PR_FALSE; rc = eventQ->IsOnCurrentThread(&isOnMainThread); if (NS_SUCCEEDED(rc) && isOnMainThread) ++gXPCOMInitCount; } AssertComRC(rc); return rc; } Assert(RTThreadIsMain(RTThreadSelf())); /* this is the first initialization */ gXPCOMInitCount = 1; bool const fInitEventQueues = true; /* prepare paths for registry files */ char szCompReg[RTPATH_MAX]; char szXptiDat[RTPATH_MAX]; int vrc = GetVBoxUserHomeDirectory(szCompReg, sizeof(szCompReg)); if (vrc == VERR_ACCESS_DENIED) return NS_ERROR_FILE_ACCESS_DENIED; AssertRCReturn(vrc, NS_ERROR_FAILURE); strcpy(szXptiDat, szCompReg); vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat"); AssertRCReturn(vrc, NS_ERROR_FAILURE); vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat"); AssertRCReturn(vrc, NS_ERROR_FAILURE); LogFlowFunc(("component registry : \"%s\"\n", szCompReg)); LogFlowFunc(("XPTI data file : \"%s\"\n", szXptiDat)); #if defined (XPCOM_GLUE) XPCOMGlueStartup(nsnull); #endif static const char *kAppPathsToProbe[] = { NULL, /* 0: will use VBOX_APP_HOME */ NULL, /* 1: will try RTPathAppPrivateArch() */ #ifdef RT_OS_LINUX "/usr/lib/virtualbox", "/opt/VirtualBox", #elif RT_OS_SOLARIS "/opt/VirtualBox/amd64", "/opt/VirtualBox/i386", #elif RT_OS_DARWIN "/Application/VirtualBox.app/Contents/MacOS", #endif }; /* Find out the directory where VirtualBox binaries are located */ for (size_t i = 0; i < RT_ELEMENTS(kAppPathsToProbe); ++ i) { char szAppHomeDir[RTPATH_MAX]; if (i == 0) { /* Use VBOX_APP_HOME if present */ vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_APP_HOME", szAppHomeDir, sizeof(szAppHomeDir), NULL); if (vrc == VERR_ENV_VAR_NOT_FOUND) continue; AssertRC(vrc); } else if (i == 1) { /* Use RTPathAppPrivateArch() first */ vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir)); AssertRC(vrc); } else { /* Iterate over all other paths */ szAppHomeDir[RTPATH_MAX - 1] = '\0'; strncpy(szAppHomeDir, kAppPathsToProbe[i], RTPATH_MAX - 1); vrc = VINF_SUCCESS; } if (RT_FAILURE(vrc)) { rc = NS_ERROR_FAILURE; continue; } char szCompDir[RTPATH_MAX]; vrc = RTPathAppend(strcpy(szCompDir, szAppHomeDir), sizeof(szCompDir), "components"); if (RT_FAILURE(vrc)) { rc = NS_ERROR_FAILURE; continue; } LogFlowFunc(("component directory : \"%s\"\n", szCompDir)); nsCOMPtr<DirectoryServiceProvider> dsProv; dsProv = new DirectoryServiceProvider(); if (dsProv) rc = dsProv->init(szCompReg, szXptiDat, szCompDir, szAppHomeDir); else rc = NS_ERROR_OUT_OF_MEMORY; if (NS_FAILED(rc)) break; /* Setup the application path for NS_InitXPCOM2. Note that we properly * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory * service provider but it seems to be activated after the directory * service is used for the first time (see the source NS_InitXPCOM2). So * use the same value here to be on the safe side. */ nsCOMPtr <nsIFile> appDir; { char *appDirCP = NULL; vrc = RTStrUtf8ToCurrentCP(&appDirCP, szAppHomeDir); if (RT_SUCCESS(vrc)) { nsCOMPtr<nsILocalFile> file; rc = NS_NewNativeLocalFile(nsEmbedCString(appDirCP), PR_FALSE, getter_AddRefs(file)); if (NS_SUCCEEDED(rc)) appDir = do_QueryInterface(file, &rc); RTStrFree(appDirCP); } else rc = NS_ERROR_FAILURE; } if (NS_FAILED(rc)) break; /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that * still use it instead of the directory service happy */ vrc = RTEnvSetEx(RTENV_DEFAULT, "VBOX_XPCOM_HOME", szAppHomeDir); AssertRC(vrc); /* Finally, initialize XPCOM */ { nsCOMPtr<nsIServiceManager> serviceManager; rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), appDir, dsProv); if (NS_SUCCEEDED(rc)) { nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager, &rc); if (NS_SUCCEEDED(rc)) { rc = registrar->AutoRegister(nsnull); if (NS_SUCCEEDED(rc)) { /* We succeeded, stop probing paths */ LogFlowFunc(("Succeeded.\n")); break; } } } } /* clean up before the new try */ rc = NS_ShutdownXPCOM(nsnull); if (i == 0) { /* We failed with VBOX_APP_HOME, don't probe other paths */ break; } } #endif /* !defined (VBOX_WITH_XPCOM) */ // for both COM and XPCOM, we only get here if this is the main thread; // only then initialize the autolock system (AutoLock.cpp) Assert(RTThreadIsMain(RTThreadSelf())); util::InitAutoLockSystem(); AssertComRC(rc); /* * Init the main event queue (ASSUMES it cannot fail). */ if (SUCCEEDED(rc)) EventQueue::init(); return rc; }