Changeset 93748 in vbox for trunk/src/VBox/VMM/VMMR3
- Timestamp:
- Feb 15, 2022 12:20:46 PM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp
r93728 r93748 1842 1842 1843 1843 /** 1844 * Handles an exit from hv_vcpu_run() - debug runloop variant. 1845 * 1846 * @returns VBox strict status code. 1847 * @param pVM The cross context VM structure. 1848 * @param pVCpu The cross context virtual CPU structure of the 1849 * calling EMT. 1850 * @param pVmxTransient The transient VMX structure. 1851 * @param pDbgState The debug state structure. 1852 */ 1853 static VBOXSTRICTRC nemR3DarwinHandleExitDebug(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState) 1854 { 1855 uint32_t uExitReason; 1856 int rc = nemR3DarwinReadVmcs32(pVCpu, VMX_VMCS32_RO_EXIT_REASON, &uExitReason); 1857 AssertRC(rc); 1858 pVmxTransient->fVmcsFieldsRead = 0; 1859 pVmxTransient->fIsNestedGuest = false; 1860 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason); 1861 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason); 1862 1863 if (RT_UNLIKELY(pVmxTransient->fVMEntryFailed)) 1864 AssertLogRelMsgFailedReturn(("Running guest failed for CPU #%u: %#x %u\n", 1865 pVCpu->idCpu, pVmxTransient->uExitReason, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)), 1866 VERR_NEM_IPE_0); 1867 1868 /** @todo Only copy the state on demand (the R0 VT-x code saves some stuff unconditionally and the VMX template assumes that 1869 * when handling exits). */ 1870 rc = nemR3DarwinCopyStateFromHv(pVM, pVCpu, CPUMCTX_EXTRN_ALL); 1871 AssertRCReturn(rc, rc); 1872 1873 STAM_COUNTER_INC(&pVCpu->nem.s.pVmxStats->aStatExitReason[pVmxTransient->uExitReason & MASK_EXITREASON_STAT]); 1874 STAM_REL_COUNTER_INC(&pVCpu->nem.s.pVmxStats->StatExitAll); 1875 1876 return vmxHCRunDebugHandleExit(pVCpu, pVmxTransient, pDbgState); 1877 } 1878 1879 1880 /** 1844 1881 * Worker for nemR3NativeInit that loads the Hypervisor.framework shared library. 1845 1882 * … … 3125 3162 3126 3163 3127 VBOXSTRICTRC nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu) 3128 { 3129 LogFlow(("NEM/%u: %04x:%08RX64 efl=%#08RX64 <=\n", pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags)); 3130 #ifdef LOG_ENABLED 3131 if (LogIs3Enabled()) 3132 nemR3DarwinLogState(pVM, pVCpu); 3133 #endif 3134 3135 AssertReturn(NEMR3CanExecuteGuest(pVM, pVCpu), VERR_NEM_IPE_9); 3164 /** 3165 * Runs the guest once until an exit occurs. 3166 * 3167 * @returns HV status code. 3168 * @param pVM The cross context VM structure. 3169 * @param pVCpu The cross context virtual CPU structure. 3170 * @param pVmxTransient The transient VMX execution structure. 3171 */ 3172 static hv_return_t nemR3DarwinRunGuest(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient) 3173 { 3174 TMNotifyStartOfExecution(pVM, pVCpu); 3175 3176 Assert(!pVCpu->nem.s.fCtxChanged); 3177 hv_return_t hrc; 3178 if (hv_vcpu_run_until) /** @todo Configur the deadline dynamically based on when the next timer triggers. */ 3179 hrc = hv_vcpu_run_until(pVCpu->nem.s.hVCpuId, mach_absolute_time() + 2 * RT_NS_1SEC_64 * pVM->nem.s.cMachTimePerNs); 3180 else 3181 hrc = hv_vcpu_run(pVCpu->nem.s.hVCpuId); 3182 3183 TMNotifyEndOfExecution(pVM, pVCpu, ASMReadTSC()); 3136 3184 3137 3185 /* 3138 * Try switch to NEM runloopstate.3186 * Sync the TPR shadow with our APIC state. 3139 3187 */ 3140 if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED)) 3141 { /* likely */ } 3142 else 3143 { 3144 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED); 3145 LogFlow(("NEM/%u: returning immediately because canceled\n", pVCpu->idCpu)); 3146 return VINF_SUCCESS; 3147 } 3148 3188 if ( !pVmxTransient->fIsNestedGuest 3189 && (pVCpu->nem.s.VmcsInfo.u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)) 3190 { 3191 uint64_t u64Tpr; 3192 hv_return_t hrc2 = hv_vcpu_read_register(pVCpu->nem.s.hVCpuId, HV_X86_TPR, &u64Tpr); 3193 Assert(hrc2 == HV_SUCCESS); 3194 3195 if (pVmxTransient->u8GuestTpr != (uint8_t)u64Tpr) 3196 { 3197 int rc = APICSetTpr(pVCpu, (uint8_t)u64Tpr); 3198 AssertRC(rc); 3199 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR); 3200 } 3201 } 3202 3203 return hrc; 3204 } 3205 3206 3207 /** 3208 * The normal runloop (no debugging features enabled). 3209 * 3210 * @returns Strict VBox status code. 3211 * @param pVM The cross context VM structure. 3212 * @param pVCpu The cross context virtual CPU structure. 3213 */ 3214 static VBOXSTRICTRC nemR3DarwinRunGuestNormal(PVM pVM, PVMCPU pVCpu) 3215 { 3149 3216 /* 3150 3217 * The run loop. … … 3153 3220 * everything every time. This will be optimized later. 3154 3221 */ 3155 3156 3222 VMXTRANSIENT VmxTransient; 3157 3223 RT_ZERO(VmxTransient); … … 3232 3298 pVCpu->nem.s.Event.fPending = false; 3233 3299 3234 TMNotifyStartOfExecution(pVM, pVCpu); 3235 3236 Assert(!pVCpu->nem.s.fCtxChanged); 3237 hv_return_t hrc; 3238 if (hv_vcpu_run_until) /** @todo Configur the deadline dynamically based on when the next timer triggers. */ 3239 hrc = hv_vcpu_run_until(pVCpu->nem.s.hVCpuId, mach_absolute_time() + 2 * RT_NS_1SEC_64 * pVM->nem.s.cMachTimePerNs); 3240 else 3241 hrc = hv_vcpu_run(pVCpu->nem.s.hVCpuId); 3242 3243 TMNotifyEndOfExecution(pVM, pVCpu, ASMReadTSC()); 3244 3245 /* 3246 * Sync the TPR shadow with our APIC state. 3247 */ 3248 if ( !VmxTransient.fIsNestedGuest 3249 && (pVCpu->nem.s.VmcsInfo.u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)) 3250 { 3251 uint64_t u64Tpr; 3252 hrc = hv_vcpu_read_register(pVCpu->nem.s.hVCpuId, HV_X86_TPR, &u64Tpr); 3253 Assert(hrc == HV_SUCCESS); 3254 3255 if (VmxTransient.u8GuestTpr != (uint8_t)u64Tpr) 3256 { 3257 rc = APICSetTpr(pVCpu, (uint8_t)u64Tpr); 3258 AssertRC(rc); 3259 ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR); 3260 } 3261 } 3262 3300 hv_return_t hrc = nemR3DarwinRunGuest(pVM, pVCpu, &VmxTransient); 3263 3301 if (hrc == HV_SUCCESS) 3264 3302 { … … 3285 3323 } /* the run loop */ 3286 3324 3325 return rcStrict; 3326 } 3327 3328 3329 /** 3330 * The debug runloop. 3331 * 3332 * @returns Strict VBox status code. 3333 * @param pVM The cross context VM structure. 3334 * @param pVCpu The cross context virtual CPU structure. 3335 */ 3336 static VBOXSTRICTRC nemR3DarwinRunGuestDebug(PVM pVM, PVMCPU pVCpu) 3337 { 3338 /* 3339 * The run loop. 3340 * 3341 * Current approach to state updating to use the sledgehammer and sync 3342 * everything every time. This will be optimized later. 3343 */ 3344 VMXTRANSIENT VmxTransient; 3345 RT_ZERO(VmxTransient); 3346 VmxTransient.pVmcsInfo = &pVCpu->nem.s.VmcsInfo; 3347 3348 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */ 3349 VMXRUNDBGSTATE DbgState; 3350 vmxHCRunDebugStateInit(pVCpu, &VmxTransient, &DbgState); 3351 vmxHCPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState); 3352 3353 /* 3354 * Poll timers and run for a bit. 3355 */ 3356 /** @todo See if we cannot optimize this TMTimerPollGIP by only redoing 3357 * the whole polling job when timers have changed... */ 3358 uint64_t offDeltaIgnored; 3359 uint64_t const nsNextTimerEvt = TMTimerPollGIP(pVM, pVCpu, &offDeltaIgnored); NOREF(nsNextTimerEvt); 3360 3361 const bool fSingleStepping = DBGFIsStepping(pVCpu); 3362 VBOXSTRICTRC rcStrict = VINF_SUCCESS; 3363 for (unsigned iLoop = 0;; iLoop++) 3364 { 3365 /* Set up VM-execution controls the next two can respond to. */ 3366 vmxHCPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState); 3367 3368 /* 3369 * Check and process force flag actions, some of which might require us to go back to ring-3. 3370 */ 3371 rcStrict = vmxHCCheckForceFlags(pVCpu, false /*fIsNestedGuest*/, fSingleStepping); 3372 if (rcStrict == VINF_SUCCESS) 3373 { /*likely */ } 3374 else 3375 { 3376 if (rcStrict == VINF_EM_RAW_TO_R3) 3377 rcStrict = VINF_SUCCESS; 3378 break; 3379 } 3380 3381 /* 3382 * Do not execute in HV if the A20 isn't enabled. 3383 */ 3384 if (PGMPhysIsA20Enabled(pVCpu)) 3385 { /* likely */ } 3386 else 3387 { 3388 rcStrict = VINF_EM_RESCHEDULE_REM; 3389 LogFlow(("NEM/%u: breaking: A20 disabled\n", pVCpu->idCpu)); 3390 break; 3391 } 3392 3393 /* 3394 * Evaluate events to be injected into the guest. 3395 * 3396 * Events in TRPM can be injected without inspecting the guest state. 3397 * If any new events (interrupts/NMI) are pending currently, we try to set up the 3398 * guest to cause a VM-exit the next time they are ready to receive the event. 3399 */ 3400 if (TRPMHasTrap(pVCpu)) 3401 vmxHCTrpmTrapToPendingEvent(pVCpu); 3402 3403 uint32_t fIntrState; 3404 rcStrict = vmxHCEvaluatePendingEvent(pVCpu, &pVCpu->nem.s.VmcsInfo, false /*fIsNestedGuest*/, &fIntrState); 3405 3406 /* 3407 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus 3408 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might 3409 * also result in triple-faulting the VM. 3410 * 3411 * With nested-guests, the above does not apply since unrestricted guest execution is a 3412 * requirement. Regardless, we do this here to avoid duplicating code elsewhere. 3413 */ 3414 rcStrict = vmxHCInjectPendingEvent(pVCpu, &pVCpu->nem.s.VmcsInfo, false /*fIsNestedGuest*/, fIntrState, fSingleStepping); 3415 if (RT_LIKELY(rcStrict == VINF_SUCCESS)) 3416 { /* likely */ } 3417 else 3418 { 3419 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fSingleStepping), 3420 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); 3421 break; 3422 } 3423 3424 int rc = nemR3DarwinExportGuestState(pVM, pVCpu, &VmxTransient); 3425 AssertRCReturn(rc, rc); 3426 3427 LogFlowFunc(("Running vCPU\n")); 3428 pVCpu->nem.s.Event.fPending = false; 3429 3430 /* Override any obnoxious code in the above two calls. */ 3431 vmxHCPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState); 3432 3433 hv_return_t hrc = nemR3DarwinRunGuest(pVM, pVCpu, &VmxTransient); 3434 if (hrc == HV_SUCCESS) 3435 { 3436 /* 3437 * Deal with the message. 3438 */ 3439 rcStrict = nemR3DarwinHandleExitDebug(pVM, pVCpu, &VmxTransient, &DbgState); 3440 if (rcStrict == VINF_SUCCESS) 3441 { /* hopefully likely */ } 3442 else 3443 { 3444 LogFlow(("NEM/%u: breaking: nemR3DarwinHandleExitDebug -> %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict) )); 3445 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnStatus); 3446 break; 3447 } 3448 //Assert(!pVCpu->cpum.GstCtx.fExtrn); 3449 } 3450 else 3451 { 3452 AssertLogRelMsgFailedReturn(("hv_vcpu_run()) failed for CPU #%u: %#x %u\n", 3453 pVCpu->idCpu, hrc, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)), 3454 VERR_NEM_IPE_0); 3455 } 3456 } /* the run loop */ 3457 3458 /* Restore all controls applied by vmxHCPreRunGuestDebugStateApply above. */ 3459 return vmxHCRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict); 3460 } 3461 3462 3463 VBOXSTRICTRC nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu) 3464 { 3465 LogFlow(("NEM/%u: %04x:%08RX64 efl=%#08RX64 <=\n", pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags)); 3466 #ifdef LOG_ENABLED 3467 if (LogIs3Enabled()) 3468 nemR3DarwinLogState(pVM, pVCpu); 3469 #endif 3470 3471 AssertReturn(NEMR3CanExecuteGuest(pVM, pVCpu), VERR_NEM_IPE_9); 3472 3473 /* 3474 * Try switch to NEM runloop state. 3475 */ 3476 if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED)) 3477 { /* likely */ } 3478 else 3479 { 3480 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED); 3481 LogFlow(("NEM/%u: returning immediately because canceled\n", pVCpu->idCpu)); 3482 return VINF_SUCCESS; 3483 } 3484 3485 VBOXSTRICTRC rcStrict; 3486 if ( !pVCpu->nem.s.fUseDebugLoop 3487 /** @todo dtrace && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled()) */ 3488 && !DBGFIsStepping(pVCpu) 3489 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints) 3490 rcStrict = nemR3DarwinRunGuestNormal(pVM, pVCpu); 3491 else 3492 rcStrict = nemR3DarwinRunGuestDebug(pVM, pVCpu); 3287 3493 3288 3494 /*
Note:
See TracChangeset
for help on using the changeset viewer.