Add get_intercept_linear_addr() to compute the linear address for
intercepts that report one, and pass the result through
x86_instruction_info.

Handle INVLPG as the initial user.  INVLPG's memory operand is decoded
with NoAccess, and thus src_val does not contain the operand address.
Compute the address from the decoded segment base and effective address
in the emulator, where the operand state is available.

This allows intercept handlers to use the linear address directly
without duplicating the emulator's address calculation.

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

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8071b372d233..a0e57b64cadd 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -410,6 +410,26 @@ static int em_salc(struct x86_emulate_ctxt *ctxt)
        _fault ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE; \
 })
 
+static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
+{
+       if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
+               return 0;
+
+       return ctxt->ops->get_cached_segment_base(ctxt, seg);
+}
+
+static u64 get_intercept_linear_addr(struct x86_emulate_ctxt *ctxt,
+                                    enum x86_intercept intercept)
+{
+       u64 la;
+
+       if (intercept != x86_intercept_invlpg)
+               return 0;
+
+       la = seg_base(ctxt, ctxt->src.addr.mem.seg) + ctxt->src.addr.mem.ea;
+       return ctxt->mode == X86EMUL_MODE_PROT64 ? la : (u32)la;
+}
+
 static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
                                    enum x86_intercept intercept,
                                    enum x86_intercept_stage stage)
@@ -427,6 +447,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,
+               .intercept_linear_addr = get_intercept_linear_addr(ctxt, 
intercept),
                .rip        = ctxt->eip,
                .next_rip   = ctxt->_eip,
        };
@@ -520,14 +541,6 @@ static u32 desc_limit_scaled(struct desc_struct *desc)
        return desc->g ? (limit << 12) | 0xfff : limit;
 }
 
-static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
-{
-       if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
-               return 0;
-
-       return ctxt->ops->get_cached_segment_base(ctxt, seg);
-}
-
 static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
                             u32 error, bool valid)
 {
diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
index 3e375af15c03..9eda648a1314 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 intercept_linear_addr;      /* arch-reported linear address, if any 
*/
        u64 rip;                /* rip of the instruction               */
        u64 next_rip;           /* rip following the instruction        */
 };
-- 
2.43.7


Reply via email to