VirtualBox

Changeset 93748 in vbox for trunk/src/VBox/VMM/VMMR3


Ignore:
Timestamp:
Feb 15, 2022 12:20:46 PM (3 years ago)
Author:
vboxsync
Message:

VMM/{NEMR3Native-darwin.cpp,HMVMXR0.cpp,VMXAllTemplate.cpp.h}: Move some of the debug loop helpers to the all context template in order to be able to use it for the macOS NEM backend to enable some rudimentary VBox debugger support (breakpoints, etc.), bugref:9044 and bugref:10136

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp

    r93728 r93748  
    18421842
    18431843/**
     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 */
     1853static 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/**
    18441881 * Worker for nemR3NativeInit that loads the Hypervisor.framework shared library.
    18451882 *
     
    31253162
    31263163
    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 */
     3172static 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());
    31363184
    31373185    /*
    3138      * Try switch to NEM runloop state.
     3186     * Sync the TPR shadow with our APIC state.
    31393187     */
    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 */
     3214static VBOXSTRICTRC nemR3DarwinRunGuestNormal(PVM pVM, PVMCPU pVCpu)
     3215{
    31493216    /*
    31503217     * The run loop.
     
    31533220     * everything every time.  This will be optimized later.
    31543221     */
    3155 
    31563222    VMXTRANSIENT VmxTransient;
    31573223    RT_ZERO(VmxTransient);
     
    32323298        pVCpu->nem.s.Event.fPending = false;
    32333299
    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);
    32633301        if (hrc == HV_SUCCESS)
    32643302        {
     
    32853323    } /* the run loop */
    32863324
     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 */
     3336static 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
     3463VBOXSTRICTRC 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);
    32873493
    32883494    /*
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