Changeset 97562 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Nov 16, 2022 2:34:26 AM (2 years ago)
- svn:sync-xref-src-repo-rev:
- 154593
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/VMXAllTemplate.cpp.h
r97335 r97562 7144 7144 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 7145 7145 | X86_DR6_BD | X86_DR6_BS)); 7146 Log6Func(("uDR6=%#RX64 uExitQual=%#RX64\n", uDR6, pVmxTransient->uExitQual)); 7146 7147 7147 7148 int rc; … … 7170 7171 * The exception was for the guest. Update DR6, DR7.GD and 7171 7172 * 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)}. 7173 7175 */ 7174 7176 #ifndef IN_NEM_DARWIN … … 9170 9172 { 9171 9173 /* 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 ) 9173 9179 { 9174 9180 AssertMsgFailed(("Unexpected MOV DRx exit\n")); … … 9182 9188 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB)); 9183 9189 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 } 9188 9205 9189 9206 #ifndef IN_NEM_DARWIN … … 9204 9221 #endif 9205 9222 9223 STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatDRxContextSwitch); 9224 if (fResumeInstruction) 9225 { 9206 9226 #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 else9211 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 } 9215 9235 } 9216 9236 } … … 9226 9246 | CPUMCTX_EXTRN_DR7>(pVCpu, pVmcsInfo, __FUNCTION__); 9227 9247 AssertRCReturn(rc, rc); 9228 Log4Func(("cs:rip=%#04x:%08RX64\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));9229 9248 9230 9249 uint8_t const iGReg = VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual); 9231 9250 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)); 9232 9253 9233 9254 VBOXSTRICTRC rcStrict; … … 9242 9263 9243 9264 if (rcStrict == VINF_SUCCESS) 9265 { 9244 9266 /** @todo r=bird: Not sure why we always flag DR7 as modified here, but I've 9245 9267 * kept it for now to avoid breaking something non-obvious. */ 9246 9268 ASMAtomicUoOrU64(&VCPU_2_VMXSTATE(pVCpu).fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS 9247 9269 | 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 } 9248 9277 else if (rcStrict == VINF_IEM_RAISED_XCPT) 9249 9278 { -
trunk/src/VBox/VMM/VMMR0/CPUMR0.cpp
r96407 r97562 678 678 pVCpu->cpum.s.Guest.dr[3] = ASMGetDR3(); 679 679 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. */ 681 681 } 682 682 ASMAtomicAndU32(&pVCpu->cpum.s.fUseFlags, ~(CPUM_USED_DEBUG_REGS_GUEST | CPUM_USED_DEBUG_REGS_HYPER)); -
trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
r97224 r97562 71 71 #endif 72 72 73 /** Enables the fAlwaysInterceptMovDRx related code. */ 74 #define VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX 1 75 73 76 74 77 /********************************************************************************************************************************* … … 97 100 static bool hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient); 98 101 static 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(). */ 109 static uint64_t g_fDr6Zeroed = 0; 99 110 100 111 … … 3044 3055 # endif 3045 3056 #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 3046 3071 return VINF_SUCCESS; 3047 3072 } … … 3151 3176 *(uint64_t *)(pVM->hmr0.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef); 3152 3177 #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 3153 3195 return VINF_SUCCESS; 3154 3196 } … … 3802 3844 3803 3845 bool fSteppingDB = false; 3804 bool fInterceptMovDRx = false;3805 3846 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls; 3806 3847 if (pVCpu->hm.s.fSingleInstruction) … … 3821 3862 } 3822 3863 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 3823 3869 uint64_t u64GuestDr7; 3824 3870 if ( fSteppingDB … … 3860 3906 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed); 3861 3907 } 3908 #ifndef VMX_WITH_MAYBE_ALWAYS_INTERCEPT_MOV_DRX 3862 3909 Assert(!fInterceptMovDRx); 3910 #endif 3863 3911 } 3864 3912 else if (!CPUMIsGuestDebugStateActive(pVCpu)) … … 4607 4655 4608 4656 /* 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)); 4612 4662 #endif 4613 4663 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */); … … 5497 5547 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT 5498 5548 | 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. */ 5500 5551 | VMX_PROC_CTLS_USE_TPR_SHADOW 5501 5552 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG)); -
trunk/src/VBox/VMM/VMMR3/HM.cpp
r97193 r97562 281 281 "|SvmVGif" 282 282 "|LovelyMesaDrvWorkaround" 283 "|MissingOS2TlbFlushWorkaround", 284 "" /* pszValidNodes */, "HM" /* pszWho */, 0 /* uInstance */); 283 "|MissingOS2TlbFlushWorkaround" 284 "|AlwaysInterceptVmxMovDRx" 285 , "" /* pszValidNodes */, "HM" /* pszWho */, 0 /* uInstance */); 285 286 if (RT_FAILURE(rc)) 286 287 return rc; … … 526 527 * (TESTCFG.SYS typically crashes). See ticketref:20625 for details. */ 527 528 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); 528 549 AssertLogRelRCReturn(rc, rc); 529 550 … … 1602 1623 LogRel(("HM: Host EFER = %#RX64\n", pVM->hm.s.ForR3.vmx.u64HostMsrEfer)); 1603 1624 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" : "")); 1604 1627 1605 1628 hmR3VmxReportFeatCtlMsr(pVM->hm.s.ForR3.vmx.u64HostFeatCtrl); -
trunk/src/VBox/VMM/include/HMInternal.h
r97069 r97562 276 276 /** The shift mask employed by the VMX-Preemption timer (set by ring-0). */ 277 277 uint8_t cPreemptTimerShift; 278 bool fAlignment1;279 278 280 279 /** @name Configuration (gets copied if problematic) … … 290 289 * quietly clears this if the hardware doesn't support the preemption timer. */ 291 290 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; 292 295 /** @} */ 293 296 … … 365 368 /** Whether to use VMCS shadowing. */ 366 369 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; 368 373 369 374 /** Host CR4 value (set by ring-0 VMX init, for logging). */ … … 375 380 /** Host IA32_FEATURE_CONTROL MSR (set by ring-0 VMX init, for logging). */ 376 381 uint64_t u64HostFeatCtrl; 382 /** Host zero'ed DR6 value (set by ring-0 VMX init, for logging). */ 383 uint64_t u64HostDr6Zeroed; 377 384 378 385 /** The first valid host LBR branch-from-IP stack range. */ … … 512 519 /** Set if Last Branch Record (LBR) is enabled. */ 513 520 bool fLbr; 514 bool afAlignment2[3]; 521 /** Set always intercept MOV DRx. */ 522 bool fAlwaysInterceptMovDRx; 523 bool afAlignment2[2]; 515 524 516 525 /** Set if VPID is supported (copy in HM::vmx::fVpidForRing3). */
Note:
See TracChangeset
for help on using the changeset viewer.