|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 1/3] x86/svm: Remove list functionality from __get_instruction_length_* infrastructure
On 12/31/18 5:37 AM, Andrew Cooper wrote:
> The existing __get_instruction_length_from_list() has a single user
> which uses the list functionality. That user however should be looking
> specifically for INVD or WBINVD, as reported by the vmexit exit reason.
>
> Modify svm_vmexit_do_invalidate_cache() to ask for the correct
> instruction, and drop all list functionality from the helper.
>
> Take the opportunity to rename it to svm_get_insn_len(), and drop the
> IOIO length handling whch has never been used.
>
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
Acked-by: Brian Woods <brian.woods@xxxxxxx>
> ---
> CC: Wei Liu <wei.liu2@xxxxxxxxxx>
> CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
> CC: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
> CC: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
> CC: Brian Woods <brian.woods@xxxxxxx>
>
> v2:
> * New
> v3:
> * Deduplicate the calls to svm_nextrip_insn_length()
> ---
> xen/arch/x86/hvm/svm/emulate.c | 76
> +++++++++++++++++------------------
> xen/arch/x86/hvm/svm/nestedsvm.c | 9 +++--
> xen/arch/x86/hvm/svm/svm.c | 39 +++++++++---------
> xen/include/asm-x86/hvm/svm/emulate.h | 9 +----
> 4 files changed, 61 insertions(+), 72 deletions(-)
>
> diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c
> index 4abeab8..7799908 100644
> --- a/xen/arch/x86/hvm/svm/emulate.c
> +++ b/xen/arch/x86/hvm/svm/emulate.c
> @@ -84,28 +84,31 @@ static const struct {
> [INSTR_CPUID] = { X86EMUL_OPC(0x0f, 0xa2) },
> };
>
> -int __get_instruction_length_from_list(struct vcpu *v,
> - const enum instruction_index *list, unsigned int list_count)
> +/*
> + * First-gen SVM didn't have the NextRIP feature, meaning that when we take a
> + * fault-style vmexit, we have to decode the instruction stream to calculate
> + * how many bytes to move %rip forwards by.
> + *
> + * To double check the implementation, in debug builds, always compare the
> + * hardware reported instruction length (if available) with the result from
> + * x86_decode_insn().
> + */
> +unsigned int svm_get_insn_len(struct vcpu *v, enum instruction_index insn)
> {
> struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
> struct hvm_emulate_ctxt ctxt;
> struct x86_emulate_state *state;
> - unsigned long inst_len, j;
> + unsigned long nrip_len, emul_len;
> unsigned int modrm_rm, modrm_reg;
> int modrm_mod;
>
> - /*
> - * In debug builds, always use x86_decode_insn() and compare with
> - * hardware.
> - */
> -#ifdef NDEBUG
> - if ( (inst_len = svm_nextrip_insn_length(v)) > MAX_INST_LEN )
> - gprintk(XENLOG_WARNING, "NRip reported inst_len %lu\n", inst_len);
> - else if ( inst_len != 0 )
> - return inst_len;
> + nrip_len = svm_nextrip_insn_length(v);
>
> - if ( vmcb->exitcode == VMEXIT_IOIO )
> - return vmcb->exitinfo2 - vmcb->rip;
> +#ifdef NDEBUG
> + if ( nrip_len > MAX_INST_LEN )
> + gprintk(XENLOG_WARNING, "NRip reported inst_len %lu\n", nrip_len);
> + else if ( nrip_len != 0 )
> + return nrip_len;
> #endif
>
> ASSERT(v == current);
> @@ -115,41 +118,34 @@ int __get_instruction_length_from_list(struct vcpu *v,
> if ( IS_ERR_OR_NULL(state) )
> return 0;
>
> - inst_len = x86_insn_length(state, &ctxt.ctxt);
> + emul_len = x86_insn_length(state, &ctxt.ctxt);
> modrm_mod = x86_insn_modrm(state, &modrm_rm, &modrm_reg);
> x86_emulate_free_state(state);
> +
> #ifndef NDEBUG
> - if ( vmcb->exitcode == VMEXIT_IOIO )
> - j = vmcb->exitinfo2 - vmcb->rip;
> - else
> - j = svm_nextrip_insn_length(v);
> - if ( j && j != inst_len )
> + if ( nrip_len && nrip_len != emul_len )
> {
> gprintk(XENLOG_WARNING, "insn-len[%02x]=%lu (exp %lu)\n",
> - ctxt.ctxt.opcode, inst_len, j);
> - return j;
> + ctxt.ctxt.opcode, nrip_len, emul_len);
> + return nrip_len;
> }
> #endif
>
> - for ( j = 0; j < list_count; j++ )
> + if ( insn >= ARRAY_SIZE(opc_tab) )
> {
> - unsigned int instr = list[j];
> -
> - if ( instr >= ARRAY_SIZE(opc_tab) )
> - {
> - ASSERT_UNREACHABLE();
> - break;
> - }
> - if ( opc_tab[instr].opcode == ctxt.ctxt.opcode )
> - {
> - if ( !opc_tab[instr].modrm.mod )
> - return inst_len;
> -
> - if ( modrm_mod == opc_tab[instr].modrm.mod &&
> - (modrm_rm & 7) == opc_tab[instr].modrm.rm &&
> - (modrm_reg & 7) == opc_tab[instr].modrm.reg )
> - return inst_len;
> - }
> + ASSERT_UNREACHABLE();
> + return 0;
> + }
> +
> + if ( opc_tab[insn].opcode == ctxt.ctxt.opcode )
> + {
> + if ( !opc_tab[insn].modrm.mod )
> + return emul_len;
> +
> + if ( modrm_mod == opc_tab[insn].modrm.mod &&
> + (modrm_rm & 7) == opc_tab[insn].modrm.rm &&
> + (modrm_reg & 7) == opc_tab[insn].modrm.reg )
> + return emul_len;
> }
>
> gdprintk(XENLOG_WARNING,
> diff --git a/xen/arch/x86/hvm/svm/nestedsvm.c
> b/xen/arch/x86/hvm/svm/nestedsvm.c
> index 9660202..35c1a04 100644
> --- a/xen/arch/x86/hvm/svm/nestedsvm.c
> +++ b/xen/arch/x86/hvm/svm/nestedsvm.c
> @@ -743,8 +743,9 @@ nsvm_vcpu_vmrun(struct vcpu *v, struct cpu_user_regs
> *regs)
> struct nestedvcpu *nv = &vcpu_nestedhvm(v);
> struct nestedsvm *svm = &vcpu_nestedsvm(v);
>
> - inst_len = __get_instruction_length(v, INSTR_VMRUN);
> - if (inst_len == 0) {
> + inst_len = svm_get_insn_len(v, INSTR_VMRUN);
> + if ( inst_len == 0 )
> + {
> svm->ns_vmexit.exitcode = VMEXIT_SHUTDOWN;
> return -1;
> }
> @@ -1616,7 +1617,7 @@ void svm_vmexit_do_stgi(struct cpu_user_regs *regs,
> struct vcpu *v)
> return;
> }
>
> - if ( (inst_len = __get_instruction_length(v, INSTR_STGI)) == 0 )
> + if ( (inst_len = svm_get_insn_len(v, INSTR_STGI)) == 0 )
> return;
>
> nestedsvm_vcpu_stgi(v);
> @@ -1637,7 +1638,7 @@ void svm_vmexit_do_clgi(struct cpu_user_regs *regs,
> struct vcpu *v)
> return;
> }
>
> - if ( (inst_len = __get_instruction_length(v, INSTR_CLGI)) == 0 )
> + if ( (inst_len = svm_get_insn_len(v, INSTR_CLGI)) == 0 )
> return;
>
> nestedsvm_vcpu_clgi(v);
> diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
> index 954822c..2584b90 100644
> --- a/xen/arch/x86/hvm/svm/svm.c
> +++ b/xen/arch/x86/hvm/svm/svm.c
> @@ -2244,8 +2244,8 @@ static void svm_do_msr_access(struct cpu_user_regs
> *regs)
> {
> struct vcpu *curr = current;
> bool rdmsr = curr->arch.hvm.svm.vmcb->exitinfo1 == 0;
> - int rc, inst_len = __get_instruction_length(
> - curr, rdmsr ? INSTR_RDMSR : INSTR_WRMSR);
> + int rc, inst_len = svm_get_insn_len(curr, rdmsr ? INSTR_RDMSR
> + : INSTR_WRMSR);
>
> if ( inst_len == 0 )
> return;
> @@ -2272,7 +2272,7 @@ static void svm_vmexit_do_hlt(struct vmcb_struct *vmcb,
> {
> unsigned int inst_len;
>
> - if ( (inst_len = __get_instruction_length(current, INSTR_HLT)) == 0 )
> + if ( (inst_len = svm_get_insn_len(current, INSTR_HLT)) == 0 )
> return;
> __update_guest_eip(regs, inst_len);
>
> @@ -2283,7 +2283,6 @@ static void svm_vmexit_do_rdtsc(struct cpu_user_regs
> *regs, bool rdtscp)
> {
> struct vcpu *curr = current;
> const struct domain *currd = curr->domain;
> - enum instruction_index insn = rdtscp ? INSTR_RDTSCP : INSTR_RDTSC;
> unsigned int inst_len;
>
> if ( rdtscp && !currd->arch.cpuid->extd.rdtscp )
> @@ -2292,7 +2291,8 @@ static void svm_vmexit_do_rdtsc(struct cpu_user_regs
> *regs, bool rdtscp)
> return;
> }
>
> - if ( (inst_len = __get_instruction_length(curr, insn)) == 0 )
> + if ( (inst_len = svm_get_insn_len(curr, rdtscp ? INSTR_RDTSCP
> + : INSTR_RDTSC)) == 0 )
> return;
>
> __update_guest_eip(regs, inst_len);
> @@ -2307,7 +2307,7 @@ static void svm_vmexit_do_pause(struct cpu_user_regs
> *regs)
> {
> unsigned int inst_len;
>
> - if ( (inst_len = __get_instruction_length(current, INSTR_PAUSE)) == 0 )
> + if ( (inst_len = svm_get_insn_len(current, INSTR_PAUSE)) == 0 )
> return;
> __update_guest_eip(regs, inst_len);
>
> @@ -2374,7 +2374,7 @@ svm_vmexit_do_vmload(struct vmcb_struct *vmcb,
> unsigned int inst_len;
> struct page_info *page;
>
> - if ( (inst_len = __get_instruction_length(v, INSTR_VMLOAD)) == 0 )
> + if ( (inst_len = svm_get_insn_len(v, INSTR_VMLOAD)) == 0 )
> return;
>
> if ( !nsvm_efer_svm_enabled(v) )
> @@ -2409,7 +2409,7 @@ svm_vmexit_do_vmsave(struct vmcb_struct *vmcb,
> unsigned int inst_len;
> struct page_info *page;
>
> - if ( (inst_len = __get_instruction_length(v, INSTR_VMSAVE)) == 0 )
> + if ( (inst_len = svm_get_insn_len(v, INSTR_VMSAVE)) == 0 )
> return;
>
> if ( !nsvm_efer_svm_enabled(v) )
> @@ -2477,13 +2477,12 @@ static void svm_wbinvd_intercept(void)
> flush_all(FLUSH_CACHE);
> }
>
> -static void svm_vmexit_do_invalidate_cache(struct cpu_user_regs *regs)
> +static void svm_vmexit_do_invalidate_cache(struct cpu_user_regs *regs,
> + bool invld)
> {
> - static const enum instruction_index list[] = { INSTR_INVD, INSTR_WBINVD
> };
> - int inst_len;
> + unsigned int inst_len = svm_get_insn_len(current, invld ? INSTR_INVD
> + : INSTR_WBINVD);
>
> - inst_len = __get_instruction_length_from_list(
> - current, list, ARRAY_SIZE(list));
> if ( inst_len == 0 )
> return;
>
> @@ -2758,7 +2757,7 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
> else
> {
> trap_type = X86_EVENTTYPE_PRI_SW_EXCEPTION;
> - inst_len = __get_instruction_length(v, INSTR_ICEBP);
> + inst_len = svm_get_insn_len(v, INSTR_ICEBP);
> }
>
> rc = hvm_monitor_debug(regs->rip,
> @@ -2775,7 +2774,7 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
> break;
>
> case VMEXIT_EXCEPTION_BP:
> - inst_len = __get_instruction_length(v, INSTR_INT3);
> + inst_len = svm_get_insn_len(v, INSTR_INT3);
>
> if ( inst_len == 0 )
> break;
> @@ -2866,7 +2865,7 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
>
> case VMEXIT_INVD:
> case VMEXIT_WBINVD:
> - svm_vmexit_do_invalidate_cache(regs);
> + svm_vmexit_do_invalidate_cache(regs, exit_reason == VMEXIT_INVD);
> break;
>
> case VMEXIT_TASK_SWITCH: {
> @@ -2895,7 +2894,7 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
>
> case VMEXIT_CPUID:
> {
> - unsigned int inst_len = __get_instruction_length(v, INSTR_CPUID);
> + unsigned int inst_len = svm_get_insn_len(v, INSTR_CPUID);
> int rc = 0;
>
> if ( inst_len == 0 )
> @@ -2951,14 +2950,14 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
> hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);
> break;
> }
> - if ( (inst_len = __get_instruction_length(v, INSTR_INVLPGA)) == 0 )
> + if ( (inst_len = svm_get_insn_len(v, INSTR_INVLPGA)) == 0 )
> break;
> svm_invlpga_intercept(v, regs->rax, regs->ecx);
> __update_guest_eip(regs, inst_len);
> break;
>
> case VMEXIT_VMMCALL:
> - if ( (inst_len = __get_instruction_length(v, INSTR_VMCALL)) == 0 )
> + if ( (inst_len = svm_get_insn_len(v, INSTR_VMCALL)) == 0 )
> break;
> BUG_ON(vcpu_guestmode);
> HVMTRACE_1D(VMMCALL, regs->eax);
> @@ -3012,7 +3011,7 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
> case VMEXIT_XSETBV:
> if ( vmcb_get_cpl(vmcb) )
> hvm_inject_hw_exception(TRAP_gp_fault, 0);
> - else if ( (inst_len = __get_instruction_length(v, INSTR_XSETBV)) &&
> + else if ( (inst_len = svm_get_insn_len(v, INSTR_XSETBV)) &&
> hvm_handle_xsetbv(regs->ecx, msr_fold(regs)) ==
> X86EMUL_OKAY )
> __update_guest_eip(regs, inst_len);
> break;
> diff --git a/xen/include/asm-x86/hvm/svm/emulate.h
> b/xen/include/asm-x86/hvm/svm/emulate.h
> index ca92abb..82359ec 100644
> --- a/xen/include/asm-x86/hvm/svm/emulate.h
> +++ b/xen/include/asm-x86/hvm/svm/emulate.h
> @@ -45,14 +45,7 @@ enum instruction_index {
>
> struct vcpu;
>
> -int __get_instruction_length_from_list(
> - struct vcpu *, const enum instruction_index *, unsigned int list_count);
> -
> -static inline int __get_instruction_length(
> - struct vcpu *v, enum instruction_index instr)
> -{
> - return __get_instruction_length_from_list(v, &instr, 1);
> -}
> +unsigned int svm_get_insn_len(struct vcpu *v, enum instruction_index instr);
>
> #endif /* __ASM_X86_HVM_SVM_EMULATE_H__ */
>
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |