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 EXITINFO fields when
DecodeAssists is exposed to L1.

Generate EXITINFO1 with the GPR number for MOV CR/DR, the interrupt vector
for INTn, and the linear address for INVLPG.  Set EXITINFO1 to zero for
CLTS, LMSW, SMSW, and INVLPGA; the INVLPGA address remains in guest rAX.
Clear EXITINFO2 for all covered intercepts and leave unrelated intercepts
unchanged.

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

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index e02a38da5296..cc35afb59623 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -4754,6 +4754,52 @@ static const struct __x86_intercept {
 #undef POST_EX
 #undef POST_MEM
 
+static void svm_prepare_decode_assist_exit_info(struct kvm_vcpu *vcpu,
+                                               const struct 
x86_instruction_info *info)
+{
+       struct vmcb *vmcb = to_svm(vcpu)->vmcb;
+       u64 exit_info_1;
+
+       if (!guest_cpu_cap_has(vcpu, X86_FEATURE_DECODEASSISTS))
+               return;
+
+       switch (info->intercept) {
+       case x86_intercept_cr_read:
+       case x86_intercept_cr_write:
+               /* MOV CRx: bit 63 set, GPR number in bits 3:0. */
+               exit_info_1 = BIT_ULL(63) | (info->modrm_rm & 0xf);
+               break;
+       case x86_intercept_clts:
+       case x86_intercept_lmsw:
+       case x86_intercept_smsw:
+               /* CLTS/LMSW/SMSW: no decode information, bit 63 clear. */
+               exit_info_1 = 0;
+               break;
+       case x86_intercept_dr_read:
+       case x86_intercept_dr_write:
+               /* MOV DRx: GPR number in bits 3:0. */
+               exit_info_1 = info->modrm_rm & 0xf;
+               break;
+       case x86_intercept_intn:
+               /* INTn: software interrupt number in bits 7:0. */
+               exit_info_1 = info->src_val & 0xff;
+               break;
+       case x86_intercept_invlpg:
+               /* INVLPG: linear address of the target page. */
+               exit_info_1 = info->intercept_linear_addr;
+               break;
+       case x86_intercept_invlpga:
+               /* INVLPGA: the address remains available in guest rAX. */
+               exit_info_1 = 0;
+               break;
+       default:
+               return;
+       }
+
+       vmcb->control.exit_info_1 = exit_info_1;
+       vmcb->control.exit_info_2 = 0;
+}
+
 static int svm_check_intercept(struct kvm_vcpu *vcpu,
                               struct x86_instruction_info *info,
                               enum x86_intercept_stage stage,
@@ -4875,6 +4921,8 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
                break;
        }
 
+       svm_prepare_decode_assist_exit_info(vcpu, info);
+
        /* TODO: Advertise NRIPS to guest hypervisor unconditionally */
        if (static_cpu_has(X86_FEATURE_NRIPS))
                vmcb->control.next_rip  = info->next_rip;
-- 
2.43.7


Reply via email to