VirtualBox

Changeset 74633 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Oct 6, 2018 6:29:16 AM (6 years ago)
Author:
vboxsync
Message:

VMM/IEM: Nested VMX: bugref:9180 VM-exit bits; Add Mov-to-cr8 and mov-from-cr8 intercepts and TPR virtualization for TPR-below threshold VM-exit.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h

    r74632 r74633  
    52035203                /*
    52045204                 * If the Mov-from-CR8 doesn't cause a VM-exit, bits 7:4 of the VTPR is copied
    5205                  * to bits 0:3 of the destination operand and bits 63:4 are cleared.
     5205                 * to bits 0:3 of the destination operand. Bits 63:4 of the destination operand
     5206                 * are cleared.
    52065207                 *
    5207                  * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation".
     5208                 * See Intel Spec. 29.3 "Virtualizing CR8-based TPR Accesses"
    52085209                 */
    52095210                if (IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_USE_TPR_SHADOW))
     
    57255726            }
    57265727
     5728#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
     5729            if (   IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
     5730                && IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_USE_TPR_SHADOW))
     5731            {
     5732                /*
     5733                 * If the Mov-to-CR8 doesn't cause a VM-exit, bits 0:3 of the source operand
     5734                 * is copied to bits 7:4 of the VTPR. Bits 0:3 and bits 31:8 of the VTPR are
     5735                 * cleared. Following this the processor performs TPR virtualization.
     5736                 *
     5737                 * See Intel Spec. 29.3 "Virtualizing CR8-based TPR Accesses"
     5738                 */
     5739                uint32_t const uVTpr = (uNewCrX & 0xf) << 4;
     5740                iemVmxVirtApicWriteRaw32(pVCpu, uVTpr, XAPIC_OFF_TPR);
     5741                rcStrict = iemVmxVmexitTprVirtualization(pVCpu, cbInstr);
     5742                if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
     5743                    return rcStrict;
     5744                rcStrict = VINF_SUCCESS;
     5745                break;
     5746            }
     5747#endif
     5748
    57275749#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    57285750            if (CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
     
    57955817        {
    57965818            case 0:
    5797             case 4:
    5798                 rcStrict = iemVmxVmexitInstrMovToCr0Cr4(pVCpu, iCrReg, &uNewCrX, iGReg, cbInstr);
    5799                 break;
    5800             case 3:
    5801                 rcStrict = iemVmxVmexitInstrMovToCr3(pVCpu, uNewCrX, iGReg, cbInstr);
    5802                 break;
    5803             default:
    5804                 break;
    5805         }
    5806 
     5819            case 4: rcStrict = iemVmxVmexitInstrMovToCr0Cr4(pVCpu, iCrReg, &uNewCrX, iGReg, cbInstr);   break;
     5820            case 3: rcStrict = iemVmxVmexitInstrMovToCr3(pVCpu, uNewCrX, iGReg, cbInstr);               break;
     5821            case 8: rcStrict = iemVmxVmexitInstrMovToCr8(pVCpu, iGReg, cbInstr);                        break;
     5822        }
    58075823        if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
    58085824                return rcStrict;
  • trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h

    r74632 r74633  
    910910{
    911911    Assert(idxCr3Target < VMX_V_CR3_TARGET_COUNT);
    912 
    913912    uint8_t  const  uWidth         = VMX_VMCS_ENC_WIDTH_NATURAL;
    914913    uint8_t  const  uType          = VMX_VMCS_ENC_TYPE_CONTROL;
     
    935934{
    936935    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint32_t));
    937 
    938936    uint8_t  const *pbVirtApic = (const uint8_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
    939937    Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage));
    940     uint32_t const uValue      = *(const uint32_t *)(pbVirtApic + offReg);
    941     return uValue;
     938    uint32_t const uReg = *(const uint32_t *)(pbVirtApic + offReg);
     939    return uReg;
     940}
     941
     942
     943/**
     944 * Writes a 32-bit register to the virtual-APIC page at the given offset.
     945 *
     946 * @param   pVCpu       The cross context virtual CPU structure.
     947 * @param   uReg        The register value to write.
     948 * @param   offReg      The offset of the register being written.
     949 */
     950DECLINLINE(void) iemVmxVirtApicWriteRaw32(PVMCPU pVCpu, uint32_t uReg, uint8_t offReg)
     951{
     952    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint32_t));
     953    uint8_t *pbVirtApic = (uint8_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
     954    Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage));
     955    *(uint32_t *)(pbVirtApic + offReg) = uReg;
    942956}
    943957
     
    13861400 * @param   pVCpu       The cross context virtual CPU structure.
    13871401 * @param   cbInstr     The VM-exit instruction length in bytes.
     1402 *
     1403 * @remarks Callers may clear this field to 0. Hence, this function does not check
     1404 *          the validity of the instruction length.
    13881405 */
    13891406DECL_FORCE_INLINE(void) iemVmxVmcsSetExitInstrLen(PVMCPU pVCpu, uint32_t cbInstr)
     
    20832100     * Save guest RIP, RSP and RFLAGS.
    20842101     * See Intel spec. 27.3.3 "Saving RIP, RSP and RFLAGS".
    2085      */
     2102     *
     2103     * For trap-like VM-exits we must advance the RIP by the length of the instruction.
     2104     * Callers must pass the instruction length in the VM-exit instruction length
     2105     * field though it is undefined for such VM-exits. After updating RIP here, we clear
     2106     * the VM-exit instruction length field.
     2107     *
     2108     * See Intel spec. 27.1 "Architectural State Before A VM Exit"
     2109     */
     2110    if (HMVmxIsTrapLikeVmexit(uExitReason))
     2111    {
     2112        uint8_t const cbInstr = pVmcs->u32RoExitInstrLen;
     2113        AssertMsg(cbInstr >= 1 && cbInstr <= 15, ("uReason=%u cbInstr=%u\n", uExitReason, cbInstr));
     2114        iemRegAddToRipAndClearRF(pVCpu, cbInstr);
     2115        iemVmxVmcsSetExitInstrLen(pVCpu, 0 /* cbInstr */);
     2116    }
     2117
    20862118    /* We don't support enclave mode yet. */
    20872119    pVmcs->u64GuestRip.u    = pVCpu->cpum.GstCtx.rip;
     
    31593191 *
    31603192 * @returns VBox strict status code.
     3193 * @retval VINF_VMX_INTERCEPT_NOT_ACTIVE if the Mov instruction did not cause a
     3194 *         VM-exit.
    31613195 * @param   pVCpu       The cross context virtual CPU structure.
    31623196 * @param   iGReg       The general register to which the CR8 value is being stored.
     
    31853219                         | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_GENREG,   iGReg);
    31863220        return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
     3221    }
     3222
     3223    return VINF_VMX_INTERCEPT_NOT_ACTIVE;
     3224}
     3225
     3226
     3227/**
     3228 * VMX VM-exit handler for VM-exits due to 'Mov CR8,GReg' (CR8 write).
     3229 *
     3230 * @returns VBox strict status code.
     3231 * @param   pVCpu       The cross context virtual CPU structure.
     3232 * @param   iGReg       The general register from which the CR8 value is being
     3233 *                      loaded.
     3234 * @param   cbInstr     The instruction length in bytes.
     3235 */
     3236IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrMovToCr8(PVMCPU pVCpu, uint8_t iGReg, uint8_t cbInstr)
     3237{
     3238    PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     3239    Assert(pVmcs);
     3240
     3241    /*
     3242     * If the CR8-load exiting control is set, we must cause a VM-exit.
     3243     * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
     3244     */
     3245    if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_CR8_LOAD_EXIT)
     3246    {
     3247        Log2(("mov_Cr_Rd: (CR8) Guest intercept -> VM-exit\n"));
     3248
     3249        VMXVEXITINFO ExitInfo;
     3250        RT_ZERO(ExitInfo);
     3251        ExitInfo.uReason = VMX_EXIT_MOV_CRX;
     3252        ExitInfo.cbInstr = cbInstr;
     3253
     3254        ExitInfo.u64Qual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_REGISTER, 8) /* CR8 */
     3255                         | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_ACCESS,   VMX_EXIT_QUAL_CRX_ACCESS_WRITE)
     3256                         | RT_BF_MAKE(VMX_BF_EXIT_QUAL_CRX_GENREG,   iGReg);
     3257        return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
     3258    }
     3259
     3260    return VINF_VMX_INTERCEPT_NOT_ACTIVE;
     3261}
     3262
     3263
     3264/**
     3265 * VMX VM-exit handler for TPR virtualization.
     3266 *
     3267 * @returns VBox strict status code.
     3268 * @param   pVCpu       The cross context virtual CPU structure.
     3269 * @param   cbInstr     The instruction length in bytes.
     3270 */
     3271IEM_STATIC VBOXSTRICTRC iemVmxVmexitTprVirtualization(PVMCPU pVCpu, uint8_t cbInstr)
     3272{
     3273    PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     3274    Assert(pVmcs);
     3275
     3276    Assert(pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
     3277    Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY));    /* We don't support virtual-interrupt delivery yet. */
     3278
     3279    uint32_t const uTprThreshold = pVmcs->u32TprThreshold;
     3280    uint32_t const uVTpr         = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
     3281
     3282    /*
     3283     * If the VTPR falls below the TPR threshold, we must cause a VM-exit.
     3284     * See Intel spec. 29.1.2 "TPR Virtualization".
     3285     */
     3286    if (((uVTpr >> 4) & 0xf) < uTprThreshold)
     3287    {
     3288        Log2(("tpr_virt: uVTpr=%u uTprThreshold=%u -> VM-exit\n", uVTpr, uTprThreshold));
     3289
     3290        /*
     3291         * This is a trap-like VM-exit. We pass the instruction length along in the VM-exit
     3292         * instruction length field and let the VM-exit handler update the RIP when appropriate.
     3293         * It will then clear the VM-exit instruction length field before completing the VM-exit.
     3294         */
     3295        iemVmxVmcsSetExitInstrLen(pVCpu, cbInstr);
     3296        return iemVmxVmexit(pVCpu, VMX_EXIT_TPR_BELOW_THRESHOLD);
    31873297    }
    31883298
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