2018-01-31 16:56+0300, Roman Kagan: > In Hyper-V, the fast guest->host notification mechanism is the > SIGNAL_EVENT hypercall, with a single parameter of the connection ID to > signal. > > Currently this hypercall incurs a user exit and requires the userspace > to decode the parameters and trigger the notification of the potentially > different I/O context. > > To avoid the costly user exit, process this hypercall and signal the > corresponding eventfd in KVM, similar to ioeventfd. The association > between the connection id and the eventfd is established via the newly > introduced KVM_HYPERV_EVENTFD ioctl, and maintained in an > (srcu-protected) IDR. > > Signed-off-by: Roman Kagan <rkagan@xxxxxxxxxxxxx> > Reviewed-by: David Hildenbrand <david@xxxxxxxxxx> > --- > v7 -> v8: > - rebase to latest master (adjust ioctl and doc section numbers) > > v6 -> v7: > - reject non-zero flag number as invalid > - adjust error returns to better match the spec > [these changes didn't look critical so I retained David's r-b] > > v5 -> v6: > - drop unnecessary srcu_read_lock/unlock, and clean up after that > > v4 -> v5: > - fix block comment formatting > > v3 -> v4: > - switch to kvm_vcpu_read_guest and take srcu_read_lock around it > - rework and document the interpretation of the hypercall parameter > - merge !fast version into kvm_hvcall_signal_event for brevity > > v2 -> v3: > - expand docs on allowed values and return codes > - fix uninitialized return > - style fixes > > v1 -> v2: > - make data types consistent > - get by without the recently dropped struct hv_input_signal_event > - fix subject prefix > > Documentation/virtual/kvm/api.txt | 31 +++++++++++ > arch/x86/include/asm/kvm_host.h | 2 + > arch/x86/include/uapi/asm/hyperv.h | 2 + > arch/x86/kvm/hyperv.h | 1 + > include/uapi/linux/kvm.h | 13 +++++ > arch/x86/kvm/hyperv.c | 103 ++++++++++++++++++++++++++++++++++++- > arch/x86/kvm/x86.c | 10 ++++ > 7 files changed, 161 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c > @@ -1226,6 +1227,43 @@ static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu) > return 1; > } > > +static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, bool fast, u64 param) > +{ > + struct eventfd_ctx *eventfd; > + > + if (unlikely(!fast)) { > + int ret; > + gpa_t gpa = param; > + > + if ((gpa & (__alignof__(param) - 1)) || > + offset_in_page(gpa) + sizeof(param) > PAGE_SIZE) > + return HV_STATUS_INVALID_ALIGNMENT; > + > + ret = kvm_vcpu_read_guest(vcpu, gpa, ¶m, sizeof(param)); > + if (ret < 0) > + return HV_STATUS_INVALID_ALIGNMENT; > + } I have completely missed this series in the past, sorry. It looks good, but I don't follow this: > + > + /* > + * Per spec, bits 32-47 contain the extra "flag number". However, we > + * have no use for it, and in all known usecases it is zero, so just > + * require it here. > + */ The spec says: FlagNumber specifies the relative index of the event flag that the caller wants to set within the target SIEF area. This number is relative to the base flag number associated with the port. And then: 11.5.1 Event Flag Delivery When a partition calls HvSignalEvent, it specifies an event flag number. The hypervisor responds by atomically setting a bit within the receiving virtual processor’s SIEF page. (See section 11.9 for a detailed description of the SIEF page.) Virtual processors whose SynIC or SIEF page is disabled will not be considered as potential targets. If no targets are available, the hypervisor terminates the operation and returns an error to the caller. If the event flag was previously cleared, the hypervisor attempts to notify the receiving partition that the flag is now set by generating an edge-triggered interrupt. The target virtual processor, along with the target SINTx, is specified as part of a port’s creation. (See the following for information about ports.) If the SINTx is masked, HvSignalEvent returns HV_STATUS_INVALID_SYNIC_STATE. As with any fixed-priority external interrupt, the interrupt is not acknowledged by the virtual processor until the process priority register (PPR) is less than the vector specified in the SINTx register and interrupts are not masked by the virtual processor (rFLAGS[IF] is set to 1). Don't we want to pass the flag into userspace? Thanks. > + if (param & 0xffff00000000) > + return HV_STATUS_INVALID_PARAMETER; > + /* remaining bits are reserved-zero */ > + if (param & ~KVM_HYPERV_CONN_ID_MASK) > + return HV_STATUS_INVALID_HYPERCALL_INPUT; > + > + /* conn_to_evt is protected by vcpu->kvm->srcu */ > + eventfd = idr_find(&vcpu->kvm->arch.hyperv.conn_to_evt, param); > + if (!eventfd) > + return HV_STATUS_INVALID_PORT_ID; > + > + eventfd_signal(eventfd, 1); > + return HV_STATUS_SUCCESS; > +} > +