Sean Christopherson <seanjc@xxxxxxxxxx> writes: > Get the number of sparse banks from the VARHEAD field, which the guest is > required to provide as "The size of a variable header, in QWORDS.", where > the variable header is: > > Variable Header Bytes = {Total Header Bytes - sizeof(Fixed Header)} > rounded up to nearest multiple of 8 > Variable HeaderSize = Variable Header Bytes / 8 > > In other words, the VARHEAD should match the number of sparse banks. > Keep the manual count as a sanity check, but otherwise rely on the field > so as to more closely align with the logic defined in the TLFS and to > allow for future cleanups. > > Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> > --- > arch/x86/kvm/hyperv.c | 35 ++++++++++++++++++------------- > arch/x86/kvm/trace.h | 14 +++++++------ > include/asm-generic/hyperv-tlfs.h | 1 + > 3 files changed, 30 insertions(+), 20 deletions(-) > > diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c > index 814d1a1f2cb8..cf18aa1712bf 100644 > --- a/arch/x86/kvm/hyperv.c > +++ b/arch/x86/kvm/hyperv.c > @@ -1742,6 +1742,7 @@ struct kvm_hv_hcall { > u64 ingpa; > u64 outgpa; > u16 code; > + u16 var_cnt; > u16 rep_cnt; > u16 rep_idx; > bool fast; > @@ -1761,7 +1762,6 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool > unsigned long *vcpu_mask; > u64 valid_bank_mask; > u64 sparse_banks[64]; > - int sparse_banks_len; > bool all_cpus; > > if (!ex) { > @@ -1811,24 +1811,28 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool > all_cpus = flush_ex.hv_vp_set.format != > HV_GENERIC_SET_SPARSE_4K; > > - sparse_banks_len = bitmap_weight((unsigned long *)&valid_bank_mask, 64); > + if (hc->var_cnt != bitmap_weight((unsigned long *)&valid_bank_mask, 64)) > + return HV_STATUS_INVALID_HYPERCALL_INPUT; Let's hope Windows doesn't break this ruls when vp_set.format != HV_GENERIC_SET_SPARSE_4K > > - if (!sparse_banks_len && !all_cpus) > + if (!hc->var_cnt && !all_cpus) > goto ret_success; > > if (!all_cpus) { > if (hc->fast) { > - if (sparse_banks_len > HV_HYPERCALL_MAX_XMM_REGISTERS - 1) > + if (hc->var_cnt > HV_HYPERCALL_MAX_XMM_REGISTERS - 1) > return HV_STATUS_INVALID_HYPERCALL_INPUT; > - for (i = 0; i < sparse_banks_len; i += 2) { > + for (i = 0; i < hc->var_cnt; i += 2) { > sparse_banks[i] = sse128_lo(hc->xmm[i / 2 + 1]); > sparse_banks[i + 1] = sse128_hi(hc->xmm[i / 2 + 1]); > } > } else { > + if (hc->var_cnt > 64) > + return HV_STATUS_INVALID_HYPERCALL_INPUT; > + > gpa = hc->ingpa + offsetof(struct hv_tlb_flush_ex, > hv_vp_set.bank_contents); > if (unlikely(kvm_read_guest(kvm, gpa, sparse_banks, > - sparse_banks_len * > + hc->var_cnt * > sizeof(sparse_banks[0])))) > return HV_STATUS_INVALID_HYPERCALL_INPUT; > } > @@ -1884,7 +1888,6 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool > unsigned long *vcpu_mask; > unsigned long valid_bank_mask; > u64 sparse_banks[64]; > - int sparse_banks_len; > u32 vector; > bool all_cpus; > > @@ -1917,22 +1920,25 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool > > vector = send_ipi_ex.vector; > valid_bank_mask = send_ipi_ex.vp_set.valid_bank_mask; > - sparse_banks_len = bitmap_weight(&valid_bank_mask, 64) * > - sizeof(sparse_banks[0]); > - > all_cpus = send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL; > > + if (hc->var_cnt != bitmap_weight(&valid_bank_mask, 64)) > + return HV_STATUS_INVALID_HYPERCALL_INPUT; > + > if (all_cpus) > goto check_and_send_ipi; > > - if (!sparse_banks_len) > + if (!hc->var_cnt) > goto ret_success; > > + if (hc->var_cnt > 64) > + return HV_STATUS_INVALID_HYPERCALL_INPUT; > + > if (kvm_read_guest(kvm, > hc->ingpa + offsetof(struct hv_send_ipi_ex, > vp_set.bank_contents), > sparse_banks, > - sparse_banks_len)) > + hc->var_cnt * sizeof(sparse_banks[0]))) > return HV_STATUS_INVALID_HYPERCALL_INPUT; > } > > @@ -2190,13 +2196,14 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) > } > > hc.code = hc.param & 0xffff; > + hc.var_cnt = (hc.param & HV_HYPERCALL_VARHEAD_MASK) >> HV_HYPERCALL_VARHEAD_OFFSET; > hc.fast = !!(hc.param & HV_HYPERCALL_FAST_BIT); > hc.rep_cnt = (hc.param >> HV_HYPERCALL_REP_COMP_OFFSET) & 0xfff; > hc.rep_idx = (hc.param >> HV_HYPERCALL_REP_START_OFFSET) & 0xfff; > hc.rep = !!(hc.rep_cnt || hc.rep_idx); > > - trace_kvm_hv_hypercall(hc.code, hc.fast, hc.rep_cnt, hc.rep_idx, > - hc.ingpa, hc.outgpa); > + trace_kvm_hv_hypercall(hc.code, hc.fast, hc.var_cnt, hc.rep_cnt, > + hc.rep_idx, hc.ingpa, hc.outgpa); > > if (unlikely(!hv_check_hypercall_access(hv_vcpu, hc.code))) { > ret = HV_STATUS_ACCESS_DENIED; > diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h > index 953b0fcb21ee..f6625cfb686c 100644 > --- a/arch/x86/kvm/trace.h > +++ b/arch/x86/kvm/trace.h > @@ -64,9 +64,9 @@ TRACE_EVENT(kvm_hypercall, > * Tracepoint for hypercall. > */ > TRACE_EVENT(kvm_hv_hypercall, > - TP_PROTO(__u16 code, bool fast, __u16 rep_cnt, __u16 rep_idx, > - __u64 ingpa, __u64 outgpa), > - TP_ARGS(code, fast, rep_cnt, rep_idx, ingpa, outgpa), > + TP_PROTO(__u16 code, bool fast, __u16 var_cnt, __u16 rep_cnt, > + __u16 rep_idx, __u64 ingpa, __u64 outgpa), > + TP_ARGS(code, fast, var_cnt, rep_cnt, rep_idx, ingpa, outgpa), > > TP_STRUCT__entry( > __field( __u16, rep_cnt ) > @@ -74,6 +74,7 @@ TRACE_EVENT(kvm_hv_hypercall, > __field( __u64, ingpa ) > __field( __u64, outgpa ) > __field( __u16, code ) > + __field( __u16, var_cnt ) > __field( bool, fast ) > ), > > @@ -83,13 +84,14 @@ TRACE_EVENT(kvm_hv_hypercall, > __entry->ingpa = ingpa; > __entry->outgpa = outgpa; > __entry->code = code; > + __entry->var_cnt = var_cnt; > __entry->fast = fast; > ), > > - TP_printk("code 0x%x %s cnt 0x%x idx 0x%x in 0x%llx out 0x%llx", > + TP_printk("code 0x%x %s var_cnt 0x%x cnt 0x%x idx 0x%x in 0x%llx out 0x%llx", Nit: 'cnt' is (and was) a bit ambiguous, I'd suggest to explicitly say 'rep_cnt' (and probably 'rep_idx') instead. > __entry->code, __entry->fast ? "fast" : "slow", > - __entry->rep_cnt, __entry->rep_idx, __entry->ingpa, > - __entry->outgpa) > + __entry->var_cnt, __entry->rep_cnt, __entry->rep_idx, > + __entry->ingpa, __entry->outgpa) > ); > > TRACE_EVENT(kvm_hv_hypercall_done, > diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h > index 56348a541c50..1ba8e6da4427 100644 > --- a/include/asm-generic/hyperv-tlfs.h > +++ b/include/asm-generic/hyperv-tlfs.h > @@ -182,6 +182,7 @@ enum HV_GENERIC_SET_FORMAT { > #define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0) > #define HV_HYPERCALL_FAST_BIT BIT(16) > #define HV_HYPERCALL_VARHEAD_OFFSET 17 > +#define HV_HYPERCALL_VARHEAD_MASK GENMASK_ULL(26, 17) > #define HV_HYPERCALL_REP_COMP_OFFSET 32 > #define HV_HYPERCALL_REP_COMP_1 BIT_ULL(32) > #define HV_HYPERCALL_REP_COMP_MASK GENMASK_ULL(43, 32) Reviewed-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> -- Vitaly