From patchwork Thu Dec 14 19:27:49 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Kagan X-Patchwork-Id: 10113205 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 40EFC603FA for ; Thu, 14 Dec 2017 19:28:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2B92929CE7 for ; Thu, 14 Dec 2017 19:28:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 206B629CE9; Thu, 14 Dec 2017 19:28:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4CDCE29CE8 for ; Thu, 14 Dec 2017 19:28:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754309AbdLNT2G (ORCPT ); Thu, 14 Dec 2017 14:28:06 -0500 Received: from mail-eopbgr10108.outbound.protection.outlook.com ([40.107.1.108]:51648 "EHLO EUR02-HE1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754161AbdLNT2E (ORCPT ); Thu, 14 Dec 2017 14:28:04 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=virtuozzo.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=801WZQ0Yzai6n1Bmiy3e+jxkmGOTvowI0cMz6SNfD/g=; b=SZuvMRMHD1V6zK9IWkd+22X5mHTY2Zt1KTI/p0zm5BD1oxLS1b0FaRXB0vCrqDzrKO5qbhzGyH93AY1Aa37rXX06dAcYLivjhALu5b52++xUShAcg7fdjTi671NoLRMpC6RWu4pO2B6L7KEXZopGLYoOCb6hx+TwiE2XVAUfd1E= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=rkagan@virtuozzo.com; Received: from rkaganb.sw.ru (195.214.232.6) by HE1PR08MB0841.eurprd08.prod.outlook.com (2a01:111:e400:59b2::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.302.9; Thu, 14 Dec 2017 19:28:00 +0000 From: Roman Kagan To: kvm@vger.kernel.org, Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Cc: "Denis V. Lunev" , Konrad Rzeszutek Wilk , Vitaly Kuznetsov , David Hildenbrand Subject: [PATCH v7 2/2] kvm: x86: hyperv: guest->host event signaling via eventfd Date: Thu, 14 Dec 2017 22:27:49 +0300 Message-Id: <20171214192749.25764-3-rkagan@virtuozzo.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20171214192749.25764-1-rkagan@virtuozzo.com> References: <20171214192749.25764-1-rkagan@virtuozzo.com> MIME-Version: 1.0 X-Originating-IP: [195.214.232.6] X-ClientProxiedBy: HE1PR05CA0196.eurprd05.prod.outlook.com (2603:10a6:3:f9::20) To HE1PR08MB0841.eurprd08.prod.outlook.com (2a01:111:e400:59b2::15) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: d5056772-c8f5-467e-7386-08d54328c9df X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(5600026)(4604075)(4534020)(4602075)(7168020)(4627115)(201703031133081)(201702281549075)(2017052603307); SRVR:HE1PR08MB0841; X-Microsoft-Exchange-Diagnostics: 1; HE1PR08MB0841; 3:t1s+H0OJ1j2KG7ibM6OKag7ZOr9nSCBDMoh5WDM+cyJR5fAxzbniGnwZ1m7E2tp1j355NZDo1cnYdDi5zzZWrlGAkDieK0Akv5uuqGQ/Mfaam3WNZoIWJmDIa0UQ7zB8/QB4m22Ys3ppBO6mlfNU7Y+gsDzO0ny5XJJJ5j0BQ449fVweh4bPy9Mp0IShPEp0vkgwpQL9Q9vyVG2EDJNhSuxrKeQ3whxcMBI8X3lhGGJZtuNbD6HfzEDaVeG+Cw9g; 25:5NINRdILOgQdqCCdrIaHIVeNzX46Y1+V2JXxmIEbpTuBgoOH8P4isEW20LiScodUudzGEnCcDoN+WVNohpMExpA1sPsdPcCm3CY1XUtC0f7bYl1l0LbeSQOgnz8OVMVfNY2y1xQB7pj+RVNE3zLz6spg9uu5FDmt+It5s3UBW4I/NAZM9xgIelmE+GQjVD6nBA8vD49JTd6bcveYWu8DNyljvWlH0EQed6gTLErBWflVfgY4raGmpEqVuWARWcdyC093h7AAqDFIhu4GlNzJ6DeuNlZCI6kzxZE6yLwVYzOaZl9OVysleizcxABo7WuaAwhxy9BkDxV5wC9djBa18Q==; 31:06VwPm7LrXv7iaEX+dhOUMAn5Fc256lliXaPjrqjhxEgXYEREjTMnWb68hyum0O2KDNsJT1VHhj2LAkDZd5saAJk8qnj8CgwUsnbByEKDfP4NwnM/Noid1aKFpIChYH210/jETr5RyKxlEGopi96RzFSfrRNHgmmmfouzqe4xPybVCJux9fJQBPVm/+KBruCV0lMTAwHWwz2vQwS4o+s36m8iXrYqHoHLej/55tXdh8= X-MS-TrafficTypeDiagnostic: HE1PR08MB0841: X-Microsoft-Exchange-Diagnostics: 1; HE1PR08MB0841; 20:RqQsvsv1kLL9daQiNfW717ANqF6EPWTEoyxInV54yBjPDrs4gP5rGvzwAJ6GkOpqk0xDtNfJmC44wCA/4ry98BIJ0l4G16CElQ0dSY4vGwsxONThLqAqu9WsiKBrQRhNWA8nDanAMf0tRyCqsMLTKYrc7GGigHLCl+ZGC5vkSPjULSj1Ggqfex0JwAStkT8FLjkZ9HMXNXZ5Qq+CFNq6NzXvLG6o4UvMNLTx+PMDqU/QrFtFrGxzTW7NLps+un57aaNsi0pxCyzPswCO3Z/3UQWDhoB9ynbDMxLof5jHcFw3JUM8CAe830daB3PgpDPvj0HdLjMntZTIdoUgxCrrToQaCaxIU4eLHnJoIawWQ2i17KfAIlVOZMc1gL08CvwGV7xaiHoo61lOp/njesNnibd+pyUL4UWzjfKstz1wHdA=; 4:xZkdroU89wa5SD79ebvxN+7sLFtXiaE7YAGgCtuh7GhmS9FtswqH2ZcdSD9FA1FCAeVzzXeYTqI1VbnNriRRK2LlFJ/NFiJU7y24snJhKDZlh5eqDMxrGWmdNTSvfm5PVpVTrGxLe96a7qmCXR89xxTGd5UlrVrYLWQ0yq7UFYa/7DdOFUl1JOtk8y9IWOG58bGkAPSovptz2g3ZbhqWXtmj824Y66a60l9znT8reV/RzSg2wqVfTJbqL/l4VIj7egwJvDzAnlyCgrDoEeWt/w== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040450)(2401047)(8121501046)(5005006)(3002001)(3231023)(93006095)(93001095)(10201501046)(6041248)(20161123560025)(20161123564025)(20161123555025)(20161123558100)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123562025)(6072148)(201708071742011); SRVR:HE1PR08MB0841; BCL:0; PCL:0; RULEID:(100000803101)(100110400095); SRVR:HE1PR08MB0841; X-Forefront-PRVS: 05214FD68E X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(346002)(39840400004)(366004)(396003)(376002)(189003)(199004)(478600001)(105586002)(2906002)(53416004)(3846002)(6116002)(106356001)(8676002)(81166006)(1076002)(76176011)(81156014)(8936002)(50226002)(51416003)(55236004)(69596002)(52116002)(6486002)(2950100002)(6666003)(36756003)(5660300001)(50466002)(53936002)(6512007)(4326008)(48376002)(25786009)(68736007)(47776003)(66066001)(54906003)(16526018)(16586007)(110136005)(316002)(59450400001)(305945005)(7736002)(97736004)(86362001)(6506007)(386003); DIR:OUT; SFP:1102; SCL:1; SRVR:HE1PR08MB0841; H:rkaganb.sw.ru; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; Received-SPF: None (protection.outlook.com: virtuozzo.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; HE1PR08MB0841; 23:OwzyKeG7y6A6H8qqLIrLAAs/TCDmcPrqW6guMPHp6?= =?us-ascii?Q?CRMTd5aZR3xGgyD7amJYA2cj84itJkXU51zPFOV3UBhfs4spICg366LG6D7U?= =?us-ascii?Q?8IogQUqPIY4h77y+9/ARj465GzAnkPzQh1l0EuXYROrbFNV54h0glt8BOOsL?= =?us-ascii?Q?87wjfEKV+94zbbGmVBqeiicxj8lmDjs+ZHII2pk3XeX+OPxYXHZc6Dib/wiV?= =?us-ascii?Q?qHt4UASgqP1fUXScYMgSdzdEo8oSNiopXRacxsD7jhsYhFa+eVOKLEWp/ntx?= =?us-ascii?Q?K5VLx1eedESxl/g4+3QeqYRDDCxqlVVsCIq5qjekWN3tQ09/jUTdtAq03Z94?= =?us-ascii?Q?amGEhW8Ir9vgO3Pj3L30fs2qFDAIMyvc9mWGSrGnZVFEQe8KzSaCXznFyBk1?= =?us-ascii?Q?32+QG2e5/tfH8eXTrtTOwQ1aDVhIJT1CseuU6oBg6XZwuS+2/wJqb4QFhFWk?= =?us-ascii?Q?zImowJsgWsnGfqFP51WcgGB296+3kCxMc6zhuhqnAFjoFPoIXi8Hjy7eJKhk?= =?us-ascii?Q?kHEz/ssPFQQGH8bGeKJhyUWd+kTw/uJehy7z0P/dINbYnKTysRg19UFvxHUb?= =?us-ascii?Q?uQAp0FvGEImB/hN1d0q1HkYnAur9k0c53g5dkvMjKLIAag4z4jkeHdHkXgPW?= =?us-ascii?Q?sJ70difm91a1nnnamm+z+rLMwIXBDY0+4eJcwC+aeWM1iWCSkPNOPpk8cEth?= =?us-ascii?Q?Ue7+Fum3nzj6KG9raTdjP4cavmnVYt23zEArAVC5Zkm8n51mO+QIk2fSPoLz?= =?us-ascii?Q?JQLhX27oyq7sLvQwAb2c6nr+KsG+JTQ0uDOVD/7bHL23jBcd+ZLSRHo+0cPo?= =?us-ascii?Q?YxmAKXHJVSBHk3PbERpOyVUc/Ij72fwzpYQcFdMQ4ZjNLK7wpj4RxSAdrzTn?= =?us-ascii?Q?G82+0es+7COselLmjwZ7nvLIFi9cFq1xno//Crg/aTnM8vUw0RVIR/lue8kr?= =?us-ascii?Q?4nL/ylLrCGis3VRpF5BeApDkis73uiGvLbJPpUQyzwdBm/j8mB/zQrh9GVr3?= =?us-ascii?Q?UNZ7rRTiVdKIsjyHNHqiobO3yo9E6X7ke0L8CzSI9jIW5Xiutm9uY0SJLCwP?= =?us-ascii?Q?hqRXxpvjgaecWoyYiV30BlqUnUHyWmAY6gdqUuqSNW3ExhmwFFL5jB/Q9vUO?= =?us-ascii?Q?759iT3EWyDTzOFfgGHaM9HOUeJDftkOuDWSiprDUbvFdQoBimpiT5dtIG0Mq?= =?us-ascii?Q?ZBATC+0eoCVOhY=3D?= X-Microsoft-Exchange-Diagnostics: 1; HE1PR08MB0841; 6:143MbbnpGd38rinojG0YXJb7uROT2q93gGJOqHYbYjXO1luxURFwoAIEuUIOxu6dn/w4lyUWzimwzvEqKs/b7Itr+awhYANLwI+Zp5W5fecDxdkRu+6nOET25h9jYKjc7yS7+XTeeNfBJO6z3DPcYvZAXE/NHnIsW8nTwxn4pvdPW4/I7hdHdQtTGaLKQEDFFmXAU/Kgn+0eQMEseZwqQM6cy1cHr8YEf1MCkyqFb29uQ3WyARNGqthFDEbNLSkWIuBsfH4tYlZl0QvljbFIUBscatux/gkpojMHq/CPCVWS8tsn0pBcbwws5uL35DomSsvRye1hoDUT64RnqcPiPfKL7nG/hSh/j1dkfJgKZZo=; 5:koECWbVBqUAf1t5NtEku0xhWi+G9NIUCd5wuWWUZM94gRIAtYxSJ69WEQ5ytExSZeEVJQcBD6SIqhXUqNHY1g8uKyTmUPC0ogidd9Vdql1dJLGhgnAVDIFd736Aa3Ktd++yqQ35ldq3SceDO0+6Wgt+Wd2EnYmjVt4DjEeX+WBE=; 24:BC4ahpb26sUTO/aL1j42TGgaUwbqbRbvnvz0O5igXDLnbDdfxu+7gYJ3+vnRG8dWFoWri2AQ4wKuDSwIshQxAjwjXCtBHC581aos7/rLjfA=; 7:T9xSxseKs1hrMmX1qtBEuEMTmDBTH9fXMLvDI+WaItS5ZFCkYqTH1Y9UX4JLUQfdWdVvZOc/wArWTgyY5pc2UlvnN54DRI4rRK04pkSi6Me9LnCjWGabKLsuLG6EhJJRzP2W8mJO7ccTYPYV9k/jA+EKbgN6NQYOQPNV8bGicJnCtYFLfclvdfh2UOZQNVoLrJ9ETSFUwBDtT9c9v1Wx/0dth4l5B974MTMWVjUS3aob/mLsRcqFpkXHHijE/OUj SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; HE1PR08MB0841; 20:L5hSpcr9p4ab3Ei+2CAaXw298uDHaBloqSx1DFAfnuPcelz51BogQzHMOSW39ZODuvDefXu7DdOKGYPk6ynEcOUQFoZDqvGCUJbICg0OIdN+d7xB1y/uJ89Seat3d5apkSHu4hGEEubLqxrNM6i0GiEb5amOf7GfIws0oiVH2Ds= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Dec 2017 19:28:00.4910 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d5056772-c8f5-467e-7386-08d54328c9df X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 0bc7f26d-0264-416e-a6fc-8352af79c58f X-MS-Exchange-Transport-CrossTenantHeadersStamped: HE1PR08MB0841 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Reviewed-by: David Hildenbrand --- 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/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 57d3ee9e4bde..3a959373fd97 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3403,6 +3403,37 @@ invalid, if invalid pages are written to (e.g. after the end of memory) or if no page table is present for the addresses (e.g. when using hugepages). +4.109 KVM_HYPERV_EVENTFD + +Capability: KVM_CAP_HYPERV_EVENTFD +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_hyperv_eventfd (in) + +This ioctl (un)registers an eventfd to receive notifications from the guest on +the specified Hyper-V connection id through the SIGNAL_EVENT hypercall, without +causing a user exit. + +struct kvm_hyperv_eventfd { + __u32 conn_id; + __s32 fd; + __u32 flags; + __u32 padding[3]; +}; + +The conn_id field should fit within 24 bits: + +#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff + +The acceptable values for the flags field are: + +#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0) + +Returns: 0 on success, + -EINVAL if conn_id or flags is outside the allowed range + -ENOENT on deassign if the conn_id isn't registered + -EEXIST on assign if the conn_id is already registered + 5. The kvm_run structure ------------------------ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 516798431328..6a9914752a84 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -752,6 +752,8 @@ struct kvm_hv { u64 hv_crash_ctl; HV_REFERENCE_TSC_PAGE tsc_ref; + + struct idr conn_to_evt; }; enum kvm_irqchip_mode { diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 1a5bfead93b4..f9ed479d479c 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -276,7 +276,9 @@ enum HV_GENERIC_SET_FORMAT { #define HV_STATUS_INVALID_HYPERCALL_CODE 2 #define HV_STATUS_INVALID_HYPERCALL_INPUT 3 #define HV_STATUS_INVALID_ALIGNMENT 4 +#define HV_STATUS_INVALID_PARAMETER 5 #define HV_STATUS_INSUFFICIENT_MEMORY 11 +#define HV_STATUS_INVALID_PORT_ID 17 #define HV_STATUS_INVALID_CONNECTION_ID 18 #define HV_STATUS_INSUFFICIENT_BUFFERS 19 diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index cc2468244ca2..837465d69c6d 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -90,5 +90,6 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm, void kvm_hv_init_vm(struct kvm *kvm); void kvm_hv_destroy_vm(struct kvm *kvm); +int kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args); #endif diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 496e59a2738b..7a871e7fb5df 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -932,6 +932,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_HYPERV_SYNIC2 148 #define KVM_CAP_HYPERV_VP_INDEX 149 #define KVM_CAP_S390_AIS_MIGRATION 150 +#define KVM_CAP_HYPERV_EVENTFD 151 #ifdef KVM_CAP_IRQ_ROUTING @@ -1359,6 +1360,8 @@ struct kvm_s390_ucas_mapping { #define KVM_S390_GET_CMMA_BITS _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log) #define KVM_S390_SET_CMMA_BITS _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log) +#define KVM_HYPERV_EVENTFD _IOW(KVMIO, 0xba, struct kvm_hyperv_eventfd) + #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) @@ -1419,4 +1422,14 @@ struct kvm_assigned_msix_entry { #define KVM_ARM_DEV_EL1_PTIMER (1 << 1) #define KVM_ARM_DEV_PMU (1 << 2) +struct kvm_hyperv_eventfd { + __u32 conn_id; + __s32 fd; + __u32 flags; + __u32 padding[3]; +}; + +#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff +#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0) + #endif /* __LINUX_KVM_H */ diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 015fb06c7522..7c283c404238 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -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; + } + + /* + * 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. + */ + 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; +} + int kvm_hv_hypercall(struct kvm_vcpu *vcpu) { u64 param, ingpa, outgpa, ret; @@ -1276,8 +1314,12 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) case HVCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu, true); break; - case HVCALL_POST_MESSAGE: case HVCALL_SIGNAL_EVENT: + res = kvm_hvcall_signal_event(vcpu, fast, ingpa); + if (res != 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) { res = HV_STATUS_INVALID_HYPERCALL_CODE; @@ -1305,8 +1347,67 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) void kvm_hv_init_vm(struct kvm *kvm) { mutex_init(&kvm->arch.hyperv.hv_lock); + idr_init(&kvm->arch.hyperv.conn_to_evt); } void kvm_hv_destroy_vm(struct kvm *kvm) { + struct eventfd_ctx *eventfd; + int i; + + idr_for_each_entry(&kvm->arch.hyperv.conn_to_evt, eventfd, i) + eventfd_ctx_put(eventfd); + idr_destroy(&kvm->arch.hyperv.conn_to_evt); +} + +static int kvm_hv_eventfd_assign(struct kvm *kvm, u32 conn_id, int fd) +{ + struct kvm_hv *hv = &kvm->arch.hyperv; + struct eventfd_ctx *eventfd; + int ret; + + eventfd = eventfd_ctx_fdget(fd); + if (IS_ERR(eventfd)) + return PTR_ERR(eventfd); + + mutex_lock(&hv->hv_lock); + ret = idr_alloc(&hv->conn_to_evt, eventfd, conn_id, conn_id + 1, + GFP_KERNEL); + mutex_unlock(&hv->hv_lock); + + if (ret >= 0) + return 0; + + if (ret == -ENOSPC) + ret = -EEXIST; + eventfd_ctx_put(eventfd); + return ret; +} + +static int kvm_hv_eventfd_deassign(struct kvm *kvm, u32 conn_id) +{ + struct kvm_hv *hv = &kvm->arch.hyperv; + struct eventfd_ctx *eventfd; + + mutex_lock(&hv->hv_lock); + eventfd = idr_remove(&hv->conn_to_evt, conn_id); + mutex_unlock(&hv->hv_lock); + + if (!eventfd) + return -ENOENT; + + synchronize_srcu(&kvm->srcu); + eventfd_ctx_put(eventfd); + return 0; +} + +int kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args) +{ + if ((args->flags & ~KVM_HYPERV_EVENTFD_DEASSIGN) || + (args->conn_id & ~KVM_HYPERV_CONN_ID_MASK)) + return -EINVAL; + + if (args->flags == KVM_HYPERV_EVENTFD_DEASSIGN) + return kvm_hv_eventfd_deassign(kvm, args->conn_id); + return kvm_hv_eventfd_assign(kvm, args->conn_id, args->fd); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d17cf7900138..1c43d262da14 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2701,6 +2701,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_HYPERV_SYNIC: case KVM_CAP_HYPERV_SYNIC2: case KVM_CAP_HYPERV_VP_INDEX: + case KVM_CAP_HYPERV_EVENTFD: case KVM_CAP_PCI_SEGMENT: case KVM_CAP_DEBUGREGS: case KVM_CAP_X86_ROBUST_SINGLESTEP: @@ -4295,6 +4296,15 @@ long kvm_arch_vm_ioctl(struct file *filp, r = kvm_vm_ioctl_enable_cap(kvm, &cap); break; } + case KVM_HYPERV_EVENTFD: { + struct kvm_hyperv_eventfd hvevfd; + + r = -EFAULT; + if (copy_from_user(&hvevfd, argp, sizeof(hvevfd))) + goto out; + r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd); + break; + } default: r = -ENOTTY; }