VirtualBox

Changeset 97562 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Nov 16, 2022 2:34:26 AM (2 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
154593
Message:

VMM/HMVMX,CPUM: Added a HM/AlwaysInterceptVmxMovDRx config for controlling how we deal with DR6.RTM & DR7.RTM and similar. Current default (-1) is the old behaviour of ignoring the issue, will change that to hide these new bits in a few hours.

Location:
trunk/src/VBox/VMM
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/VMXAllTemplate.cpp.h

    r97335 r97562  
    71447144                        | (pVmxTransient->uExitQual & (  X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
    71457145                                                       | X86_DR6_BD | X86_DR6_BS));
     7146    Log6Func(("uDR6=%#RX64 uExitQual=%#RX64\n", uDR6, pVmxTransient->uExitQual));
    71467147
    71477148    int rc;
     
    71707171         * The exception was for the guest.  Update DR6, DR7.GD and
    71717172         * IA32_DEBUGCTL.LBR before forwarding it.
    7172          * See Intel spec. 27.1 "Architectural State before a VM-Exit".
     7173         * See Intel spec. 27.1 "Architectural State before a VM-Exit"
     7174         * and @sdmv3{077,622,17.2.3,Debug Status Register (DR6)}.
    71737175         */
    71747176#ifndef IN_NEM_DARWIN
     
    91709172    {
    91719173        /* We should -not- get this VM-exit if the guest's debug registers were active. */
    9172         if (pVmxTransient->fWasGuestDebugStateActive)
     9174        if (   pVmxTransient->fWasGuestDebugStateActive
     9175#ifdef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX
     9176            && !pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fAlwaysInterceptMovDRx
     9177#endif
     9178           )
    91739179        {
    91749180            AssertMsgFailed(("Unexpected MOV DRx exit\n"));
     
    91829188            Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
    91839189
    9184             /* Don't intercept MOV DRx any more. */
    9185             pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
    9186             int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
    9187             AssertRC(rc);
     9190            /* Whether we disable intercepting MOV DRx instructions and resume
     9191               the current one, or emulate it and keep intercepting them is
     9192               configurable.  Though it usually comes down to whether there are
     9193               any new DR6 & DR7 bits (RTM) we want to hide from the guest. */
     9194#ifdef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX
     9195            bool const fResumeInstruction = !pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fAlwaysInterceptMovDRx;
     9196#else
     9197            bool const fResumeInstruction = true;
     9198#endif
     9199            if (fResumeInstruction)
     9200            {
     9201                pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
     9202                int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
     9203                AssertRC(rc);
     9204            }
    91889205
    91899206#ifndef IN_NEM_DARWIN
     
    92049221#endif
    92059222
     9223            STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatDRxContextSwitch);
     9224            if (fResumeInstruction)
     9225            {
    92069226#ifdef VBOX_WITH_STATISTICS
    9207             vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
    9208             if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
    9209                 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitDRxWrite);
    9210             else
    9211                 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitDRxRead);
    9212 #endif
    9213             STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatDRxContextSwitch);
    9214             return VINF_SUCCESS;
     9227                vmxHCReadToTransient<HMVMX_READ_EXIT_QUALIFICATION>(pVCpu, pVmxTransient);
     9228                if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
     9229                    STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitDRxWrite);
     9230                else
     9231                    STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatExitDRxRead);
     9232#endif
     9233                return VINF_SUCCESS;
     9234            }
    92159235        }
    92169236    }
     
    92269246                                   | CPUMCTX_EXTRN_DR7>(pVCpu, pVmcsInfo, __FUNCTION__);
    92279247    AssertRCReturn(rc, rc);
    9228     Log4Func(("cs:rip=%#04x:%08RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    92299248
    92309249    uint8_t const iGReg  = VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual);
    92319250    uint8_t const iDrReg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
     9251    Log4Func(("cs:rip=%#04x:%08RX64 r%d %s dr%d\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, iGReg,
     9252              VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE ? "->" : "<-", iDrReg));
    92329253
    92339254    VBOXSTRICTRC  rcStrict;
     
    92429263
    92439264        if (rcStrict == VINF_SUCCESS)
     9265       {
    92449266            /** @todo r=bird: Not sure why we always flag DR7 as modified here, but I've
    92459267             * kept it for now to avoid breaking something non-obvious. */
    92469268            ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
    92479269                                                                | HM_CHANGED_GUEST_DR7);
     9270            /* Update the DR6 register if guest debug state is active, otherwise we'll
     9271               trash it when calling CPUMR0DebugStateMaybeSaveGuestAndRestoreHost. */
     9272            if (iDrReg == 6 && CPUMIsGuestDebugStateActive(pVCpu))
     9273                ASMSetDR6(pVCpu->cpum.GstCtx.dr[6]);
     9274            Log4Func(("r%d=%#RX64 => dr%d=%#RX64\n", iGReg, pVCpu->cpum.GstCtx.aGRegs[iGReg].u,
     9275                      iDrReg, pVCpu->cpum.GstCtx.dr[iDrReg]));
     9276        }
    92489277        else if (rcStrict == VINF_IEM_RAISED_XCPT)
    92499278        {
  • trunk/src/VBox/VMM/VMMR0/CPUMR0.cpp

    r96407 r97562  
    678678        pVCpu->cpum.s.Guest.dr[3] = ASMGetDR3();
    679679        if (fDr6)
    680             pVCpu->cpum.s.Guest.dr[6] = ASMGetDR6();
     680            pVCpu->cpum.s.Guest.dr[6] = ASMGetDR6() | X86_DR6_RA1_MASK; /* ASSUMES no guest supprot for TSX-NI / RTM. */
    681681    }
    682682    ASMAtomicAndU32(&pVCpu->cpum.s.fUseFlags, ~(CPUM_USED_DEBUG_REGS_GUEST | CPUM_USED_DEBUG_REGS_HYPER));
  • trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp

    r97224 r97562  
    7171#endif
    7272
     73/** Enables the fAlwaysInterceptMovDRx related code. */
     74#define VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX 1
     75
    7376
    7477/*********************************************************************************************************************************
     
    97100static bool     hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient);
    98101static int      hmR0VmxExitHostNmi(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo);
     102
     103
     104/*********************************************************************************************************************************
     105*   Global Variables                                                                                                             *
     106*********************************************************************************************************************************/
     107/** The DR6 value after writing zero to the register.
     108 * Set by VMXR0GlobalInit(). */
     109static uint64_t g_fDr6Zeroed = 0;
    99110
    100111
     
    30443055# endif
    30453056#endif
     3057
     3058    /*
     3059     * For detecting whether DR6.RTM is writable or not (done in VMXR0InitVM).
     3060     */
     3061    RTTHREADPREEMPTSTATE Preempt = RTTHREADPREEMPTSTATE_INITIALIZER;
     3062    RTThreadPreemptDisable(&Preempt);
     3063    RTCCUINTXREG const fSavedDr6 = ASMGetDR6();
     3064    ASMSetDR6(0);
     3065    RTCCUINTXREG const fZeroDr6  = ASMGetDR6();
     3066    ASMSetDR6(fSavedDr6);
     3067    RTThreadPreemptRestore(&Preempt);
     3068
     3069    g_fDr6Zeroed = fZeroDr6;
     3070
    30463071    return VINF_SUCCESS;
    30473072}
     
    31513176    *(uint64_t *)(pVM->hmr0.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
    31523177#endif
     3178
     3179    /*
     3180     * Copy out stuff that's for ring-3 and determin default configuration.
     3181     */
     3182    pVM->hm.s.ForR3.vmx.u64HostDr6Zeroed = g_fDr6Zeroed;
     3183
     3184    /* Since we do not emulate RTM, make sure DR6.RTM cannot be cleared by the
     3185       guest and cause confusion there.  It appears that the DR6.RTM bit can be
     3186       cleared even if TSX-NI is disabled (microcode update / system / whatever). */
     3187#ifdef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX
     3188    if (pVM->hm.s.vmx.fAlwaysInterceptMovDRxCfg == 0)
     3189        pVM->hmr0.s.vmx.fAlwaysInterceptMovDRx = g_fDr6Zeroed != X86_DR6_RA1_MASK;
     3190    else
     3191#endif
     3192        pVM->hmr0.s.vmx.fAlwaysInterceptMovDRx = pVM->hm.s.vmx.fAlwaysInterceptMovDRxCfg > 0;
     3193    pVM->hm.s.ForR3.vmx.fAlwaysInterceptMovDRx = pVM->hmr0.s.vmx.fAlwaysInterceptMovDRx;
     3194
    31533195    return VINF_SUCCESS;
    31543196}
     
    38023844
    38033845    bool     fSteppingDB      = false;
    3804     bool     fInterceptMovDRx = false;
    38053846    uint32_t uProcCtls        = pVmcsInfo->u32ProcCtls;
    38063847    if (pVCpu->hm.s.fSingleInstruction)
     
    38213862    }
    38223863
     3864#ifdef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX
     3865    bool     fInterceptMovDRx = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fAlwaysInterceptMovDRx;
     3866#else
     3867    bool     fInterceptMovDRx = false;
     3868#endif
    38233869    uint64_t u64GuestDr7;
    38243870    if (   fSteppingDB
     
    38603906                STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
    38613907            }
     3908#ifndef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX
    38623909            Assert(!fInterceptMovDRx);
     3910#endif
    38633911        }
    38643912        else if (!CPUMIsGuestDebugStateActive(pVCpu))
     
    46074655
    46084656    /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
    4609 #ifdef VBOX_STRICT
    4610     if (CPUMIsHyperDebugStateActive(pVCpu))
    4611         Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
     4657#ifdef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX
     4658    Assert(   (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT)
     4659           || (!CPUMIsHyperDebugStateActive(pVCpu) && !pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fAlwaysInterceptMovDRx));
     4660#else
     4661    Assert((pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT) || !CPUMIsHyperDebugStateActive(pVCpu));
    46124662#endif
    46134663    CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
     
    54975547                               | (pVmcsInfoGst->u32ProcCtls & ~(  VMX_PROC_CTLS_INT_WINDOW_EXIT
    54985548                                                                | VMX_PROC_CTLS_NMI_WINDOW_EXIT
    5499                                                                 | VMX_PROC_CTLS_MOV_DR_EXIT
     5549                                                                | VMX_PROC_CTLS_MOV_DR_EXIT /* hmR0VmxExportSharedDebugState makes
     5550                                                                                               sure guest DRx regs are loaded. */
    55005551                                                                | VMX_PROC_CTLS_USE_TPR_SHADOW
    55015552                                                                | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
  • trunk/src/VBox/VMM/VMMR3/HM.cpp

    r97193 r97562  
    281281                              "|SvmVGif"
    282282                              "|LovelyMesaDrvWorkaround"
    283                               "|MissingOS2TlbFlushWorkaround",
    284                               "" /* pszValidNodes */, "HM" /* pszWho */, 0 /* uInstance */);
     283                              "|MissingOS2TlbFlushWorkaround"
     284                              "|AlwaysInterceptVmxMovDRx"
     285                              , "" /* pszValidNodes */, "HM" /* pszWho */, 0 /* uInstance */);
    285286    if (RT_FAILURE(rc))
    286287        return rc;
     
    526527     * (TESTCFG.SYS typically crashes).  See ticketref:20625 for details. */
    527528    rc = CFGMR3QueryBoolDef(pCfgHm, "MissingOS2TlbFlushWorkaround", &pVM->hm.s.fMissingOS2TlbFlushWorkaround, false);
     529    AssertLogRelRCReturn(rc, rc);
     530
     531    /** @cfgm{/HM/AlwaysInterceptVmxMovDRx,int8_t,-1}
     532     * Whether to always intercept MOV DRx when using VMX.
     533     * The value is a tristate: 1 for always intercepting, -1 for lazy intercept,
     534     * and 0 for default.  The default means that it's always intercepted when the
     535     * host DR6 contains bits not known to the guest.
     536     *
     537     * With the introduction of transactional synchronization extensions new
     538     * instructions, aka TSX-NI or RTM, bit 16 in DR6 is cleared to indicate that a
     539     * \#DB was related to a transaction.  The bit is also cleared when writing zero
     540     * to it, so guest lazily resetting DR6 by writing 0 to it, ends up with an
     541     * unexpected value.  Similiarly, bit 11 in DR7 is used to enabled RTM
     542     * debugging support and therefore writable by the guest.
     543     *
     544     * Out of caution/paranoia, we will by default intercept DRx moves when setting
     545     * DR6 to zero (on the host) doesn't result in 0xffff0ff0 (X86_DR6_RA1_MASK).
     546     * Note that it seems DR6.RTM remains writable even after the microcode updates
     547     * disabling TSX. */
     548    rc = CFGMR3QueryS8Def(pCfgHm, "AlwaysInterceptVmxMovDRx", &pVM->hm.s.vmx.fAlwaysInterceptMovDRxCfg, -1);
    528549    AssertLogRelRCReturn(rc, rc);
    529550
     
    16021623    LogRel(("HM: Host EFER                         = %#RX64\n", pVM->hm.s.ForR3.vmx.u64HostMsrEfer));
    16031624    LogRel(("HM: MSR_IA32_SMM_MONITOR_CTL          = %#RX64\n", pVM->hm.s.ForR3.vmx.u64HostSmmMonitorCtl));
     1625    LogRel(("HM: Host DR6 zero'ed                  = %#RX64%s\n", pVM->hm.s.ForR3.vmx.u64HostDr6Zeroed,
     1626            pVM->hm.s.ForR3.vmx.fAlwaysInterceptMovDRx ? " - always intercept MOV DRx" : ""));
    16041627
    16051628    hmR3VmxReportFeatCtlMsr(pVM->hm.s.ForR3.vmx.u64HostFeatCtrl);
  • trunk/src/VBox/VMM/include/HMInternal.h

    r97069 r97562  
    276276        /** The shift mask employed by the VMX-Preemption timer (set by ring-0). */
    277277        uint8_t                     cPreemptTimerShift;
    278         bool                        fAlignment1;
    279278
    280279        /** @name Configuration (gets copied if problematic)
     
    290289         * quietly clears this if the hardware doesn't support the preemption timer. */
    291290        bool                        fUsePreemptTimerCfg;
     291        /** Whether to always intercept MOV DRx: 1 (always), 0 (default), -1 (lazy).
     292         * In the default case it is only always intercepted when setting DR6 to 0 on
     293         * the host results in a value different from X86_DR6_RA1_MASK. */
     294        int8_t                      fAlwaysInterceptMovDRxCfg;
    292295        /** @} */
    293296
     
    365368            /** Whether to use VMCS shadowing. */
    366369            bool                        fUseVmcsShadowing;
    367             bool                        fAlignment2;
     370            /** Whether MOV DRx is always intercepted or not (set by ring-0 VMX init, for
     371             * logging). */
     372            bool                        fAlwaysInterceptMovDRx;
    368373
    369374            /** Host CR4 value (set by ring-0 VMX init, for logging). */
     
    375380            /** Host IA32_FEATURE_CONTROL MSR (set by ring-0 VMX init, for logging). */
    376381            uint64_t                    u64HostFeatCtrl;
     382            /** Host zero'ed DR6 value (set by ring-0 VMX init, for logging). */
     383            uint64_t                    u64HostDr6Zeroed;
    377384
    378385            /** The first valid host LBR branch-from-IP stack range. */
     
    512519        /** Set if Last Branch Record (LBR) is enabled. */
    513520        bool                        fLbr;
    514         bool                        afAlignment2[3];
     521        /** Set always intercept MOV DRx. */
     522        bool                        fAlwaysInterceptMovDRx;
     523        bool                        afAlignment2[2];
    515524
    516525        /** Set if VPID is supported (copy in HM::vmx::fVpidForRing3). */
Note: See TracChangeset for help on using the changeset viewer.

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