VirtualBox

Changeset 48296 in vbox


Ignore:
Timestamp:
Sep 5, 2013 9:52:17 AM (11 years ago)
Author:
vboxsync
Message:

VMM/HMR0: Fix for SMX mode, avoid rechecking what's already checked.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/HMR0.cpp

    r48280 r48296  
    187187 * @param   rc                  The status code.
    188188 */
    189 static void     hmR0FirstRcSetStatus(PHMR0FIRSTRC pFirstRc, int rc)
     189static void hmR0FirstRcSetStatus(PHMR0FIRSTRC pFirstRc, int rc)
    190190{
    191191    if (   RT_FAILURE(rc)
     
    386386        if (RT_SUCCESS(g_HvmR0.lLastError))
    387387        {
    388             /* Reread in case we've changed it. */
     388            /* Reread in case it was changed by hmR0InitIntelCpu(). */
    389389            g_HvmR0.vmx.Msrs.u64FeatureCtrl = ASMRdMsr(MSR_IA32_FEATURE_CONTROL);
    390390
    391             /** @todo r=ramshankar: This should be fixed for when the host is in SMX mode.
    392              *        Probably don't need to recheck it here. It's done in
    393              *        hmR0InitIntelCpu(). */
    394             if (   (g_HvmR0.vmx.Msrs.u64FeatureCtrl & (MSR_IA32_FEATURE_CONTROL_VMXON | MSR_IA32_FEATURE_CONTROL_LOCK))
    395                 ==                                    (MSR_IA32_FEATURE_CONTROL_VMXON | MSR_IA32_FEATURE_CONTROL_LOCK))
     391            /*
     392             * Read all relevant registers and MSRs.
     393             */
     394            g_HvmR0.vmx.u64HostCr4          = ASMGetCR4();
     395            g_HvmR0.vmx.u64HostEfer         = ASMRdMsr(MSR_K6_EFER);
     396            g_HvmR0.vmx.Msrs.u64BasicInfo   = ASMRdMsr(MSR_IA32_VMX_BASIC_INFO);
     397            g_HvmR0.vmx.Msrs.VmxPinCtls.u   = ASMRdMsr(MSR_IA32_VMX_PINBASED_CTLS);
     398            g_HvmR0.vmx.Msrs.VmxProcCtls.u  = ASMRdMsr(MSR_IA32_VMX_PROCBASED_CTLS);
     399            g_HvmR0.vmx.Msrs.VmxExit.u      = ASMRdMsr(MSR_IA32_VMX_EXIT_CTLS);
     400            g_HvmR0.vmx.Msrs.VmxEntry.u     = ASMRdMsr(MSR_IA32_VMX_ENTRY_CTLS);
     401            g_HvmR0.vmx.Msrs.u64Misc        = ASMRdMsr(MSR_IA32_VMX_MISC);
     402            g_HvmR0.vmx.Msrs.u64Cr0Fixed0   = ASMRdMsr(MSR_IA32_VMX_CR0_FIXED0);
     403            g_HvmR0.vmx.Msrs.u64Cr0Fixed1   = ASMRdMsr(MSR_IA32_VMX_CR0_FIXED1);
     404            g_HvmR0.vmx.Msrs.u64Cr4Fixed0   = ASMRdMsr(MSR_IA32_VMX_CR4_FIXED0);
     405            g_HvmR0.vmx.Msrs.u64Cr4Fixed1   = ASMRdMsr(MSR_IA32_VMX_CR4_FIXED1);
     406            g_HvmR0.vmx.Msrs.u64VmcsEnum    = ASMRdMsr(MSR_IA32_VMX_VMCS_ENUM);
     407            /* VPID 16 bits ASID. */
     408            g_HvmR0.uMaxAsid                = 0x10000; /* exclusive */
     409
     410            if (g_HvmR0.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
     411            {
     412                g_HvmR0.vmx.Msrs.VmxProcCtls2.u = ASMRdMsr(MSR_IA32_VMX_PROCBASED_CTLS2);
     413                if (g_HvmR0.vmx.Msrs.VmxProcCtls2.n.allowed1 & (VMX_VMCS_CTRL_PROC_EXEC2_EPT | VMX_VMCS_CTRL_PROC_EXEC2_VPID))
     414                    g_HvmR0.vmx.Msrs.u64EptVpidCaps = ASMRdMsr(MSR_IA32_VMX_EPT_VPID_CAP);
     415
     416                if (g_HvmR0.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VMFUNC)
     417                    g_HvmR0.vmx.Msrs.u64Vmfunc = ASMRdMsr(MSR_IA32_VMX_VMFUNC);
     418            }
     419
     420            if (!g_HvmR0.vmx.fUsingSUPR0EnableVTx)
    396421            {
    397422                /*
    398                  * Read all relevant registers and MSRs.
     423                 * Enter root mode
    399424                 */
    400                 g_HvmR0.vmx.u64HostCr4          = ASMGetCR4();
    401                 g_HvmR0.vmx.u64HostEfer         = ASMRdMsr(MSR_K6_EFER);
    402                 g_HvmR0.vmx.Msrs.u64BasicInfo   = ASMRdMsr(MSR_IA32_VMX_BASIC_INFO);
    403                 g_HvmR0.vmx.Msrs.VmxPinCtls.u   = ASMRdMsr(MSR_IA32_VMX_PINBASED_CTLS);
    404                 g_HvmR0.vmx.Msrs.VmxProcCtls.u  = ASMRdMsr(MSR_IA32_VMX_PROCBASED_CTLS);
    405                 g_HvmR0.vmx.Msrs.VmxExit.u      = ASMRdMsr(MSR_IA32_VMX_EXIT_CTLS);
    406                 g_HvmR0.vmx.Msrs.VmxEntry.u     = ASMRdMsr(MSR_IA32_VMX_ENTRY_CTLS);
    407                 g_HvmR0.vmx.Msrs.u64Misc        = ASMRdMsr(MSR_IA32_VMX_MISC);
    408                 g_HvmR0.vmx.Msrs.u64Cr0Fixed0   = ASMRdMsr(MSR_IA32_VMX_CR0_FIXED0);
    409                 g_HvmR0.vmx.Msrs.u64Cr0Fixed1   = ASMRdMsr(MSR_IA32_VMX_CR0_FIXED1);
    410                 g_HvmR0.vmx.Msrs.u64Cr4Fixed0   = ASMRdMsr(MSR_IA32_VMX_CR4_FIXED0);
    411                 g_HvmR0.vmx.Msrs.u64Cr4Fixed1   = ASMRdMsr(MSR_IA32_VMX_CR4_FIXED1);
    412                 g_HvmR0.vmx.Msrs.u64VmcsEnum    = ASMRdMsr(MSR_IA32_VMX_VMCS_ENUM);
    413                 /* VPID 16 bits ASID. */
    414                 g_HvmR0.uMaxAsid                = 0x10000; /* exclusive */
    415 
    416                 if (g_HvmR0.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
     425                RTR0MEMOBJ hScatchMemObj;
     426                rc = RTR0MemObjAllocCont(&hScatchMemObj, PAGE_SIZE, false /* fExecutable */);
     427                if (RT_FAILURE(rc))
    417428                {
    418                     g_HvmR0.vmx.Msrs.VmxProcCtls2.u = ASMRdMsr(MSR_IA32_VMX_PROCBASED_CTLS2);
    419                     if (g_HvmR0.vmx.Msrs.VmxProcCtls2.n.allowed1 & (VMX_VMCS_CTRL_PROC_EXEC2_EPT | VMX_VMCS_CTRL_PROC_EXEC2_VPID))
    420                         g_HvmR0.vmx.Msrs.u64EptVpidCaps = ASMRdMsr(MSR_IA32_VMX_EPT_VPID_CAP);
    421 
    422                     if (g_HvmR0.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VMFUNC)
    423                         g_HvmR0.vmx.Msrs.u64Vmfunc = ASMRdMsr(MSR_IA32_VMX_VMFUNC);
     429                    LogRel(("hmR0InitIntel: RTR0MemObjAllocCont(,PAGE_SIZE,true) -> %Rrc\n", rc));
     430                    return rc;
    424431                }
    425432
    426                 if (!g_HvmR0.vmx.fUsingSUPR0EnableVTx)
     433                void      *pvScatchPage      = RTR0MemObjAddress(hScatchMemObj);
     434                RTHCPHYS   HCPhysScratchPage = RTR0MemObjGetPagePhysAddr(hScatchMemObj, 0);
     435                ASMMemZeroPage(pvScatchPage);
     436
     437                /* Set revision dword at the beginning of the structure. */
     438                *(uint32_t *)pvScatchPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(g_HvmR0.vmx.Msrs.u64BasicInfo);
     439
     440                /* Make sure we don't get rescheduled to another cpu during this probe. */
     441                RTCCUINTREG fFlags = ASMIntDisableFlags();
     442
     443                /*
     444                 * Check CR4.VMXE
     445                 */
     446                g_HvmR0.vmx.u64HostCr4 = ASMGetCR4();
     447                if (!(g_HvmR0.vmx.u64HostCr4 & X86_CR4_VMXE))
     448                {
     449                    /* In theory this bit could be cleared behind our back.  Which would cause
     450                       #UD faults when we try to execute the VMX instructions... */
     451                    ASMSetCR4(g_HvmR0.vmx.u64HostCr4 | X86_CR4_VMXE);
     452                }
     453
     454                /*
     455                 * The only way of checking if we're in VMX root mode or not is to try and enter it.
     456                 * There is no instruction or control bit that tells us if we're in VMX root mode.
     457                 * Therefore, try and enter VMX root mode here.
     458                 */
     459                rc = VMXEnable(HCPhysScratchPage);
     460                if (RT_SUCCESS(rc))
     461                {
     462                    g_HvmR0.vmx.fSupported = true;
     463                    VMXDisable();
     464                }
     465                else
    427466                {
    428467                    /*
    429                      * Enter root mode
     468                     * KVM leaves the CPU in VMX root mode. Not only is  this not allowed,
     469                     * it will crash the host when we enter raw mode, because:
     470                     *
     471                     *   (a) clearing X86_CR4_VMXE in CR4 causes a #GP (we no longer modify
     472                     *       this bit), and
     473                     *   (b) turning off paging causes a #GP  (unavoidable when switching
     474                     *       from long to 32 bits mode or 32 bits to PAE).
     475                     *
     476                     * They should fix their code, but until they do we simply refuse to run.
    430477                     */
    431                     RTR0MEMOBJ hScatchMemObj;
    432                     rc = RTR0MemObjAllocCont(&hScatchMemObj, PAGE_SIZE, false /* fExecutable */);
    433                     if (RT_FAILURE(rc))
    434                     {
    435                         LogRel(("hmR0InitIntel: RTR0MemObjAllocCont(,PAGE_SIZE,true) -> %Rrc\n", rc));
    436                         return rc;
    437                     }
    438 
    439                     void      *pvScatchPage      = RTR0MemObjAddress(hScatchMemObj);
    440                     RTHCPHYS   HCPhysScratchPage = RTR0MemObjGetPagePhysAddr(hScatchMemObj, 0);
    441                     ASMMemZeroPage(pvScatchPage);
    442 
    443                     /* Set revision dword at the beginning of the structure. */
    444                     *(uint32_t *)pvScatchPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(g_HvmR0.vmx.Msrs.u64BasicInfo);
    445 
    446                     /* Make sure we don't get rescheduled to another cpu during this probe. */
    447                     RTCCUINTREG fFlags = ASMIntDisableFlags();
    448 
    449                     /*
    450                      * Check CR4.VMXE
    451                      */
    452                     g_HvmR0.vmx.u64HostCr4 = ASMGetCR4();
    453                     if (!(g_HvmR0.vmx.u64HostCr4 & X86_CR4_VMXE))
    454                     {
    455                         /* In theory this bit could be cleared behind our back.  Which would cause
    456                            #UD faults when we try to execute the VMX instructions... */
    457                         ASMSetCR4(g_HvmR0.vmx.u64HostCr4 | X86_CR4_VMXE);
    458                     }
    459 
    460                     /*
    461                      * The only way of checking if we're in VMX root mode or not is to try and enter it.
    462                      * There is no instruction or control bit that tells us if we're in VMX root mode.
    463                      * Therefore, try and enter VMX root mode here.
    464                      */
    465                     rc = VMXEnable(HCPhysScratchPage);
    466                     if (RT_SUCCESS(rc))
    467                     {
    468                         g_HvmR0.vmx.fSupported = true;
    469                         VMXDisable();
    470                     }
    471                     else
    472                     {
    473                         /*
    474                          * KVM leaves the CPU in VMX root mode. Not only is  this not allowed,
    475                          * it will crash the host when we enter raw mode, because:
    476                          *
    477                          *   (a) clearing X86_CR4_VMXE in CR4 causes a #GP (we no longer modify
    478                          *       this bit), and
    479                          *   (b) turning off paging causes a #GP  (unavoidable when switching
    480                          *       from long to 32 bits mode or 32 bits to PAE).
    481                          *
    482                          * They should fix their code, but until they do we simply refuse to run.
    483                          */
    484                         g_HvmR0.lLastError = VERR_VMX_IN_VMX_ROOT_MODE;
    485                     }
    486 
    487                     /* Restore CR4 again; don't leave the X86_CR4_VMXE flag set
    488                        if it wasn't so before (some software could incorrectly
    489                        think it's in VMX mode). */
    490                     ASMSetCR4(g_HvmR0.vmx.u64HostCr4);
    491                     ASMSetFlags(fFlags);
    492 
    493                     RTR0MemObjFree(hScatchMemObj, false);
     478                    g_HvmR0.lLastError = VERR_VMX_IN_VMX_ROOT_MODE;
     479                    Assert(g_HvmR0.vmx.fSupported == false);
    494480                }
    495             }
    496             else
    497             {
    498                 AssertFailed(); /* can't hit this case anymore */
    499                 g_HvmR0.lLastError = VERR_VMX_ILLEGAL_FEATURE_CONTROL_MSR;
     481
     482                /* Restore CR4 again; don't leave the X86_CR4_VMXE flag set
     483                   if it wasn't so before (some software could incorrectly
     484                   think it's in VMX mode). */
     485                ASMSetCR4(g_HvmR0.vmx.u64HostCr4);
     486                ASMSetFlags(fFlags);
     487
     488                RTR0MemObjFree(hScatchMemObj, false);
    500489            }
    501490
    502491            if (g_HvmR0.vmx.fSupported)
    503492            {
    504                 /* Call the global VT-x initialization routine. */
    505493                rc = VMXR0GlobalInit();
    506494                if (RT_FAILURE(rc))
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette