Add intercept_linear_addr to x86_instruction_info so that the emulator can pass linear addresses needed by intercept handlers.
Populate the field for INVLPG from its decoded memory operand. INVLPG is decoded with NoAccess, and therefore src_val does not contain the operand address. Calculate the address in the emulator, where the decoded segment and effective address are available. Signed-off-by: Tina Zhang <[email protected]> --- arch/x86/kvm/emulate.c | 30 ++++++++++++++++++++++-------- arch/x86/kvm/kvm_emulate.h | 1 + 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 8013dccb3110..03bf95417275 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -410,6 +410,27 @@ 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); +} + +/* Return the linear address for intercepts that report one. */ +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 +448,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 +542,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 0abff36d0994..900bd95e9e55 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -47,6 +47,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

