INVLPG's memory operand is decoded with NoAccess, and thus src_val does
not contain the operand address.  Intercept handlers therefore cannot
construct exit state that reports the linear address from the existing
x86_instruction_info fields.

Add get_invlpg_linear_addr() to compute the address through __linearize(),
using the same flags as em_invlpg(), and pass the result through
x86_instruction_info.

Signed-off-by: Tina Zhang <[email protected]>
---
 arch/x86/kvm/emulate.c     | 18 ++++++++++++++++++
 arch/x86/kvm/kvm_emulate.h |  1 +
 2 files changed, 19 insertions(+)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8071b372d233..1dfece6af81e 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -410,6 +410,9 @@ static int em_salc(struct x86_emulate_ctxt *ctxt)
        _fault ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE; \
 })
 
+static u64 get_invlpg_linear_addr(struct x86_emulate_ctxt *ctxt,
+                                 enum x86_intercept intercept);
+
 static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
                                    enum x86_intercept intercept,
                                    enum x86_intercept_stage stage)
@@ -427,6 +430,7 @@ static int emulator_check_intercept(struct x86_emulate_ctxt 
*ctxt,
                .src_type   = ctxt->src.type,
                .dst_type   = ctxt->dst.type,
                .ad_bytes   = ctxt->ad_bytes,
+               .invlpg_linear_addr = get_invlpg_linear_addr(ctxt, intercept),
                .rip        = ctxt->eip,
                .next_rip   = ctxt->_eip,
        };
@@ -702,6 +706,20 @@ static __always_inline int __linearize(struct 
x86_emulate_ctxt *ctxt,
                return emulate_gp(ctxt, 0);
 }
 
+static u64 get_invlpg_linear_addr(struct x86_emulate_ctxt *ctxt,
+                                 enum x86_intercept intercept)
+{
+       unsigned int max_size;
+       unsigned long linear = 0;
+
+       if (intercept != x86_intercept_invlpg)
+               return 0;
+
+       __linearize(ctxt, ctxt->src.addr.mem, &max_size, 1, ctxt->mode,
+                   &linear, X86EMUL_F_INVLPG);
+       return linear;
+}
+
 static int linearize(struct x86_emulate_ctxt *ctxt,
                     struct segmented_address addr,
                     unsigned size, bool write,
diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
index 3e375af15c03..d05558ef28ae 100644
--- a/arch/x86/kvm/kvm_emulate.h
+++ b/arch/x86/kvm/kvm_emulate.h
@@ -51,6 +51,7 @@ struct x86_instruction_info {
        u8  src_type;           /* type of source operand               */
        u8  dst_type;           /* type of destination operand          */
        u8  ad_bytes;           /* size of src/dst address              */
+       u64 invlpg_linear_addr; /* linear address, if INVLPG */
        u64 rip;                /* rip of the instruction               */
        u64 next_rip;           /* rip following the instruction        */
 };
-- 
2.43.7


Reply via email to