VirtualBox

Changeset 46657 in vbox


Ignore:
Timestamp:
Jun 19, 2013 1:18:19 PM (11 years ago)
Author:
vboxsync
Message:

VMM/HMSVMR0: AMD-V bits.

File:
1 edited

Legend:

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

    r46603 r46657  
    4444#define HMSVM_EXIT_DECL                 static int
    4545
     46
    4647/** @name Segment attribute conversion between CPU and AMD-V VMCB format.
    4748 *
     
    5657#define HMSVM_VMCB_2_CPU_SEG_ATTR(a)       (a & 0xff) | ((a & 0x0f00) << 4)
    5758/** @} */
     59
    5860
    5961/** @name Macros for loading, storing segment registers to/from the VMCB.
     
    8183    } while (0)
    8284/** @} */
     85
     86
     87/** @name Macro for checking and returning from the using function for
     88 *        #VMEXIT intercepts that maybe caused during delivering of another
     89 *        event in the guest. */
     90#define HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY() \
     91    do \
     92    { \
     93        int rc = hmR0SvmCheckExitDueToEventDelivery(pVCpu, pCtx, pSvmTransient); \
     94        if (RT_UNLIKELY(rc == VINF_HM_DOUBLE_FAULT)) \
     95            return VINF_SUCCESS; \
     96        else if (RT_UNLIKELY(rc == VINF_EM_RESET)) \
     97            return rc; \
     98    } while (0)
     99/** @} */
     100
     101
     102/**
     103 * @name Exception bitmap mask for all contributory exceptions.
     104 *
     105 * Page fault is deliberately excluded here as it's conditional whether it's
     106 * contributory or benign. It's handled separately.
     107 */
     108#define HMSVM_CONTRIBUTORY_XCPT_MASK  ( RT_BIT(X86_XCPT_GP) | RT_BIT(X86_XCPT_NP) | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_TS) \
     109                                       | RT_BIT(X86_XCPT_DE))
     110/** @} */
     111
    83112
    84113/** @name VMCB Clean Bits.
     
    148177    /** The guest's TPR value used for TPR shadowing. */
    149178    uint8_t         u8GuestTpr;
     179
     180    /** Whether the #VMEXIT was caused by a page-fault during delivery of a
     181     *  contributary exception or a page-fault. */
     182    bool            fVectoringPF;
    150183} SVMTRANSIENT, *PSVMTRANSIENT;
    151184/** @}  */
     
    25222555    }
    25232556
    2524     pSvmTransient->u64ExitCode = pVmcb->ctrl.u64ExitCode;
     2557    pSvmTransient->u64ExitCode   = pVmcb->ctrl.u64ExitCode;     /* Save the #VMEXIT reason. */
     2558    pSvmTransient->fVectoringPF  = false;                       /* Vectoring page-fault needs to be determined later. */
    25252559    hmR0SvmSaveGuestState(pVCpu, pMixedCtx);                    /* Save the guest state from the VMCB to the guest-CPU context. */
    25262560
    2527     if (RT_LIKELY(pSvmTransient->u64ExitCode != SVM_EXIT_INVALID))
     2561    if (RT_LIKELY(pSvmTransient->u64ExitCode != (uint64_t)SVM_EXIT_INVALID))
    25282562    {
    25292563        if (pVCpu->hm.s.svm.fSyncVTpr)
     
    25952629         */
    25962630        hmR0SvmPostRunGuest(pVM, pVCpu, pCtx, &SvmTransient, rc);
    2597         if (RT_UNLIKELY(   rc != VINF_SUCCESS                              /* Check for errors with running the VM (VMRUN). */
    2598                         || SvmTransient.u64ExitCode == SVM_EXIT_INVALID))  /* Check for errors due to invalid guest state. */
     2631        if (RT_UNLIKELY(   rc != VINF_SUCCESS                                         /* Check for VMRUN errors. */
     2632                        || SvmTransient.u64ExitCode == (uint64_t)SVM_EXIT_INVALID))   /* Check for invalid guest-state errors. */
    25992633        {
    26002634            if (rc == VINF_SUCCESS);
     
    26052639
    26062640        /* Handle the #VMEXIT. */
    2607         AssertMsg(SvmTransient.u64ExitCode != SVM_EXIT_INVALID, ("%#x\n", SvmTransient.u64ExitCode));
     2641        AssertMsg(SvmTransient.u64ExitCode != (uint64_t)SVM_EXIT_INVALID, ("%#x\n", SvmTransient.u64ExitCode));
    26082642        HMSVM_EXITCODE_STAM_COUNTER_INC(SvmTransient.u64ExitCode);
    26092643        rc = hmR0SvmHandleExit(pVCpu, pCtx, &SvmTransient);
     
    27522786            case SVM_EXIT_EXCEPTION_C:      /* X86_XCPT_SS */
    27532787            case SVM_EXIT_EXCEPTION_D:      /* X86_XCPT_GP */
    2754                 return
     2788            {
     2789                SVMEVENT Event;
     2790                Event.u          = 0;
     2791                Event.n.u3Type   = SVM_EVENT_EXCEPTION;
     2792                Event.n.u1Valid  = 1;
     2793                Event.n.u8Vector = pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0;
     2794
     2795                switch (Event.n.u8Vector)
     2796                {
     2797                    case X86_XCPT_GP:
     2798                        Event.n.u1ErrorCodeValid    = 1;
     2799                        Event.n.u32ErrorCode        = pVmcb->ctrl.u64ExitInfo1;
     2800                        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
     2801                        break;
     2802                    case X86_XCPT_BP:
     2803                        /** Saves the wrong EIP on the stack (pointing to the int3) instead of the
     2804                         *  next instruction. */
     2805                        /** @todo Investigate this later. */
     2806                        break;
     2807                    case X86_XCPT_DE:
     2808                        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE);
     2809                        break;
     2810                    case X86_XCPT_UD:
     2811                        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);
     2812                        break;
     2813                    case X86_XCPT_SS:
     2814                        Event.n.u1ErrorCodeValid    = 1;
     2815                        Event.n.u32ErrorCode        = pVmcb->ctrl.u64ExitInfo1;
     2816                        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS);
     2817                        break;
     2818                    case X86_XCPT_NP:
     2819                        Event.n.u1ErrorCodeValid    = 1;
     2820                        Event.n.u32ErrorCode        = pVmcb->ctrl.u64ExitInfo1;
     2821                        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP);
     2822                        break;
     2823                }
     2824                Log4(("#Xcpt: Vector=%#x at CS:RIP=%04x:%RGv\n", Event.n.u8Vector, pCtx->cs.Sel, (RTGCPTR)pCtx->rip));
     2825                hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
     2826                return VINF_SUCCESS;
     2827            }
    27552828#endif
    27562829
     
    27812854            do { \
    27822855                AssertPtr(pVCpu); \
    2783                 AssertPtr(pMixedCtx); \
     2856                AssertPtr(pCtx); \
    27842857                AssertPtr(pSvmTransient); \
    27852858                Assert(ASMIntAreEnabled()); \
    27862859                Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD)); \
    27872860                HMSVM_ASSERT_PREEMPT_CPUID_VAR(); \
    2788                 Log4Func(("vcpu[%u] -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-\n", (uint32_t)pVCpu->idCpu)); \
     2861                Log4Func(("vcpu[%u] -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-\n", (uint32_t)pVCpu->idCpu)); \
    27892862                Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD)); \
    27902863                if (VMMR0IsLogFlushDisabled(pVCpu)) \
     
    29242997
    29252998    hmR0SvmSetPendingEvent(pVCpu, &Event);
    2926     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
    29272999}
    29283000
     
    29573029    Event.n.u3Type   = SVM_EVENT_EXCEPTION;
    29583030    Event.n.u8Vector = X86_XCPT_MF;
     3031    hmR0SvmSetPendingEvent(pVCpu, &Event);
     3032}
     3033
     3034
     3035/**
     3036 * Sets a double fault (#DF) exception as pending-for-injection into the VM.
     3037 *
     3038 * @param   pVCpu       Pointer to the VMCPU.
     3039 */
     3040DECLINLINE(void) hmR0SvmSetPendingXcptDF(PVMCPU pVCpu)
     3041{
     3042    SVMEVENT Event;
     3043    Event.u                  = 0;
     3044    Event.n.u1Valid          = 1;
     3045    Event.n.u3Type           = SVM_EVENT_EXCEPTION;
     3046    Event.n.u8Vector         = X86_XCPT_DF;
     3047    Event.n.u1ErrorCodeValid = 1;
     3048    Event.n.u32ErrorCode     = 0;
    29593049    hmR0SvmSetPendingEvent(pVCpu, &Event);
    29603050}
     
    30273117}
    30283118
     3119/**
     3120 * Determines if an exception is a contributory exception. Contributory
     3121 * exceptions are ones which can cause double-faults. Page-fault is
     3122 * intentionally not included here as it's a conditional contributory exception.
     3123 *
     3124 * @returns true if the exception is contributory, false otherwise.
     3125 * @param   uVector     The exception vector.
     3126 */
     3127DECLINLINE(bool) hmR0SvmIsContributoryXcpt(const uint32_t uVector)
     3128{
     3129    switch (uVector)
     3130    {
     3131        case X86_XCPT_GP:
     3132        case X86_XCPT_SS:
     3133        case X86_XCPT_NP:
     3134        case X86_XCPT_TS:
     3135        case X86_XCPT_DE:
     3136            return true;
     3137        default:
     3138            break;
     3139    }
     3140    return false;
     3141}
     3142
     3143
     3144/**
     3145 * Handle a condition that occurred while delivering an event through the guest
     3146 * IDT.
     3147 *
     3148 * @returns VBox status code (informational error codes included).
     3149 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
     3150 * @retval VINF_HM_DOUBLE_FAULT if a #DF condition was detected and we ought to
     3151 *         continue execution of the guest which will delivery the #DF.
     3152 * @retval VINF_EM_RESET if we detected a triple-fault condition.
     3153 *
     3154 * @param   pVCpu           Pointer to the VMCPU.
     3155 * @param   pCtx            Pointer to the guest-CPU context.
     3156 * @param   pSvmTransient   Pointer to the SVM transient structure.
     3157 *
     3158 * @remarks No-long-jump zone!!!
     3159 */
     3160static int hmR0SvmCheckExitDueToEventDelivery(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
     3161{
     3162    int rc = VINF_SUCCESS;
     3163    PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcb;
     3164
     3165    /* See AMD spec. 15.7.3 "EXITINFO Pseudo-Code". The EXITINTINFO (if valid) contains the prior exception (IDT vector)
     3166     * that was trying to be delivered to the guest which caused a #VMEXIT which was intercepted (Exit vector). */
     3167    if (pVmcb->ctrl.ExitIntInfo.n.u1Valid)
     3168    {
     3169        if (pVmcb->ctrl.ExitIntInfo.n.u3Type == SVM_EVENT_EXCEPTION)
     3170        {
     3171            typedef enum
     3172            {
     3173                SVMREFLECTXCPT_XCPT,    /* Reflect the exception to the guest or for further evaluation by VMM. */
     3174                SVMREFLECTXCPT_DF,      /* Reflect the exception as a double-fault to the guest. */
     3175                SVMREFLECTXCPT_TF,      /* Indicate a triple faulted state to the VMM. */
     3176                SVMREFLECTXCPT_NONE     /* Nothing to reflect. */
     3177            } SVMREFLECTXCPT;
     3178
     3179            SVMREFLECTXCPT enmReflect = SVMREFLECTXCPT_NONE;
     3180
     3181            if (pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0 <= SVM_EXIT_EXCEPTION_1F)
     3182            {
     3183                uint8_t uExitVector = (uint8_t)(pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0);
     3184                uint8_t uIdtVector  = pVmcb->ctrl.ExitIntInfo.n.u8Vector;
     3185
     3186                if (   uExitVector == X86_XCPT_PF
     3187                    && uIdtVector  == X86_XCPT_PF)
     3188                {
     3189                    pSvmTransient->fVectoringPF = true;
     3190                    Log4(("IDT: Vectoring #PF uCR2=%#RX64\n", pCtx->cr2));
     3191                }
     3192                else if (   (pVmcb->ctrl.u32InterceptException & HMSVM_CONTRIBUTORY_XCPT_MASK)
     3193                         && hmR0SvmIsContributoryXcpt(uExitVector)
     3194                         && (   hmR0SvmIsContributoryXcpt(uIdtVector)
     3195                             || uIdtVector == X86_XCPT_PF))
     3196               {
     3197                   enmReflect = SVMREFLECTXCPT_DF;
     3198               }
     3199               else if (uIdtVector == X86_XCPT_DF)
     3200                   enmReflect = SVMREFLECTXCPT_TF;
     3201               else
     3202                   enmReflect = SVMREFLECTXCPT_XCPT;
     3203            }
     3204            else
     3205            {
     3206                /*
     3207                 * If event delivery caused an #VMEXIT that is not an exception (e.g. #NPF) then reflect the original
     3208                 * exception to the guest after handling the VM-exit.
     3209                 */
     3210                enmReflect = SVMREFLECTXCPT_XCPT;
     3211            }
     3212        }
     3213        else if (pVmcb->ctrl.ExitIntInfo.n.u3Type != SVM_EVENT_SOFTWARE_INT)
     3214        {
     3215            /* Ignore software interrupts (INT n) as they reoccur when restarting the instruction. */
     3216            enmReflect = SVMREFLECTXCPT_XCPT;
     3217        }
     3218
     3219        switch (enmReflect)
     3220        {
     3221            case SVMREFLECTXCPT_XCPT:
     3222            {
     3223                pVCpu->hm.s.Event.u64IntrInfo = pVmcb->ctrl.ExitIntInfo.u;
     3224                pVCpu->hm.s.Event.fPending = true;
     3225
     3226                /* If uExitVector is #PF, CR2 value will be updated from the VMCB if it's a guest #PF. See hmR0SvmExitXcptPF(). */
     3227                Log4(("IDT: Pending vectoring event %#RX64 ErrValid=%RTbool Err=%#RX32\n", pVmcb->ctrl.ExitIntInfo.u,
     3228                      !!pVmcb->ctrl.ExitIntInfo.n.u1ErrorCodeValid, pVmcb->ctrl.ExitIntInfo.n.u32ErrorCode));
     3229                break;
     3230            }
     3231
     3232            case SVMREFLECTXCPT_DF:
     3233            {
     3234                hmR0SvmSetPendingXcptDF(pVCpu);
     3235                rc = VINF_HM_DOUBLE_FAULT;
     3236                Log4(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntrInfo,
     3237                      uIdtVector, uExitVector));
     3238                break;
     3239            }
     3240
     3241            case SVMREFLECTXCPT_TF:
     3242            {
     3243                rc = VINF_EM_RESET;
     3244                Log4(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector, uExitVector));
     3245                break;
     3246            }
     3247
     3248            default:
     3249                Assert(rc == VINF_SUCCESS);
     3250                break;
     3251        }
     3252    }
     3253    Assert(rc == VINF_SUCCESS || rc == VINF_HM_DOUBLE_FAULT || rc == VINF_EM_RESET);
     3254    return rc;
     3255}
     3256
    30293257
    30303258/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
     
    32143442
    32153443        if (   rc == VINF_EM_HALT
    3216             && EMShouldContinueAfterHalt(pVCpu, pMixedCtx))
     3444            && EMShouldContinueAfterHalt(pVCpu, pCtx))
    32173445        {
    32183446            rc = VINF_SUCCESS;
     
    35413769
    35423770                        /* Paranoia. */
    3543                         pMixedCtx->dr[7] &= 0xffffffff;                                             /* Upper 32 bits MBZ. */
    3544                         pMixedCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15));   /* MBZ. */
    3545                         pMixedCtx->dr[7] |= 0x400;                                                  /* MB1. */
     3771                        pCtx->dr[7] &= 0xffffffff;                                             /* Upper 32 bits MBZ. */
     3772                        pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15));   /* MBZ. */
     3773                        pCtx->dr[7] |= 0x400;                                                  /* MB1. */
    35463774
    35473775                        pVmcb->guest.u64DR7 = pCtx->dr[7];
     
    35843812    PVM pVM = pVCpu->CTX_SUFF(pVM);
    35853813    Assert(pVM->hm.s.fNestedPaging);
     3814
     3815    HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
    35863816
    35873817    /* See AMD spec. 15.25.6 "Nested versus Guest Page Faults, Fault Ordering" for VMCB details for #NPF. */
     
    37543984    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
    37553985
    3756     /* -XXX- @todo Vectoring pagefaults!! */
     3986    HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
    37573987
    37583988    /* See AMD spec. 15.12.15 "#PF (Page Fault)". */
     
    37613991    RTGCUINTPTR uFaultAddress = pVmcb->ctrl.u64ExitInfo2;
    37623992
    3763 #if defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) || defined(HMVMX_ALWAYS_TRAP_PF)
     3993#if defined(HMSVM_ALWAYS_TRAP_ALL_XCPTS) || defined(HMSVM_ALWAYS_TRAP_PF)
    37643994    if (pVM->hm.s.fNestedPaging)
    37653995    {
    3766         /* A genuine guest #PF, reflect it to the guest. */
    3767         Log4(("#PF: Guest page fault at %04X:%RGv FaultAddr=%RGv ErrCode=%#x\n", pCtx->cs, (RTGCPTR)pCtx->rip, uFaultAddress,
    3768               u32ErrCode));
    3769         hmR0SvmSetPendingXcptPF(pVCpu, pCtx, u32ErrCode, uFaultAddress);
     3996        pVCpu->hm.s.Event.fPending = false;     /* In case it's a contributory or vectoring #PF. */
     3997        if (!pSvmTransient->fVectoringPF)
     3998        {
     3999            /* A genuine guest #PF, reflect it to the guest. */
     4000            hmR0SvmSetPendingXcptPF(pVCpu, pCtx, u32ErrCode, uFaultAddress);
     4001            Log4(("#PF: Guest page fault at %04X:%RGv FaultAddr=%RGv ErrCode=%#x\n", pCtx->cs, (RTGCPTR)pCtx->rip, uFaultAddress,
     4002                  u32ErrCode));
     4003        }
     4004        else
     4005        {
     4006            /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
     4007            hmR0VmxSetPendingXcptDF(pVCpu);
     4008            Log4(("Pending #DF due to vectoring #PF. NP\n"));
     4009        }
     4010        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
    37704011        return VINF_SUCCESS;
    37714012    }
     
    38054046
    38064047    TRPMAssertXcptPF(pVCpu, uFaultAddress, u32ErrCode);
    3807     int rc = PGMTrap0eHandler(pVCpu, errCode, CPUMCTX2CORE(pCtx), (RTGCPTR)uFaultAddress);
     4048    rc = PGMTrap0eHandler(pVCpu, errCode, CPUMCTX2CORE(pCtx), (RTGCPTR)uFaultAddress);
    38084049
    38094050    Log2(("#PF rc=%Rrc\n", rc));
     
    38174058    else if (rc == VINF_EM_RAW_GUEST_TRAP)
    38184059    {
    3819         /* It's a guest page fault and needs to be reflected to the guest. */
    3820 
    3821         STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
    3822         u32ErrCode = TRPMGetErrorCode(pVCpu);        /* The error code might have been changed. */
    3823         TRPMResetTrap(pVCpu);
    3824 
    3825         hmR0SvmSetPendingXcptPF(pVCpu, pCtx, u32ErrCode, uFaultAddress);
     4060        if (!pSvmTransient->fVectoringPF)
     4061        {
     4062            /* It's a guest page fault and needs to be reflected to the guest. */
     4063            u32ErrCode = TRPMGetErrorCode(pVCpu);        /* The error code might have been changed. */
     4064            TRPMResetTrap(pVCpu);
     4065
     4066            hmR0SvmSetPendingXcptPF(pVCpu, pCtx, u32ErrCode, uFaultAddress);
     4067        }
     4068        else
     4069        {
     4070            /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
     4071            TRPMResetTrap(pVCpu);
     4072            pVCpu->hm.s.Event.fPending = false;     /* Clear pending #PF to replace it with #DF. */
     4073            hmR0SvmSetPendingXcptDF(pVCpu);
     4074            Log4(("#PF: Pending #DF due to vectoring #PF\n"));
     4075        }
     4076
    38264077        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
    38274078        return VINF_SUCCESS;
     
    38424093    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
    38434094
    3844 #ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
     4095    HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
     4096
     4097#ifndef HMSVM_ALWAYS_TRAP_ALL_XCPTS
    38454098    Assert(!CPUMIsGuestFPUStateActive(pVCpu));
    38464099#endif
     
    38704123HMSVM_EXIT_DECL hmR0SvmExitXcptMF(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
    38714124{
    3872     int rc;
    3873     if (!(pMixedCtx->cr0 & X86_CR0_NE))
     4125    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
     4126
     4127    HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
     4128
     4129    if (!(pCtx->cr0 & X86_CR0_NE))
    38744130    {
    38754131        /* Old-style FPU error reporting needs some extra work. */
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