VirtualBox

儲存庫 vbox 的更動 75884


忽略:
時間撮記:
2018-12-3 上午04:28:51 (6 年 以前)
作者:
vboxsync
訊息:

VMM/IEM: Nested VMX: bugref:9180 VMX-preemption timer VM-exit bits.

檔案:
修改 1 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h

    r75735 r75884  
    16331633
    16341634/**
     1635 * Calculates the current VMX-preemption timer value.
     1636 *
     1637 * @param   pVCpu       The cross context virtual CPU structure.
     1638 */
     1639IEM_STATIC uint32_t iemVmxCalcPreemptTimer(PVMCPU pVCpu)
     1640{
     1641    PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     1642    Assert(pVmcs);
     1643
     1644    /*
     1645     * Assume the following:
     1646     * PreemptTimerShift = 5
     1647     * VmcsPreemptTimer  = 2 (i.e. need to decrement by 1 every 2 * RT_BIT(5) = 20000 TSC ticks)
     1648     * VmentryTick       = 50000 (TSC at time of VM-entry)
     1649     *
     1650     * CurTick   Delta    PreemptTimerVal
     1651     * ----------------------------------
     1652     *  60000    10000    2
     1653     *  80000    30000    1
     1654     *  90000    40000    0  -> VM-exit.
     1655     *
     1656     * If Delta >= VmcsPreemptTimer * RT_BIT(PreemptTimerShift) cause a VMX-preemption timer VM-exit.
     1657     * The saved VMX-preemption timer value is calculated as follows:
     1658     * PreemptTimerVal = VmcsPreemptTimer - (Delta / (VmcsPreemptTimer * RT_BIT(PreemptTimerShift)))
     1659     * E.g.:
     1660     *  Delta  = 10000
     1661     *    Tmp    = 10000 / (2 * 10000) = 0.5
     1662     *    NewPt  = 2 - 0.5 = 2
     1663     *  Delta  = 30000
     1664     *    Tmp    = 30000 / (2 * 10000) = 1.5
     1665     *    NewPt  = 2 - 1.5 = 1
     1666     *  Delta  = 40000
     1667     *    Tmp    = 40000 / 20000 = 2
     1668     *    NewPt  = 2 - 2 = 0
     1669     */
     1670    uint64_t const uCurTick        = TMCpuTickGetNoCheck(pVCpu);
     1671    uint64_t const uVmentryTick    = pVCpu->cpum.GstCtx.hwvirt.vmx.uVmentryTick;
     1672    uint64_t const uDelta          = uCurTick - uVmentryTick;
     1673    uint32_t const uVmcsPreemptVal = pVmcs->u32PreemptTimer;
     1674    uint32_t const uPreemptTimer   = uVmcsPreemptVal
     1675                                   - ASMDivU64ByU32RetU32(uDelta, uVmcsPreemptVal * RT_BIT(VMX_V_PREEMPT_TIMER_SHIFT));
     1676    return uPreemptTimer;
     1677}
     1678
     1679
     1680/**
    16351681 * Saves guest segment registers, GDTR, IDTR, LDTR, TR as part of VM-exit.
    16361682 *
     
    17911837    }
    17921838
    1793     /* Save VMX-preemption timer value. */
    1794     if (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER)
    1795     {
    1796         uint32_t uPreemptTimer;
    1797         if (uExitReason == VMX_EXIT_PREEMPT_TIMER)
    1798             uPreemptTimer = 0;
    1799         else
    1800         {
    1801             /*
    1802              * Assume the following:
    1803              * PreemptTimerShift = 5
    1804              * VmcsPreemptTimer  = 2 (i.e. need to decrement by 1 every 2 * RT_BIT(5) = 20000 TSC ticks)
    1805              * VmentryTick       = 50000 (TSC at time of VM-entry)
    1806              *
    1807              * CurTick   Delta    PreemptTimerVal
    1808              * ----------------------------------
    1809              *  60000    10000    2
    1810              *  80000    30000    1
    1811              *  90000    40000    0  -> VM-exit.
    1812              *
    1813              * If Delta >= VmcsPreemptTimer * RT_BIT(PreemptTimerShift) cause a VMX-preemption timer VM-exit.
    1814              * The saved VMX-preemption timer value is calculated as follows:
    1815              * PreemptTimerVal = VmcsPreemptTimer - (Delta / (VmcsPreemptTimer * RT_BIT(PreemptTimerShift)))
    1816              * E.g.:
    1817              *  Delta  = 10000
    1818              *    Tmp    = 10000 / (2 * 10000) = 0.5
    1819              *    NewPt  = 2 - 0.5 = 2
    1820              *  Delta  = 30000
    1821              *    Tmp    = 30000 / (2 * 10000) = 1.5
    1822              *    NewPt  = 2 - 1.5 = 1
    1823              *  Delta  = 40000
    1824              *    Tmp    = 40000 / 20000 = 2
    1825              *    NewPt  = 2 - 2 = 0
    1826              */
    1827             uint64_t const uCurTick        = TMCpuTickGetNoCheck(pVCpu);
    1828             uint64_t const uVmentryTick    = pVCpu->cpum.GstCtx.hwvirt.vmx.uVmentryTick;
    1829             uint64_t const uDelta          = uCurTick - uVmentryTick;
    1830             uint32_t const uVmcsPreemptVal = pVmcs->u32PreemptTimer;
    1831             uPreemptTimer = uVmcsPreemptVal - ASMDivU64ByU32RetU32(uDelta, uVmcsPreemptVal * RT_BIT(VMX_V_PREEMPT_TIMER_SHIFT));
    1832         }
    1833 
    1834         pVmcs->u32PreemptTimer = uPreemptTimer;
    1835     }
    1836 
     1839    /*
     1840     * Save the VMX-preemption timer value back into the VMCS if the feature is enabled.
     1841     *
     1842     * For VMX-preemption timer VM-exits, we should have already written back 0 if the
     1843     * feature is supported back into the VMCS, and thus there is nothing further to do here.
     1844     */
     1845    if (   uExitReason != VMX_EXIT_PREEMPT_TIMER
     1846        && (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER))
     1847        pVmcs->u32PreemptTimer = iemVmxCalcPreemptTimer(pVCpu);
    18371848
    18381849    /* PDPTEs. */
     
    37263737IEM_STATIC VBOXSTRICTRC iemVmxVmexitPreemptTimer(PVMCPU pVCpu)
    37273738{
    3728     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     3739    PVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
    37293740    Assert(pVmcs);
    3730     Assert(pVmcs->u32PinCtls & VMX_PIN_CTLS_PREEMPT_TIMER);
    3731     NOREF(pVmcs);
    3732 
    3733     iemVmxVmcsSetExitQual(pVCpu, 0);
    3734     return iemVmxVmexit(pVCpu, VMX_EXIT_PREEMPT_TIMER);
     3741
     3742    /* Check if the guest has enabled VMX-preemption timers in the first place. */
     3743    if (pVmcs->u32PinCtls & VMX_PIN_CTLS_PREEMPT_TIMER)
     3744    {
     3745        /*
     3746         * Calculate the current VMX-preemption timer value.
     3747         * Only if the value has reached zero, we cause the VM-exit.
     3748         */
     3749        uint32_t uPreemptTimer = iemVmxCalcPreemptTimer(pVCpu);
     3750        if (!uPreemptTimer)
     3751        {
     3752            /* Save the VMX-preemption timer value (of 0) back in to the VMCS if the CPU supports this feature. */
     3753            if (pVmcs->u32ExitCtls & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER)
     3754                pVmcs->u32PreemptTimer = 0;
     3755
     3756            /* Cause the VMX-preemption timer VM-exit. The VM-exit qualification MBZ. */
     3757            iemVmxVmcsSetExitQual(pVCpu, 0);
     3758            return iemVmxVmexit(pVCpu, VMX_EXIT_PREEMPT_TIMER);
     3759        }
     3760    }
     3761
     3762    return VINF_VMX_INTERCEPT_NOT_ACTIVE;
    37353763}
    37363764
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette