diff options
Diffstat (limited to 'src/VBox/HostDrivers/Support/SUPDrv.c')
-rw-r--r-- | src/VBox/HostDrivers/Support/SUPDrv.c | 464 |
1 files changed, 360 insertions, 104 deletions
diff --git a/src/VBox/HostDrivers/Support/SUPDrv.c b/src/VBox/HostDrivers/Support/SUPDrv.c index 2f07360e..580e318d 100644 --- a/src/VBox/HostDrivers/Support/SUPDrv.c +++ b/src/VBox/HostDrivers/Support/SUPDrv.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -59,8 +59,8 @@ #include <VBox/param.h> #include <VBox/log.h> #include <VBox/err.h> -#include <VBox/vmm/hwacc_svm.h> -#include <VBox/vmm/hwacc_vmx.h> +#include <VBox/vmm/hm_svm.h> +#include <VBox/vmm/hm_vmx.h> #if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN) # include "dtrace/SUPDrv.h" @@ -137,6 +137,7 @@ static void supdrvGipUpdate(PSUPDRVDEVEXT pDevExt, uint64_t u64N static void supdrvGipUpdatePerCpu(PSUPDRVDEVEXT pDevExt, uint64_t u64NanoTS, uint64_t u64TSC, RTCPUID idCpu, uint8_t idApic, uint64_t iTick); static void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS); +static int supdrvIOCtl_ResumeSuspendedKbds(void); /******************************************************************************* @@ -172,6 +173,8 @@ static SUPFUNC g_aFunctions[] = { "SUPR0ContAlloc", (void *)SUPR0ContAlloc }, { "SUPR0ContFree", (void *)SUPR0ContFree }, { "SUPR0EnableVTx", (void *)SUPR0EnableVTx }, + { "SUPR0SuspendVTxOnCpu", (void *)SUPR0SuspendVTxOnCpu }, + { "SUPR0ResumeVTxOnCpu", (void *)SUPR0ResumeVTxOnCpu }, { "SUPR0GetPagingMode", (void *)SUPR0GetPagingMode }, { "SUPR0LockMem", (void *)SUPR0LockMem }, { "SUPR0LowAlloc", (void *)SUPR0LowAlloc }, @@ -233,6 +236,7 @@ static SUPFUNC g_aFunctions[] = { "RTHandleTableFreeWithCtx", (void *)RTHandleTableFreeWithCtx }, { "RTHandleTableLookupWithCtx", (void *)RTHandleTableLookupWithCtx }, { "RTLogDefaultInstance", (void *)RTLogDefaultInstance }, + { "RTLogGetDefaultInstance", (void *)RTLogGetDefaultInstance }, { "RTLogLoggerExV", (void *)RTLogLoggerExV }, { "RTLogPrintfV", (void *)RTLogPrintfV }, { "RTLogRelDefaultInstance", (void *)RTLogRelDefaultInstance }, @@ -363,6 +367,12 @@ static SUPFUNC g_aFunctions[] = { "RTStrPrintfExV", (void *)RTStrPrintfExV }, { "RTStrPrintfV", (void *)RTStrPrintfV }, { "RTThreadCreate", (void *)RTThreadCreate }, + { "RTThreadCtxHooksAreRegistered", (void *)RTThreadCtxHooksAreRegistered }, + { "RTThreadCtxHooksCreate", (void *)RTThreadCtxHooksCreate }, + { "RTThreadCtxHooksDeregister", (void *)RTThreadCtxHooksDeregister }, + { "RTThreadCtxHooksRegister", (void *)RTThreadCtxHooksRegister }, + { "RTThreadCtxHooksRelease", (void *)RTThreadCtxHooksRelease }, + { "RTThreadCtxHooksRetain", (void *)RTThreadCtxHooksRetain }, { "RTThreadGetName", (void *)RTThreadGetName }, { "RTThreadGetNative", (void *)RTThreadGetNative }, { "RTThreadGetType", (void *)RTThreadGetType }, @@ -453,7 +463,7 @@ int VBOXCALL supdrvInitDevExt(PSUPDRVDEVEXT pDevExt, size_t cbSession) * Initialize it. */ memset(pDevExt, 0, sizeof(*pDevExt)); - rc = RTSpinlockCreate(&pDevExt->Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "SUPDrvDevExt"); + rc = RTSpinlockCreate(&pDevExt->Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "SUPDrvDevExt"); if (RT_SUCCESS(rc)) { rc = RTSpinlockCreate(&pDevExt->hGipSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "SUPDrvGip"); @@ -654,17 +664,25 @@ void VBOXCALL supdrvDeleteDevExt(PSUPDRVDEVEXT pDevExt) * Create session. * * @returns IPRT status code. - * @param pDevExt Device extension. - * @param fUser Flag indicating whether this is a user or kernel session. - * @param ppSession Where to store the pointer to the session data. + * @param pDevExt Device extension. + * @param fUser Flag indicating whether this is a user or kernel + * session. + * @param fUnrestricted Unrestricted access (system) or restricted access + * (user)? + * @param ppSession Where to store the pointer to the session data. */ -int VBOXCALL supdrvCreateSession(PSUPDRVDEVEXT pDevExt, bool fUser, PSUPDRVSESSION *ppSession) +int VBOXCALL supdrvCreateSession(PSUPDRVDEVEXT pDevExt, bool fUser, bool fUnrestricted, PSUPDRVSESSION *ppSession) { + int rc; + PSUPDRVSESSION pSession; + + if (!SUP_IS_DEVEXT_VALID(pDevExt)) + return VERR_INVALID_PARAMETER; + /* * Allocate memory for the session data. */ - int rc; - PSUPDRVSESSION pSession = *ppSession = (PSUPDRVSESSION)RTMemAllocZ(pDevExt->cbSession); + pSession = *ppSession = (PSUPDRVSESSION)RTMemAllocZ(pDevExt->cbSession); if (pSession) { /* Initialize session data. */ @@ -672,13 +690,15 @@ int VBOXCALL supdrvCreateSession(PSUPDRVDEVEXT pDevExt, bool fUser, PSUPDRVSESSI if (!rc) { rc = RTHandleTableCreateEx(&pSession->hHandleTable, - RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT, + RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE | RTHANDLETABLE_FLAGS_CONTEXT, 1 /*uBase*/, 32768 /*cMax*/, supdrvSessionObjHandleRetain, pSession); if (RT_SUCCESS(rc)) { Assert(pSession->Spinlock != NIL_RTSPINLOCK); pSession->pDevExt = pDevExt; pSession->u32Cookie = BIRD_INV; + pSession->fUnrestricted = fUnrestricted; + pSession->cRefs = 1; /*pSession->pLdrUsage = NULL; pSession->pVM = NULL; pSession->pUsage = NULL; @@ -724,33 +744,6 @@ int VBOXCALL supdrvCreateSession(PSUPDRVDEVEXT pDevExt, bool fUser, PSUPDRVSESSI /** - * Shared code for cleaning up a session. - * - * @param pDevExt Device extension. - * @param pSession Session data. - * This data will be freed by this routine. - */ -void VBOXCALL supdrvCloseSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession) -{ - VBOXDRV_SESSION_CLOSE(pSession); - - /* - * Cleanup the session first. - */ - supdrvCleanupSession(pDevExt, pSession); - - /* - * Free the rest of the session stuff. - */ - RTSpinlockDestroy(pSession->Spinlock); - pSession->Spinlock = NIL_RTSPINLOCK; - pSession->pDevExt = NULL; - RTMemFree(pSession); - LogFlow(("supdrvCloseSession: returns\n")); -} - - -/** * Shared code for cleaning up a session (but not quite freeing it). * * This is primarily intended for MAC OS X where we have to clean up the memory @@ -760,7 +753,7 @@ void VBOXCALL supdrvCloseSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession) * @param pSession Session data. * This data will be freed by this routine. */ -void VBOXCALL supdrvCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession) +static void supdrvCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession) { int rc; PSUPDRVBUNDLE pBundle; @@ -969,6 +962,71 @@ void VBOXCALL supdrvCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSessio /** + * Shared code for cleaning up a session. + * + * @param pDevExt Device extension. + * @param pSession Session data. + * This data will be freed by this routine. + */ +static void supdrvCloseSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession) +{ + VBOXDRV_SESSION_CLOSE(pSession); + + /* + * Cleanup the session first. + */ + supdrvCleanupSession(pDevExt, pSession); + + /* + * Free the rest of the session stuff. + */ + RTSpinlockDestroy(pSession->Spinlock); + pSession->Spinlock = NIL_RTSPINLOCK; + pSession->pDevExt = NULL; + RTMemFree(pSession); + LogFlow(("supdrvCloseSession: returns\n")); +} + + +/** + * Retain a session to make sure it doesn't go away while it is in use. + * + * @returns New reference count on success, UINT32_MAX on failure. + * @param pSession Session data. + */ +uint32_t VBOXCALL supdrvSessionRetain(PSUPDRVSESSION pSession) +{ + uint32_t cRefs; + AssertPtrReturn(pSession, UINT32_MAX); + AssertReturn(SUP_IS_SESSION_VALID(pSession), UINT32_MAX); + + cRefs = ASMAtomicIncU32(&pSession->cRefs); + AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pSession)); + return cRefs; +} + + +/** + * Releases a given session. + * + * @returns New reference count on success (0 if closed), UINT32_MAX on failure. + * @param pSession Session data. + */ +uint32_t VBOXCALL supdrvSessionRelease(PSUPDRVSESSION pSession) +{ + uint32_t cRefs; + AssertPtrReturn(pSession, UINT32_MAX); + AssertReturn(SUP_IS_SESSION_VALID(pSession), UINT32_MAX); + + cRefs = ASMAtomicDecU32(&pSession->cRefs); + AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pSession)); + if (cRefs == 0) + supdrvCloseSession(pSession->pDevExt, pSession); + return cRefs; +} + + +/** * RTHandleTableDestroy callback used by supdrvCleanupSession. * * @returns IPRT status code, see SUPR0ObjAddRef. @@ -1026,8 +1084,8 @@ int VBOXCALL supdrvIOCtlFast(uintptr_t uIOCtl, VMCPUID idCpu, PSUPDRVDEVEXT pDev case SUP_IOCTL_FAST_DO_RAW_RUN: pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_RAW_RUN); break; - case SUP_IOCTL_FAST_DO_HWACC_RUN: - pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_HWACC_RUN); + case SUP_IOCTL_FAST_DO_HM_RUN: + pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_HM_RUN); break; case SUP_IOCTL_FAST_DO_NOP: pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_NOP); @@ -1078,7 +1136,7 @@ static int supdrvCheckInvalidChar(const char *pszStr, const char *pszChars) * @param pSession Session data. * @param pReqHdr The request header. */ -static int supdrvIOCtlInner(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPREQHDR pReqHdr) +static int supdrvIOCtlInnerUnrestricted(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPREQHDR pReqHdr) { /* * Validation macros @@ -1755,7 +1813,6 @@ static int supdrvIOCtlInner(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESS /* validate */ PSUPVTCAPS pReq = (PSUPVTCAPS)pReqHdr; REQ_CHECK_SIZES(SUP_IOCTL_VT_CAPS); - REQ_CHECK_EXPR(SUP_IOCTL_VT_CAPS, pReq->Hdr.cbIn <= SUP_IOCTL_VT_CAPS_SIZE_IN); /* execute */ pReq->Hdr.rc = SUPR0QueryVTCaps(pSession, &pReq->u.Out.Caps); @@ -1834,6 +1891,100 @@ static int supdrvIOCtlInner(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESS return 0; } + case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_RESUME_SUSPENDED_KBDS): + { + /* validate */ + REQ_CHECK_SIZES(SUP_IOCTL_RESUME_SUSPENDED_KBDS); + + pReqHdr->rc = supdrvIOCtl_ResumeSuspendedKbds(); + return 0; + } + + default: + Log(("Unknown IOCTL %#lx\n", (long)uIOCtl)); + break; + } + return VERR_GENERAL_FAILURE; +} + + +/** + * I/O Control inner worker for the restricted operations. + * + * @returns IPRT status code. + * @retval VERR_INVALID_PARAMETER if the request is invalid. + * + * @param uIOCtl Function number. + * @param pDevExt Device extention. + * @param pSession Session data. + * @param pReqHdr The request header. + */ +static int supdrvIOCtlInnerRestricted(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPREQHDR pReqHdr) +{ + /* + * The switch. + */ + switch (SUP_CTL_CODE_NO_SIZE(uIOCtl)) + { + case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_COOKIE): + { + PSUPCOOKIE pReq = (PSUPCOOKIE)pReqHdr; + REQ_CHECK_SIZES(SUP_IOCTL_COOKIE); + if (strncmp(pReq->u.In.szMagic, SUPCOOKIE_MAGIC, sizeof(pReq->u.In.szMagic))) + { + OSDBGPRINT(("SUP_IOCTL_COOKIE: invalid magic %.16s\n", pReq->u.In.szMagic)); + pReq->Hdr.rc = VERR_INVALID_MAGIC; + return 0; + } + + /* + * Match the version. + * The current logic is very simple, match the major interface version. + */ + if ( pReq->u.In.u32MinVersion > SUPDRV_IOC_VERSION + || (pReq->u.In.u32MinVersion & 0xffff0000) != (SUPDRV_IOC_VERSION & 0xffff0000)) + { + OSDBGPRINT(("SUP_IOCTL_COOKIE: Version mismatch. Requested: %#x Min: %#x Current: %#x\n", + pReq->u.In.u32ReqVersion, pReq->u.In.u32MinVersion, SUPDRV_IOC_VERSION)); + pReq->u.Out.u32Cookie = 0xffffffff; + pReq->u.Out.u32SessionCookie = 0xffffffff; + pReq->u.Out.u32SessionVersion = 0xffffffff; + pReq->u.Out.u32DriverVersion = SUPDRV_IOC_VERSION; + pReq->u.Out.pSession = NULL; + pReq->u.Out.cFunctions = 0; + pReq->Hdr.rc = VERR_VERSION_MISMATCH; + return 0; + } + + /* + * Fill in return data and be gone. + * N.B. The first one to change SUPDRV_IOC_VERSION shall makes sure that + * u32SessionVersion <= u32ReqVersion! + */ + /** @todo Somehow validate the client and negotiate a secure cookie... */ + pReq->u.Out.u32Cookie = pDevExt->u32Cookie; + pReq->u.Out.u32SessionCookie = pSession->u32Cookie; + pReq->u.Out.u32SessionVersion = SUPDRV_IOC_VERSION; + pReq->u.Out.u32DriverVersion = SUPDRV_IOC_VERSION; + pReq->u.Out.pSession = pSession; + pReq->u.Out.cFunctions = 0; + pReq->Hdr.rc = VINF_SUCCESS; + return 0; + } + + case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_VT_CAPS): + { + /* validate */ + PSUPVTCAPS pReq = (PSUPVTCAPS)pReqHdr; + REQ_CHECK_SIZES(SUP_IOCTL_VT_CAPS); + + /* execute */ + pReq->Hdr.rc = SUPR0QueryVTCaps(pSession, &pReq->u.Out.Caps); + if (RT_FAILURE(pReq->Hdr.rc)) + pReq->Hdr.cbOut = sizeof(pReq->Hdr); + return 0; + } + default: Log(("Unknown IOCTL %#lx\n", (long)uIOCtl)); break; @@ -1895,9 +2046,12 @@ int VBOXCALL supdrvIOCtl(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION } /* - * Hand it to an inner function to avoid lots of unnecessary return tracepoints + * Hand it to an inner function to avoid lots of unnecessary return tracepoints. */ - rc = supdrvIOCtlInner(uIOCtl, pDevExt, pSession, pReqHdr); + if (pSession->fUnrestricted) + rc = supdrvIOCtlInnerUnrestricted(uIOCtl, pDevExt, pSession, pReqHdr); + else + rc = supdrvIOCtlInnerRestricted(uIOCtl, pDevExt, pSession, pReqHdr); VBOXDRV_IOCTL_RETURN(pSession, uIOCtl, pReqHdr, pReqHdr->rc, rc); return rc; @@ -1999,7 +2153,7 @@ int VBOXCALL supdrvIDC(uintptr_t uReq, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSe pReq->u.Out.uDriverVersion = SUPDRV_IDC_VERSION; pReq->u.Out.uDriverRevision = VBOX_SVN_REV; - pReq->Hdr.rc = supdrvCreateSession(pDevExt, false /* fUser */, &pSession); + pReq->Hdr.rc = supdrvCreateSession(pDevExt, false /* fUser */, true /*fUnrestricted*/, &pSession); if (RT_FAILURE(pReq->Hdr.rc)) { OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: failed to create session, rc=%d\n", pReq->Hdr.rc)); @@ -2016,7 +2170,7 @@ int VBOXCALL supdrvIDC(uintptr_t uReq, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSe { REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_DISCONNECT, sizeof(*pReqHdr)); - supdrvCloseSession(pDevExt, pSession); + supdrvSessionRelease(pSession); return pReqHdr->rc = VINF_SUCCESS; } @@ -3187,9 +3341,61 @@ SUPR0DECL(int) SUPR0EnableVTx(bool fEnable) } -/** @todo document me */ +/** + * Suspends hardware virtualization extensions using the native OS API. + * + * This is called prior to entering raw-mode context. + * + * @returns @c true if suspended, @c false if not. + */ +SUPR0DECL(bool) SUPR0SuspendVTxOnCpu(void) +{ +#ifdef RT_OS_DARWIN + return supdrvOSSuspendVTxOnCpu(); +#else + return false; +#endif +} + + +/** + * Resumes hardware virtualization extensions using the native OS API. + * + * This is called after to entering raw-mode context. + * + * @param fSuspended The return value of SUPR0SuspendVTxOnCpu. + */ +SUPR0DECL(void) SUPR0ResumeVTxOnCpu(bool fSuspended) +{ +#ifdef RT_OS_DARWIN + supdrvOSResumeVTxOnCpu(fSuspended); +#else + Assert(!fSuspended); +#endif +} + + +/** + * Queries the AMD-V and VT-x capabilities of the calling CPU. + * + * @returns VBox status code. + * @retval VERR_VMX_NO_VMX + * @retval VERR_VMX_MSR_SMX_VMXON_DISABLED + * @retval VERR_VMX_MSR_VMXON_DISABLED + * @retval VERR_VMX_MSR_LOCKING_FAILED + * @retval VERR_SVM_NO_SVM + * @retval VERR_SVM_DISABLED + * @retval VERR_UNSUPPORTED_CPU if not identifiable as an AMD, Intel or VIA + * (centaur) CPU. + * + * @param pSession The session handle. + * @param pfCaps Where to store the capabilities. + */ SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps) { + int rc = VERR_UNSUPPORTED_CPU; + RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER; + /* * Input validation. */ @@ -3197,39 +3403,72 @@ SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps) AssertPtrReturn(pfCaps, VERR_INVALID_POINTER); *pfCaps = 0; - + /* We may modify MSRs and re-read them, disable preemption so we make sure we don't migrate CPUs. */ + RTThreadPreemptDisable(&PreemptState); if (ASMHasCpuId()) { - uint32_t u32FeaturesECX; - uint32_t u32Dummy; - uint32_t u32FeaturesEDX; - uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX; - uint64_t val; - - ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX); - ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX); - /* Query AMD features. */ - ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX); - - if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX - && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX - && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX + uint32_t fFeaturesECX, fFeaturesEDX, uDummy; + uint32_t uMaxId, uVendorEBX, uVendorECX, uVendorEDX; + uint64_t u64FeatMsr; + + ASMCpuId(0, &uMaxId, &uVendorEBX, &uVendorECX, &uVendorEDX); + ASMCpuId(1, &uDummy, &uDummy, &fFeaturesECX, &fFeaturesEDX); + + if ( ASMIsValidStdRange(uMaxId) + && ( ASMIsIntelCpuEx( uVendorEBX, uVendorECX, uVendorEDX) + || ASMIsViaCentaurCpuEx(uVendorEBX, uVendorECX, uVendorEDX) ) ) { - if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR) + if ( (fFeaturesECX & X86_CPUID_FEATURE_ECX_VMX) + && (fFeaturesEDX & X86_CPUID_FEATURE_EDX_MSR) + && (fFeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR) ) { - val = ASMRdMsr(MSR_IA32_FEATURE_CONTROL); - /* - * Both the LOCK and VMXON bit must be set; otherwise VMXON will generate a #GP. - * Once the lock bit is set, this MSR can no longer be modified. - */ - if ( (val & (MSR_IA32_FEATURE_CONTROL_VMXON|MSR_IA32_FEATURE_CONTROL_LOCK)) - == (MSR_IA32_FEATURE_CONTROL_VMXON|MSR_IA32_FEATURE_CONTROL_LOCK) /* enabled and locked */ - || !(val & MSR_IA32_FEATURE_CONTROL_LOCK) /* not enabled, but not locked either */ - ) + /** @todo Unify code with hmR0InitIntelCpu(). */ + uint64_t u64FeatMsr = ASMRdMsr(MSR_IA32_FEATURE_CONTROL); + bool const fInSmxMode = RT_BOOL(ASMGetCR4() & X86_CR4_SMXE); + bool fMsrLocked = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_LOCK); + bool fSmxVmxAllowed = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_SMX_VMXON); + bool fVmxAllowed = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_VMXON); + + /* Check if the LOCK bit is set but excludes the required VMXON bit. */ + if (fMsrLocked) + { + if (fInSmxMode && !fSmxVmxAllowed) + rc = VERR_VMX_MSR_SMX_VMXON_DISABLED; + else if (!fInSmxMode && !fVmxAllowed) + rc = VERR_VMX_MSR_VMXON_DISABLED; + else + rc = VINF_SUCCESS; + } + else + { + /* + * MSR is not yet locked; we can change it ourselves here. + * Once the lock bit is set, this MSR can no longer be modified. + */ + bool fAllowed; + u64FeatMsr |= MSR_IA32_FEATURE_CONTROL_LOCK; + if (fInSmxMode) + u64FeatMsr |= MSR_IA32_FEATURE_CONTROL_SMX_VMXON; + else + u64FeatMsr |= MSR_IA32_FEATURE_CONTROL_VMXON; + + ASMWrMsr(MSR_IA32_FEATURE_CONTROL, u64FeatMsr); + + /* Verify. */ + u64FeatMsr = ASMRdMsr(MSR_IA32_FEATURE_CONTROL); + fMsrLocked = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_LOCK); + fSmxVmxAllowed = fMsrLocked && RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_SMX_VMXON); + fVmxAllowed = fMsrLocked && RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_VMXON); + fAllowed = fInSmxMode ? fSmxVmxAllowed : fVmxAllowed; + if (fAllowed) + rc = VINF_SUCCESS; + else + rc = VERR_VMX_MSR_LOCKING_FAILED; + } + + if (rc == VINF_SUCCESS) { VMX_CAPABILITY vtCaps; @@ -3242,44 +3481,48 @@ SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps) if (vtCaps.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_EPT) *pfCaps |= SUPVTCAPS_NESTED_PAGING; } - return VINF_SUCCESS; } - return VERR_VMX_MSR_LOCKED_OR_DISABLED; } - return VERR_VMX_NO_VMX; + else + rc = VERR_VMX_NO_VMX; } - - if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX - && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX - && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX - ) + else if ( ASMIsAmdCpuEx(uVendorEBX, uVendorECX, uVendorEDX) + && ASMIsValidStdRange(uMaxId)) { - if ( (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR) - && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR) + uint32_t fExtFeaturesEcx, uExtMaxId; + ASMCpuId(0x80000000, &uExtMaxId, &uDummy, &uDummy, &uDummy); + ASMCpuId(0x80000001, &uDummy, &uDummy, &fExtFeaturesEcx, &uDummy); + if ( ASMIsValidExtRange(uExtMaxId) + && uExtMaxId >= 0x8000000a + && (fExtFeaturesEcx & X86_CPUID_AMD_FEATURE_ECX_SVM) + && (fFeaturesEDX & X86_CPUID_FEATURE_EDX_MSR) + && (fFeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR) ) { /* Check if SVM is disabled */ - val = ASMRdMsr(MSR_K8_VM_CR); - if (!(val & MSR_K8_VM_CR_SVM_DISABLE)) + u64FeatMsr = ASMRdMsr(MSR_K8_VM_CR); + if (!(u64FeatMsr & MSR_K8_VM_CR_SVM_DISABLE)) { + uint32_t fSvmFeatures; *pfCaps |= SUPVTCAPS_AMD_V; - /* Query AMD features. */ - ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32FeaturesEDX); - - if (u32FeaturesEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING) + /* Query AMD-V features. */ + ASMCpuId(0x8000000a, &uDummy, &uDummy, &uDummy, &fSvmFeatures); + if (fSvmFeatures & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING) *pfCaps |= SUPVTCAPS_NESTED_PAGING; - return VINF_SUCCESS; + rc = VINF_SUCCESS; } - return VERR_SVM_DISABLED; + else + rc = VERR_SVM_DISABLED; } - return VERR_SVM_NO_SVM; + else + rc = VERR_SVM_NO_SVM; } } - return VERR_UNSUPPORTED_CPU; + RTThreadPreemptRestore(&PreemptState); + return rc; } @@ -4719,7 +4962,7 @@ DECLINLINE(int) supdrvLdrUnlock(PSUPDRVDEVEXT pDevExt) */ static int supdrvIOCtl_CallServiceModule(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPCALLSERVICE pReq) { -#if !defined(RT_OS_WINDOWS) || defined(DEBUG) +#if !defined(RT_OS_WINDOWS) || defined(RT_ARCH_AMD64) || defined(DEBUG) int rc; /* @@ -4764,9 +5007,9 @@ static int supdrvIOCtl_CallServiceModule(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION p Log4(("SUP_IOCTL_CALL_SERVICE: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n", rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf())); return rc; -#else /* RT_OS_WINDOWS && !DEBUG */ +#else /* RT_OS_WINDOWS && !RT_ARCH_AMD64 && !DEBUG */ return VERR_NOT_IMPLEMENTED; -#endif /* RT_OS_WINDOWS && !DEBUG */ +#endif /* RT_OS_WINDOWS && !RT_ARCH_AMD64 && !DEBUG */ } @@ -4973,7 +5216,7 @@ static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt) } } if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) - rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0, supdrvGipSyncTimer, pDevExt); + rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, supdrvGipSyncTimer, pDevExt); if (RT_SUCCESS(rc)) { rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt); @@ -5440,10 +5683,8 @@ static SUPGIPMODE supdrvGipDeterminTscMode(PSUPDRVDEVEXT pDevExt) */ /* Check for "AuthenticAMD" */ ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX); - if ( uEAX >= 1 - && uEBX == X86_CPUID_VENDOR_AMD_EBX - && uECX == X86_CPUID_VENDOR_AMD_ECX - && uEDX == X86_CPUID_VENDOR_AMD_EDX) + if ( uEAX >= 1 + && ASMIsAmdCpuEx(uEBX, uECX, uEDX)) { /* Check for APM support and that TscInvariant is cleared. */ ASMCpuId(0x80000000, &uEAX, &uEBX, &uECX, &uEDX); @@ -5835,3 +6076,18 @@ static void supdrvGipUpdatePerCpu(PSUPDRVDEVEXT pDevExt, uint64_t u64NanoTS, uin } } +/** + * Resume built-in keyboard on MacBook Air and Pro hosts. + * If there is no built-in keyboard device, return success anyway. + * + * @returns 0 on Mac OS X platform, VERR_NOT_IMPLEMENTED on the other ones. + */ +static int supdrvIOCtl_ResumeSuspendedKbds(void) +{ +#if defined(RT_OS_DARWIN) + return supdrvDarwinResumeSuspendedKbds(); +#else + return VERR_NOT_IMPLEMENTED; +#endif +} + |