VirtualBox

Changeset 27231 in vbox for trunk/src


Ignore:
Timestamp:
Mar 9, 2010 8:16:59 PM (15 years ago)
Author:
vboxsync
Message:

Implemented mwait extension for breaking on external interrupt when IF=0; completely untested

Location:
trunk/src/VBox/VMM
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/EM.cpp

    r26260 r27231  
    522522        rc = SSMR3PutU32(pSSM, pVCpu->em.s.enmPrevState);
    523523        AssertRCReturn(rc, rc);
     524
     525        /* Save mwait state. */
     526        rc = SSMR3PutU32(pSSM, pVCpu->em.s.mwait.fWait);
     527        AssertRCReturn(rc, rc);
     528        rc = SSMR3PutGCPtr(pSSM, pVCpu->em.s.mwait.uMWaitEAX);
     529        AssertRCReturn(rc, rc);
     530        rc = SSMR3PutGCPtr(pSSM, pVCpu->em.s.mwait.uMWaitECX);
     531        AssertRCReturn(rc, rc);
     532        rc = SSMR3PutGCPtr(pSSM, pVCpu->em.s.mwait.uMonitorEAX);
     533        AssertRCReturn(rc, rc);
     534        rc = SSMR3PutGCPtr(pSSM, pVCpu->em.s.mwait.uMonitorECX);
     535        AssertRCReturn(rc, rc);
     536        rc = SSMR3PutGCPtr(pSSM, pVCpu->em.s.mwait.uMonitorEDX);
     537        AssertRCReturn(rc, rc);
    524538    }
    525539    return VINF_SUCCESS;
     
    542556     */
    543557    if (    uVersion != EM_SAVED_STATE_VERSION
     558        &&  uVersion != EM_SAVED_STATE_VERSION_PRE_MWAIT
    544559        &&  uVersion != EM_SAVED_STATE_VERSION_PRE_SMP)
    545560    {
     
    570585            pVCpu->em.s.enmState = EMSTATE_SUSPENDED;
    571586        }
     587        if (uVersion > EM_SAVED_STATE_VERSION_PRE_MWAIT)
     588        {
     589            /* Load mwait state. */
     590            rc = SSMR3GetU32(pSSM, &pVCpu->em.s.mwait.fWait);
     591            AssertRCReturn(rc, rc);
     592            rc = SSMR3GetGCPtr(pSSM, &pVCpu->em.s.mwait.uMWaitEAX);
     593            AssertRCReturn(rc, rc);
     594            rc = SSMR3GetGCPtr(pSSM, &pVCpu->em.s.mwait.uMWaitECX);
     595            AssertRCReturn(rc, rc);
     596            rc = SSMR3GetGCPtr(pSSM, &pVCpu->em.s.mwait.uMonitorEAX);
     597            AssertRCReturn(rc, rc);
     598            rc = SSMR3GetGCPtr(pSSM, &pVCpu->em.s.mwait.uMonitorECX);
     599            AssertRCReturn(rc, rc);
     600            rc = SSMR3GetGCPtr(pSSM, &pVCpu->em.s.mwait.uMonitorEDX);
     601            AssertRCReturn(rc, rc);
     602        }
     603
    572604        Assert(!pVCpu->em.s.pCliStatTree);
    573605    }
     
    19692001                {
    19702002                    STAM_REL_PROFILE_START(&pVCpu->em.s.StatHalted, y);
    1971                     rc = VMR3WaitHalted(pVM, pVCpu, !(CPUMGetGuestEFlags(pVCpu) & X86_EFL_IF));
     2003                    if (pVCpu->em.s.mwait.fWait & EMMWAIT_FLAG_ACTIVE)
     2004                    {
     2005                        /* mwait has a special extension where it's woken up when an interrupt is pending even when IF=0. */
     2006                        rc = VMR3WaitHalted(pVM, pVCpu, !(pVCpu->em.s.mwait.fWait & EMMWAIT_FLAG_BREAKIRQIF0) && !(CPUMGetGuestEFlags(pVCpu) & X86_EFL_IF));
     2007                        pVCpu->em.s.mwait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0);
     2008                    }
     2009                    else
     2010                        rc = VMR3WaitHalted(pVM, pVCpu, !(CPUMGetGuestEFlags(pVCpu) & X86_EFL_IF));
     2011
    19722012                    STAM_REL_PROFILE_STOP(&pVCpu->em.s.StatHalted, y);
    19732013                    break;
  • trunk/src/VBox/VMM/EMInternal.h

    r26260 r27231  
    4343
    4444/** The saved state version. */
    45 #define EM_SAVED_STATE_VERSION                          3
     45#define EM_SAVED_STATE_VERSION                          4
     46#define EM_SAVED_STATE_VERSION_PRE_MWAIT                3
    4647#define EM_SAVED_STATE_VERSION_PRE_SMP                  2
     48
     49
     50/**
     51 * MWait state flags.
     52 */
     53/* MWait activated. */
     54#define EMMWAIT_FLAG_ACTIVE             RT_BIT(0)
     55/* MWait will continue when an interrupt is pending even when IF=0. */
     56#define EMMWAIT_FLAG_BREAKIRQIF0        RT_BIT(1)
     57/* Monitor instruction was executed previously. */
     58#define EMMWAIT_FLAG_MONITOR_ACTIVE     RT_BIT(2)
     59
    4760
    4861/**
     
    336349#endif
    337350
     351    /* MWait halt state. */
     352    struct
     353    {
     354        uint32_t            fWait;          /* type of mwait; see EMMWAIT_FLAG_* */
     355        uint32_t            a32Padding[1];
     356        RTGCPTR             uMWaitEAX;      /* mwait hints */
     357        RTGCPTR             uMWaitECX;      /* mwait extensions */
     358        RTGCPTR             uMonitorEAX;    /* monitored address. */
     359        RTGCPTR             uMonitorECX;    /* monitor extension. */
     360        RTGCPTR             uMonitorEDX;    /* monitor hint. */
     361    } mwait;
     362
    338363    union
    339364    {
  • trunk/src/VBox/VMM/HWACCMInternal.h

    r27167 r27231  
    818818    STAMCOUNTER             StatExitHlt;
    819819    STAMCOUNTER             StatExitMwait;
     820    STAMCOUNTER             StatExitMonitor;
    820821    STAMCOUNTER             StatExitLMSW;
    821822    STAMCOUNTER             StatExitIOWrite;
  • trunk/src/VBox/VMM/VMMAll/EMAll.cpp

    r27129 r27231  
    27182718 * MONITOR Emulation.
    27192719 */
    2720 static int emInterpretMonitor(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
     2720VMMDECL(int) EMInterpretMonitor(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
    27212721{
    27222722    uint32_t u32Dummy, u32ExtFeatures, cpl;
    27232723
    2724     Assert(pDis->mode != CPUMODE_64BIT);    /** @todo check */
    27252724    if (pRegFrame->ecx != 0)
     2725    {
     2726        Log(("emInterpretMonitor: unexpected ecx=%x -> recompiler!!\n", pRegFrame->ecx));
    27262727        return VERR_EM_INTERPRETER; /* illegal value. */
     2728    }
    27272729
    27282730    /* Get the current privilege level. */
     
    27352737        return VERR_EM_INTERPRETER; /* not supported */
    27362738
     2739    pVCpu->em.s.mwait.uMonitorEAX = pRegFrame->rax;
     2740    pVCpu->em.s.mwait.uMonitorECX = pRegFrame->rcx;
     2741    pVCpu->em.s.mwait.uMonitorEDX = pRegFrame->rdx;
     2742    pVCpu->em.s.mwait.fWait |= EMMWAIT_FLAG_MONITOR_ACTIVE;
    27372743    return VINF_SUCCESS;
    27382744}
    27392745
     2746static int emInterpretMonitor(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
     2747{
     2748    return EMInterpretMonitor(pVM, pVCpu, pRegFrame);
     2749}
     2750
    27402751
    27412752/**
     
    27442755VMMDECL(int) EMInterpretMWait(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
    27452756{
    2746     uint32_t u32Dummy, u32ExtFeatures, cpl;
    2747 
    2748     /* @todo bit 1 is supposed to tell the cpu to wake us up on interrupts even if IF is cleared.
    2749      * Not sure which models. Intel docs say ecx and eax must be zero for Pentium 4 CPUs
    2750      * CPUID.05H.ECX[0] defines support for power management extensions (eax)
    2751      */
    2752     if (pRegFrame->ecx != 0)
    2753         return VERR_EM_INTERPRETER; /* illegal value. */
     2757    uint32_t u32Dummy, u32ExtFeatures, cpl, u32MWaitFeatures;
    27542758
    27552759    /* Get the current privilege level. */
     
    27622766        return VERR_EM_INTERPRETER; /* not supported */
    27632767
     2768    /*
     2769     * CPUID.05H.ECX[0] defines support for power management extensions (eax)
     2770     * CPUID.05H.ECX[1] defines support for interrupts as break events for mwait even when IF=0
     2771     */
     2772    CPUMGetGuestCpuId(pVCpu, 5, &u32Dummy, &u32Dummy, &u32MWaitFeatures, &u32Dummy);
     2773    if (pRegFrame->ecx > 1)
     2774    {
     2775        Log(("EMInterpretMWait: unexpected ecx value %x -> recompiler\n", pRegFrame->ecx));
     2776        return VERR_EM_INTERPRETER; /* illegal value. */
     2777    }
     2778
     2779    if (pRegFrame->ecx)
     2780    {
     2781        if (!(u32MWaitFeatures & X86_CPUID_MWAIT_ECX_BREAKIRQIF0))
     2782        {
     2783            Log(("EMInterpretMWait: unsupported X86_CPUID_MWAIT_ECX_BREAKIRQIF0 -> recompiler\n"));
     2784            return VERR_EM_INTERPRETER; /* illegal value. */
     2785        }
     2786
     2787        pVCpu->em.s.mwait.fWait = EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0;
     2788    }
     2789    else
     2790        pVCpu->em.s.mwait.fWait = EMMWAIT_FLAG_ACTIVE;
     2791
     2792    pVCpu->em.s.mwait.uMWaitEAX = pRegFrame->rax;
     2793    pVCpu->em.s.mwait.uMWaitECX = pRegFrame->rcx;
     2794
    27642795    /** @todo not completely correct */
    27652796    return VINF_EM_HALT;
     
    27682799static int emInterpretMWait(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize)
    27692800{
    2770     Assert(pDis->mode != CPUMODE_64BIT);    /** @todo check */
    2771 
    27722801    return EMInterpretMWait(pVM, pVCpu, pRegFrame);
    27732802}
     
    35003529}
    35013530
     3531/**
     3532 * Determine if we should continue after encountering a hlt or mwait instruction
     3533 *
     3534 * @returns boolean
     3535 * @param   pVCpu           The VMCPU to operate on.
     3536 * @param   pCtx            Current CPU context
     3537 */
     3538VMMDECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx)
     3539{
     3540    if (    pCtx->eflags.Bits.u1IF
     3541        ||  ((pVCpu->em.s.mwait.fWait & (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0)) == (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0)))
     3542    {
     3543        pVCpu->em.s.mwait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0);
     3544        return !!VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC));
     3545    }
     3546
     3547    return false;
     3548}
     3549
  • trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp

    r26152 r27231  
    344344                                        | SVM_CTRL2_INTERCEPT_SKINIT
    345345                                        | SVM_CTRL2_INTERCEPT_WBINVD
     346                                        | SVM_CTRL2_INTERCEPT_MONITOR
    346347                                        | SVM_CTRL2_INTERCEPT_MWAIT_UNCOND; /* don't execute mwait or else we'll idle inside the guest (host thinks the cpu load is high) */
    347348                                        ;
     
    23492350        STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitHlt);
    23502351        pCtx->rip++;    /* skip hlt */
    2351         if (    pCtx->eflags.Bits.u1IF
    2352             &&  VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)))
     2352        if (EMShouldContinueAfterHalt(pVCpu, pCtx))
    23532353            goto ResumeExecution;
    23542354
     
    23692369            if (    rc == VINF_SUCCESS
    23702370                ||  (   rc == VINF_EM_HALT
    2371                      && pCtx->eflags.Bits.u1IF
    2372                      && VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)))
     2371                     && EMShouldContinueAfterHalt(pVCpu, pCtx))
    23732372               )
    23742373                goto ResumeExecution;
     
    23762375        AssertMsg(rc == VERR_EM_INTERPRETER || rc == VINF_EM_HALT, ("EMU: mwait failed with %Rrc\n", rc));
    23772376        break;
     2377
     2378    case SVM_EXIT_MONITOR:
     2379    {
     2380        Log2(("SVM: monitor\n"));
     2381
     2382        STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMonitor);
     2383        rc = EMInterpretMonitor(pVM, pVCpu, CPUMCTX2CORE(pCtx));
     2384        if (rc == VINF_SUCCESS)
     2385        {
     2386            /* Update EIP and continue execution. */
     2387            pCtx->rip += 3;     /* Note: hardcoded opcode size assumption! */
     2388            goto ResumeExecution;
     2389        }
     2390        AssertMsg(rc == VERR_EM_INTERPRETER, ("EMU: monitor failed with %Rrc\n", rc));
     2391        break;
     2392    }
     2393       
    23782394
    23792395    case SVM_EXIT_VMMCALL:
     
    24822498        break;
    24832499
    2484     case SVM_EXIT_MONITOR:
    24852500    case SVM_EXIT_PAUSE:
    24862501    case SVM_EXIT_MWAIT_ARMED:
  • trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp

    r26296 r27231  
    413413                  | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_UNCOND_IO_EXIT
    414414                  | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDPMC_EXIT
     415                  | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MONITOR_EXIT
    415416                  | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MWAIT_EXIT;    /* don't execute mwait or else we'll idle inside the guest (host thinks the cpu load is high) */
    416417
     
    35303531    }
    35313532
     3533    case VMX_EXIT_MONITOR:              /* 39 Guest software attempted to execute MONITOR. */
     3534    {
     3535        Log2(("VMX: monitor\n"));
     3536
     3537        STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMonitor);
     3538        rc = EMInterpretMonitor(pVM, pVCpu, CPUMCTX2CORE(pCtx));
     3539        if (rc == VINF_SUCCESS)
     3540        {
     3541            /* Update EIP and continue execution. */
     3542            pCtx->rip += cbInstr;
     3543            goto ResumeExecution;
     3544        }
     3545        AssertMsg(rc == VERR_EM_INTERPRETER, ("EMU: monitor failed with %Rrc\n", rc));
     3546        break;
     3547    }
     3548
    35323549    case VMX_EXIT_WRMSR:                /* 32 WRMSR. Guest software attempted to execute WRMSR. */
    35333550        /* When an interrupt is pending, we'll let MSR_K8_LSTAR writes fault in our TPR patch code. */
     
    39753992        STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitHlt);
    39763993        pCtx->rip++;    /* skip hlt */
    3977         if (    pCtx->eflags.Bits.u1IF
    3978             &&  VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)))
     3994        if (EMShouldContinueAfterHalt(pVCpu, pCtx))
    39793995            goto ResumeExecution;
    39803996
     
    39954011            if (    rc == VINF_SUCCESS
    39964012                ||  (   rc == VINF_EM_HALT
    3997                      && pCtx->eflags.Bits.u1IF
    3998                      && VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)))
     4013                     && EMShouldContinueAfterHalt(pVCpu, pCtx))
    39994014               )
    40004015                goto ResumeExecution;
     
    40474062    case VMX_EXIT_RDMSR:                /* 31 RDMSR. Guest software attempted to execute RDMSR. */
    40484063    case VMX_EXIT_WRMSR:                /* 32 WRMSR. Guest software attempted to execute WRMSR. */
     4064    case VMX_EXIT_PAUSE:                /* 40 Guest software attempted to execute PAUSE. */
    40494065    case VMX_EXIT_MONITOR:              /* 39 Guest software attempted to execute MONITOR. */
    4050     case VMX_EXIT_PAUSE:                /* 40 Guest software attempted to execute PAUSE. */
    40514066        /* Note: If we decide to emulate them here, then we must sync the MSRs that could have been changed (sysenter, fs/gs base)!!! */
    40524067        rc = VERR_EM_INTERPRETER;
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