When the x86 emulator encounters an instruction intercepted by L1,
svm_check_intercept() synthesizes a nested VM-Exit without fresh hardware
DecodeAssist state.  Populate the architectural EXITINFO1 field when
DecodeAssists is exposed to L1.

Provide the GPR number for MOV CR/DR, the interrupt vector for INTn, and
the linear address for INVLPG.  Leave EXITINFO1 clear for CLTS, LMSW,
SMSW, selective CR0 writes, and INVLPGA; the INVLPGA address remains in
guest rAX.  Leave EXITINFO1 unchanged when DecodeAssists is not exposed,
and leave unrelated intercepts unchanged.

Signed-off-by: Tina Zhang <[email protected]>
---
 arch/x86/kvm/svm/svm.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index ea647938a2a6..6834e1101bb6 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -4837,6 +4837,7 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
        int vmexit, ret = X86EMUL_CONTINUE;
        struct __x86_intercept icpt_info;
        struct vmcb *vmcb = svm->vmcb;
+       bool decode_assists;
 
        if (info->intercept >= ARRAY_SIZE(x86_intercept_map))
                goto out;
@@ -4846,14 +4847,26 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
        if (stage != icpt_info.stage)
                goto out;
 
+       decode_assists = guest_cpu_cap_has(vcpu, X86_FEATURE_DECODEASSISTS);
+
        switch (icpt_info.exit_code) {
        case SVM_EXIT_READ_CR0:
                if (info->intercept == x86_intercept_cr_read)
                        icpt_info.exit_code += info->modrm_reg;
+
+               if (decode_assists)
+                       vmcb->control.exit_info_1 =
+                               info->intercept == x86_intercept_cr_read ?
+                               BIT_ULL(63) | (info->modrm_rm & 0xf) : 0;
                break;
        case SVM_EXIT_WRITE_CR0: {
                unsigned long cr0, val;
 
+               if (decode_assists)
+                       vmcb->control.exit_info_1 =
+                               info->intercept == x86_intercept_cr_write ?
+                               BIT_ULL(63) | (info->modrm_rm & 0xf) : 0;
+
                /*
                 * Adjust the exit code accordingly if a CR other than CR0 is
                 * being written, and skip straight to the common handling as
@@ -4891,13 +4904,30 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
                 */
                cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK;
                val = info->src_val  & ~SVM_CR0_SELECTIVE_MASK;
-               if (cr0 ^ val)
+               if (cr0 ^ val) {
                        icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE;
+                       if (decode_assists)
+                               vmcb->control.exit_info_1 = 0;
+               }
                break;
        }
        case SVM_EXIT_READ_DR0:
        case SVM_EXIT_WRITE_DR0:
                icpt_info.exit_code += info->modrm_reg;
+               if (decode_assists)
+                       vmcb->control.exit_info_1 = info->modrm_rm & 0xf;
+               break;
+       case SVM_EXIT_SWINT:
+               if (decode_assists)
+                       vmcb->control.exit_info_1 = info->src_val & 0xff;
+               break;
+       case SVM_EXIT_INVLPG:
+               if (decode_assists)
+                       vmcb->control.exit_info_1 = info->invlpg_linear_addr;
+               break;
+       case SVM_EXIT_INVLPGA:
+               if (decode_assists)
+                       vmcb->control.exit_info_1 = 0;
                break;
        case SVM_EXIT_MSR:
                if (info->intercept == x86_intercept_wrmsr)
-- 
2.43.7


Reply via email to