KVM: x86: hyperv: do rep check for each hypercall separately
authorVitaly Kuznetsov <vkuznets@redhat.com>
Wed, 16 May 2018 15:21:27 +0000 (17:21 +0200)
committerRadim Krčmář <rkrcmar@redhat.com>
Sat, 26 May 2018 12:14:33 +0000 (14:14 +0200)
Prepare to support TLB flush hypercalls, some of which are REP hypercalls.
Also, return HV_STATUS_INVALID_HYPERCALL_INPUT as it seems more
appropriate.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
arch/x86/kvm/hyperv.c

index dcfeae2deafa5adf647e7406b6692ea3ab957724..edb1ac44d628598fe52b79c5fbd9cc078c137f63 100644 (file)
@@ -1311,7 +1311,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
 {
        u64 param, ingpa, outgpa, ret = HV_STATUS_SUCCESS;
        uint16_t code, rep_idx, rep_cnt;
-       bool fast, longmode;
+       bool fast, longmode, rep;
 
        /*
         * hypercall generates UD from non zero cpl and real mode
@@ -1344,28 +1344,31 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
        fast = !!(param & HV_HYPERCALL_FAST_BIT);
        rep_cnt = (param >> HV_HYPERCALL_REP_COMP_OFFSET) & 0xfff;
        rep_idx = (param >> HV_HYPERCALL_REP_START_OFFSET) & 0xfff;
+       rep = !!(rep_cnt || rep_idx);
 
        trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa);
 
-       /* Hypercall continuation is not supported yet */
-       if (rep_cnt || rep_idx) {
-               ret = HV_STATUS_INVALID_HYPERCALL_CODE;
-               goto set_result;
-       }
-
        switch (code) {
        case HVCALL_NOTIFY_LONG_SPIN_WAIT:
+               if (unlikely(rep)) {
+                       ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
+                       break;
+               }
                kvm_vcpu_on_spin(vcpu, true);
                break;
        case HVCALL_SIGNAL_EVENT:
+               if (unlikely(rep)) {
+                       ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
+                       break;
+               }
                ret = kvm_hvcall_signal_event(vcpu, fast, ingpa);
                if (ret != HV_STATUS_INVALID_PORT_ID)
                        break;
                /* maybe userspace knows this conn_id: fall through */
        case HVCALL_POST_MESSAGE:
                /* don't bother userspace if it has no way to handle it */
-               if (!vcpu_to_synic(vcpu)->active) {
-                       ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+               if (unlikely(rep || !vcpu_to_synic(vcpu)->active)) {
+                       ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
                vcpu->run->exit_reason = KVM_EXIT_HYPERV;