VirtualBox

Changeset 58658 in vbox for trunk/src/VBox/VMM/VMMR0


Ignore:
Timestamp:
Nov 11, 2015 11:20:55 AM (9 years ago)
Author:
vboxsync
Message:

bugref:8097: AC/DB loop fixes.

Location:
trunk/src/VBox/VMM/VMMR0
Files:
2 edited

Legend:

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

    r58545 r58658  
    107107    { \
    108108        int rc = hmR0SvmCheckExitDueToEventDelivery(pVCpu, pCtx, pSvmTransient); \
    109         if (RT_UNLIKELY(rc == VINF_HM_DOUBLE_FAULT)) \
     109        if (RT_LIKELY(rc == VINF_SUCCESS)) { /* likely */ } \
     110        else if (rc == VINF_HM_DOUBLE_FAULT) \
    110111            return VINF_SUCCESS; \
    111         else if (RT_UNLIKELY(rc == VINF_EM_RESET)) \
     112        else \
    112113            return rc; \
    113114    } while (0)
     
    304305static FNSVMEXITHANDLER hmR0SvmExitXcptMF;
    305306static FNSVMEXITHANDLER hmR0SvmExitXcptDB;
     307static FNSVMEXITHANDLER hmR0SvmExitXcptAC;
    306308/** @} */
    307309
     
    692694        HMCPU_EXIT_HISTORY_RESET(pVCpu);
    693695
     696        /* Always trap #AC for reasons of security. */
     697        pVmcb->ctrl.u32InterceptException |= RT_BIT_32(X86_XCPT_AC);
     698
     699        /* Always trap #DB for reasons of security. */
     700        pVmcb->ctrl.u32InterceptException |= RT_BIT_32(X86_XCPT_DB);
     701
    694702        /* Trap exceptions unconditionally (debug purposes). */
    695703#ifdef HMSVM_ALWAYS_TRAP_PF
     
    700708        pVmcb->ctrl.u32InterceptException |= 0
    701709                                             | RT_BIT(X86_XCPT_BP)
    702                                              | RT_BIT(X86_XCPT_DB)
    703710                                             | RT_BIT(X86_XCPT_DE)
    704711                                             | RT_BIT(X86_XCPT_NM)
     
    11121119DECLINLINE(void) hmR0SvmRemoveXcptIntercept(PSVMVMCB pVmcb, uint32_t u32Xcpt)
    11131120{
     1121    Assert(u32Xcpt != X86_XCPT_DB);
     1122    Assert(u32Xcpt != X86_XCPT_AC);
    11141123#ifndef HMSVM_ALWAYS_TRAP_ALL_XCPTS
    11151124    if (pVmcb->ctrl.u32InterceptException & RT_BIT(u32Xcpt))
     
    14371446    Assert((pCtx->dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK); Assert((pCtx->dr[7] & X86_DR7_RAZ_MASK) == 0);
    14381447
    1439     bool fInterceptDB     = false;
    14401448    bool fInterceptMovDRx = false;
    14411449
     
    14501458        pVCpu->hm.s.fClearTrapFlag = true;
    14511459        pVmcb->guest.u64RFlags |= X86_EFL_TF;
    1452         fInterceptDB = true;
    14531460        fInterceptMovDRx = true; /* Need clean DR6, no guest mess. */
    14541461    }
     
    14951502        /** @todo If we cared, we could optimize to allow the guest to read registers
    14961503         *        with the same values. */
    1497         fInterceptDB = true;
    14981504        fInterceptMovDRx = true;
    14991505        Log5(("hmR0SvmLoadSharedDebugState: Loaded hyper DRx\n"));
     
    15421548         * If no debugging enabled, we'll lazy load DR0-3. We don't need to
    15431549         * intercept #DB as DR6 is updated in the VMCB.
     1550         *
     1551         * Note! If we cared and dared, we could skip intercepting \#DB here.
     1552         *       However, \#DB shouldn't be performance critical, so we'll play safe
     1553         *       and keep the code similar to the VT-x code and always intercept it.
    15441554         */
    15451555#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
     
    15541564    }
    15551565
    1556     /*
    1557      * Set up the intercepts.
    1558      */
    1559     if (fInterceptDB)
    1560         hmR0SvmAddXcptIntercept(pVmcb, X86_XCPT_DB);
    1561     else
    1562         hmR0SvmRemoveXcptIntercept(pVmcb, X86_XCPT_DB);
    1563 
     1566    Assert(pVmcb->ctrl.u32InterceptException & RT_BIT_32(X86_XCPT_DB));
    15641567    if (fInterceptMovDRx)
    15651568    {
     
    35453548            return hmR0SvmExitXcptDB(pVCpu, pCtx, pSvmTransient);
    35463549
     3550        case SVM_EXIT_EXCEPTION_11:  /* X86_XCPT_AC */
     3551            return hmR0SvmExitXcptAC(pVCpu, pCtx, pSvmTransient);
     3552
    35473553        case SVM_EXIT_MONITOR:
    35483554            return hmR0SvmExitMonitor(pVCpu, pCtx, pSvmTransient);
     
    36613667                /*   SVM_EXIT_EXCEPTION_E: */          /* X86_XCPT_PF - Handled above. */
    36623668                /*   SVM_EXIT_EXCEPTION_10: */         /* X86_XCPT_MF - Handled above. */
    3663                 case SVM_EXIT_EXCEPTION_11:            /* X86_XCPT_AC */
     3669                /*   SVM_EXIT_EXCEPTION_11: */         /* X86_XCPT_AC - Handled above. */
    36643670                case SVM_EXIT_EXCEPTION_12:            /* X86_XCPT_MC */
    36653671                case SVM_EXIT_EXCEPTION_13:            /* X86_XCPT_XF */
     
    40694075 *         continue execution of the guest which will delivery the \#DF.
    40704076 * @retval VINF_EM_RESET if we detected a triple-fault condition.
     4077 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
    40714078 *
    40724079 * @param   pVCpu           The cross context virtual CPU structure.
     
    40924099            SVMREFLECTXCPT_DF,      /* Reflect the exception as a double-fault to the guest. */
    40934100            SVMREFLECTXCPT_TF,      /* Indicate a triple faulted state to the VMM. */
     4101            SVMREFLECTXCPT_HANG,    /* Indicate bad VM trying to deadlock the CPU. */
    40944102            SVMREFLECTXCPT_NONE     /* Nothing to reflect. */
    40954103        } SVMREFLECTXCPT;
     
    41154123                    pSvmTransient->fVectoringDoublePF = true;
    41164124                    Log4(("IDT: Vectoring double #PF uCR2=%#RX64\n", pCtx->cr2));
     4125                }
     4126                else if (   uExitVector == X86_XCPT_AC
     4127                         && uIdtVector == X86_XCPT_AC)
     4128                {
     4129                    enmReflect = SVMREFLECTXCPT_HANG;
     4130                    Log4(("IDT: Nested #AC - Bad guest\n"));
    41174131                }
    41184132                else if (   (pVmcb->ctrl.u32InterceptException & HMSVM_CONTRIBUTORY_XCPT_MASK)
     
    41914205            }
    41924206
     4207            case SVMREFLECTXCPT_HANG:
     4208            {
     4209                rc = VERR_EM_GUEST_CPU_HANG;
     4210                break;
     4211            }
     4212
    41934213            default:
    41944214                Assert(rc == VINF_SUCCESS);
     
    41964216        }
    41974217    }
    4198     Assert(rc == VINF_SUCCESS || rc == VINF_HM_DOUBLE_FAULT || rc == VINF_EM_RESET);
     4218    Assert(rc == VINF_SUCCESS || rc == VINF_HM_DOUBLE_FAULT || rc == VINF_EM_RESET || rc == VERR_EM_GUEST_CPU_HANG);
    41994219    NOREF(pCtx);
    42004220    return rc;
     
    54815501}
    54825502
     5503
     5504/**
     5505 * \#VMEXIT handler for alignment check exceptions (SVM_EXIT_EXCEPTION_11).
     5506 * Conditional \#VMEXIT.
     5507 */
     5508HMSVM_EXIT_DECL hmR0SvmExitXcptAC(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
     5509{
     5510    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
     5511
     5512    HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
     5513
     5514    SVMEVENT Event;
     5515    Event.u          = 0;
     5516    Event.n.u1Valid  = 1;
     5517    Event.n.u3Type   = SVM_EVENT_EXCEPTION;
     5518    Event.n.u8Vector = X86_XCPT_AC;
     5519    hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
     5520    return VINF_SUCCESS;
     5521}
     5522
    54835523/** @} */
    54845524
  • trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp

    r58487 r58658  
    143143 * support.
    144144 */
    145 #define HMVMX_REAL_MODE_XCPT_MASK    (  RT_BIT(X86_XCPT_DE)            /* RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI)   \
     145#define HMVMX_REAL_MODE_XCPT_MASK    (  RT_BIT(X86_XCPT_DE)  /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI)   \
    146146                                      | RT_BIT(X86_XCPT_BP)             | RT_BIT(X86_XCPT_OF)    | RT_BIT(X86_XCPT_BR)    \
    147147                                      | RT_BIT(X86_XCPT_UD)            /* RT_BIT(X86_XCPT_NM) */ | RT_BIT(X86_XCPT_DF)    \
    148148                                      | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS)    | RT_BIT(X86_XCPT_NP)    \
    149149                                      | RT_BIT(X86_XCPT_SS)             | RT_BIT(X86_XCPT_GP)   /* RT_BIT(X86_XCPT_PF) */ \
    150                                      /* RT_BIT(X86_XCPT_MF) */          | RT_BIT(X86_XCPT_AC)    | RT_BIT(X86_XCPT_MC)    \
     150                                     /* RT_BIT(X86_XCPT_MF)     always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC)    \
    151151                                      | RT_BIT(X86_XCPT_XF))
    152152
     
    409409static int          hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
    410410static int          hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
     411static int          hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
    411412#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
    412413static int          hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
     
    25822583    uint32_t u32XcptBitmap = pVCpu->hm.s.fGIMTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
    25832584
     2585    /* Must always intercept #AC to prevent the guest from hanging the CPU. */
     2586    u32XcptBitmap |= RT_BIT_32(X86_XCPT_AC);
     2587
     2588    /* Because we need to maintain the DR6 state even when intercepting DRx reads
     2589       and writes, and because recursive #DBs can cause the CPU hang, we must always
     2590       intercept #DB. */
     2591    u32XcptBitmap |= RT_BIT_32(X86_XCPT_DB);
     2592
    25842593    /* Without Nested Paging, #PF must cause a VM-exit so we can sync our shadow page tables. */
    25852594    if (!pVM->hm.s.fNestedPaging)
     
    34363445        }
    34373446
     3447        Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
     3448        Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
     3449
    34383450        rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
    34393451        AssertRCReturn(rc, rc);
     
    36883700        pVCpu->hm.s.vmx.u32XcptBitmap |= 0
    36893701                                         | RT_BIT(X86_XCPT_BP)
    3690                                          | RT_BIT(X86_XCPT_DB)
    36913702                                         | RT_BIT(X86_XCPT_DE)
    36923703                                         | RT_BIT(X86_XCPT_NM)
     
    40074018    int  rc;
    40084019    PVM  pVM              = pVCpu->CTX_SUFF(pVM);
    4009     bool fInterceptDB     = false;
     4020    bool fSteppingDB      = false;
    40104021    bool fInterceptMovDRx = false;
    40114022    if (pVCpu->hm.s.fSingleInstruction)
     
    40174028            rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
    40184029            AssertRCReturn(rc, rc);
    4019             Assert(fInterceptDB == false);
     4030            Assert(fSteppingDB == false);
    40204031        }
    40214032        else
     
    40244035            pVCpu->hm.s.fClearTrapFlag = true;
    40254036            HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
    4026             fInterceptDB = true;
    4027         }
    4028     }
    4029 
    4030     if (   fInterceptDB
     4037            fSteppingDB = true;
     4038        }
     4039    }
     4040
     4041    if (   fSteppingDB
    40314042        || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
    40324043    {
     
    40604071
    40614072        pVCpu->hm.s.fUsingHyperDR7 = true;
    4062         fInterceptDB = true;
    40634073        fInterceptMovDRx = true;
    40644074    }
     
    40894099                STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
    40904100            }
    4091             Assert(!fInterceptDB);
    40924101            Assert(!fInterceptMovDRx);
    40934102        }
    40944103        /*
    40954104         * If no debugging enabled, we'll lazy load DR0-3.  Unlike on AMD-V, we
    4096          * must intercept #DB in order to maintain a correct DR6 guest value.
     4105         * must intercept #DB in order to maintain a correct DR6 guest value, and
     4106         * because we need to intercept it to prevent nested #DBs from hanging the
     4107         * CPU, we end up always having to intercept it.  See hmR0VmxInitXcptBitmap.
    40974108         */
    40984109#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
     
    41044115        {
    41054116            fInterceptMovDRx = true;
    4106             fInterceptDB = true;
    41074117        }
    41084118
     
    41124122
    41134123        pVCpu->hm.s.fUsingHyperDR7 = false;
    4114     }
    4115 
    4116     /*
    4117      * Update the exception bitmap regarding intercepting #DB generated by the guest.
    4118      */
    4119     if (   fInterceptDB
    4120         || pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
    4121     {
    4122         pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_DB);
    4123         HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
    4124     }
    4125     else
    4126     {
    4127 #ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
    4128         pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_DB);
    4129         HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
    4130 #endif
    41314124    }
    41324125
     
    55975590 *         continue execution of the guest which will delivery the \#DF.
    55985591 * @retval VINF_EM_RESET if we detected a triple-fault condition.
     5592 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
    55995593 *
    56005594 * @param   pVCpu           The cross context virtual CPU structure.
     
    56255619            VMXREFLECTXCPT_DF,      /* Reflect the exception as a double-fault to the guest. */
    56265620            VMXREFLECTXCPT_TF,      /* Indicate a triple faulted state to the VMM. */
     5621            VMXREFLECTXCPT_HANG,    /* Indicate bad VM trying to deadlock the CPU. */
    56275622            VMXREFLECTXCPT_NONE     /* Nothing to reflect. */
    56285623        } VMXREFLECTXCPT;
     
    56475642                    pVmxTransient->fVectoringDoublePF = true;
    56485643                    Log4(("IDT: vcpu[%RU32] Vectoring Double #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
     5644                }
     5645                else if (   uExitVector == X86_XCPT_AC
     5646                         && uIdtVector == X86_XCPT_AC)
     5647                {
     5648                    enmReflect = VMXREFLECTXCPT_HANG;
     5649                    Log4(("IDT: Nested #AC - Bad guest\n"));
    56495650                }
    56505651                else if (   (pVCpu->hm.s.vmx.u32XcptBitmap & HMVMX_CONTRIBUTORY_XCPT_MASK)
     
    57455746            }
    57465747
     5748            case VMXREFLECTXCPT_HANG:
     5749            {
     5750                rc = VERR_EM_GUEST_CPU_HANG;
     5751                break;
     5752            }
     5753
    57475754            default:
    57485755                Assert(rc == VINF_SUCCESS);
     
    57685775    }
    57695776
    5770     Assert(rc == VINF_SUCCESS || rc == VINF_HM_DOUBLE_FAULT || rc == VINF_EM_RESET);
     5777    Assert(rc == VINF_SUCCESS || rc == VINF_HM_DOUBLE_FAULT || rc == VINF_EM_RESET || rc == VERR_EM_GUEST_CPU_HANG);
    57715778    return rc;
    57725779}
     
    82598266    if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
    82608267    {
     8268        Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
     8269        Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
    82618270        int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
    82628271        AssertRC(rc);
     
    98729881                case X86_XCPT_DB: rc = hmR0VmxExitXcptDB(pVCpu, pMixedCtx, pVmxTransient);      break;
    98739882                case X86_XCPT_BP: rc = hmR0VmxExitXcptBP(pVCpu, pMixedCtx, pVmxTransient);      break;
     9883                case X86_XCPT_AC: rc = hmR0VmxExitXcptAC(pVCpu, pMixedCtx, pVmxTransient);      break;
    98749884#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
    98759885                case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF);
     
    1129311303    {
    1129411304        Assert(!DBGFIsStepping(pVCpu));
    11295 
    11296         /* Don't intercept MOV DRx and #DB any more. */
     11305        Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
     11306
     11307        /* Don't intercept MOV DRx any more. */
    1129711308        pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
    1129811309        rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
    1129911310        AssertRCReturn(rc, rc);
    11300 
    11301         if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
    11302         {
    11303 #ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
    11304             pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_DB);
    11305             HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
    11306 #endif
    11307         }
    1130811311
    1130911312        /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
     
    1156211565    Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
    1156311566    return rc;
     11567}
     11568
     11569
     11570/**
     11571 * VM-exit exception handler for \#AC (alignment check exception).
     11572 */
     11573static int hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
     11574{
     11575    HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
     11576
     11577    /*
     11578     * Re-inject it. We'll detect any nesting before getting here.
     11579     */
     11580    int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
     11581    rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     11582    AssertRCReturn(rc, rc);
     11583    Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
     11584
     11585    hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
     11586                           pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
     11587    return VINF_SUCCESS;
    1156411588}
    1156511589
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