From patchwork Wed Apr 27 15:34:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 12829004 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C6696C433FE for ; Wed, 27 Apr 2022 15:51:47 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.315212.533651 (Exim 4.92) (envelope-from ) id 1njjwz-0008QU-Pz; Wed, 27 Apr 2022 15:51:33 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 315212.533651; Wed, 27 Apr 2022 15:51:33 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1njjwz-0008QN-Mk; Wed, 27 Apr 2022 15:51:33 +0000 Received: by outflank-mailman (input) for mailman id 315212; Wed, 27 Apr 2022 15:51:32 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1njjwy-0007rz-8f for xen-devel@lists.xenproject.org; Wed, 27 Apr 2022 15:51:32 +0000 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id e6585bbd-c641-11ec-a405-831a346695d4; Wed, 27 Apr 2022 17:51:30 +0200 (CEST) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Apr 2022 08:34:30 -0700 Received: from esimonso-mobl1.amr.corp.intel.com (HELO ubuntu.localdomain) ([10.212.23.42]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Apr 2022 08:34:28 -0700 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: e6585bbd-c641-11ec-a405-831a346695d4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1651074690; x=1682610690; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=yu2lLCKrz9AND+oxXtfzZGp0tENLJ9h0P9FY5DkWhk4=; b=UOReKctzzFZ6jQLsHR1wFShRZnKkonFOha6THqaX2ZJK80Oogcfxt0Kv aA52qehMmpuPi1R5XgMyX7Exghra/G+b1tt5mulix4tkowPXbNEHPYLMZ utZNRmQNpslMiuaqF2m2DLe29H7hFRfmTTdiClbO2o9lqRO67hpPB4RBg Ho3ksn8WUFGxp9RLmtULeQw/9LFMAD8rZXTRqqJJrjyDr1ztWn6Car0FX JPnnoJaTvqnUywC9IxedbOQXhOmEPa1m4xmb/uRcxprTTvwvdCFYvVr36 bsdoADOTcNrm7s78ykcygwVWXxgyZXhy1R30ZIWyKkeP+14+dvL9d15ib g==; X-IronPort-AV: E=McAfee;i="6400,9594,10330"; a="328915505" X-IronPort-AV: E=Sophos;i="5.90,293,1643702400"; d="scan'208";a="328915505" X-IronPort-AV: E=Sophos;i="5.90,293,1643702400"; d="scan'208";a="680854404" From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Cc: Tamas K Lengyel , Jan Beulich , Andrew Cooper , =?utf-8?q?Roger_Pau_Monn=C3=A9?= , Wei Liu , George Dunlap , Julien Grall , Stefano Stabellini , Tamas K Lengyel , Alexandru Isaila , Petre Pircalabu Subject: [PATCH 1/3] x86/mem_sharing: make fork_reset more configurable Date: Wed, 27 Apr 2022 11:34:18 -0400 Message-Id: <7f03387eebf9de474f404ef661f80133e3725365.1651073086.git.tamas.lengyel@intel.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Alow specify distinct parts of the fork VM to be reset. This is useful when a fuzzing operation involves mapping in only a handful of pages that are known ahead of time. Throwing these pages away just to be re-copied immediately is expensive, thus allowing to specify partial resets can speed things up. Also allow resetting to be initiated from vm_event responses as an optiomization. Signed-off-by: Tamas K Lengyel Reviewed-by: Roger Pau Monné ring full @@ -148,6 +151,12 @@ static inline int mem_sharing_fork_page(struct domain *d, gfn_t gfn, bool lock) return -EOPNOTSUPP; } +static inline int mem_sharing_fork_reset(struct domain *d, bool reset_state, + bool reset_memory) +{ + return -EOPNOTSUPP; +} + #endif #endif /* __MEM_SHARING_H__ */ diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index a5c16b4429..1e1fb27c1a 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -1881,15 +1881,21 @@ static int fork(struct domain *cd, struct domain *d) * footprints the hypercall continuation should be implemented (or if this * feature needs to be become "stable"). */ -static int mem_sharing_fork_reset(struct domain *d) +int mem_sharing_fork_reset(struct domain *d, bool reset_state, + bool reset_memory) { - int rc; + int rc = 0; struct domain *pd = d->parent; struct p2m_domain *p2m = p2m_get_hostp2m(d); struct page_info *page, *tmp; + ASSERT(reset_state || reset_memory); + domain_pause(d); + if ( !reset_memory ) + goto state; + /* need recursive lock because we will free pages */ spin_lock_recursive(&d->page_alloc_lock); page_list_for_each_safe(page, tmp, &d->page_list) @@ -1922,7 +1928,9 @@ static int mem_sharing_fork_reset(struct domain *d) } spin_unlock_recursive(&d->page_alloc_lock); - rc = copy_settings(d, pd); + state: + if ( reset_state ) + rc = copy_settings(d, pd); domain_unpause(d); @@ -2229,15 +2237,21 @@ int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) case XENMEM_sharing_op_fork_reset: { + bool reset_state = mso.u.fork.flags & XENMEM_FORK_RESET_STATE; + bool reset_memory = mso.u.fork.flags & XENMEM_FORK_RESET_MEMORY; + rc = -EINVAL; - if ( mso.u.fork.pad || mso.u.fork.flags ) + if ( mso.u.fork.pad || (!reset_state && !reset_memory) ) + goto out; + if ( mso.u.fork.flags & + ~(XENMEM_FORK_RESET_STATE | XENMEM_FORK_RESET_MEMORY) ) goto out; rc = -ENOSYS; if ( !d->parent ) goto out; - rc = mem_sharing_fork_reset(d); + rc = mem_sharing_fork_reset(d, reset_state, reset_memory); break; } diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c index 84cf52636b..cc7d8bf565 100644 --- a/xen/common/vm_event.c +++ b/xen/common/vm_event.c @@ -28,6 +28,11 @@ #include #include #include + +#ifdef CONFIG_MEM_SHARING +#include +#endif + #include #include @@ -394,6 +399,19 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved) if ( rsp.reason == VM_EVENT_REASON_MEM_PAGING ) p2m_mem_paging_resume(d, &rsp); #endif +#ifdef CONFIG_MEM_SHARING + if ( mem_sharing_is_fork(d) ) + { + bool reset_state = rsp.flags & VM_EVENT_FLAG_RESET_FORK_STATE; + bool reset_mem = rsp.flags & VM_EVENT_FLAG_RESET_FORK_MEMORY; + + if ( (reset_state || reset_mem) && + mem_sharing_fork_reset(d, reset_state, reset_mem) ) + { + ASSERT_UNREACHABLE(); + } + } +#endif /* * Check emulation flags in the arch-specific handler only, as it diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index a1a0f0233a..f8d26fb77d 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -541,12 +541,14 @@ struct xen_mem_sharing_op { uint32_t gref; /* IN: gref to debug */ } u; } debug; - struct mem_sharing_op_fork { /* OP_FORK */ + struct mem_sharing_op_fork { /* OP_FORK{,_RESET} */ domid_t parent_domain; /* IN: parent's domain id */ /* Only makes sense for short-lived forks */ #define XENMEM_FORK_WITH_IOMMU_ALLOWED (1u << 0) /* Only makes sense for short-lived forks */ #define XENMEM_FORK_BLOCK_INTERRUPTS (1u << 1) +#define XENMEM_FORK_RESET_STATE (1u << 2) +#define XENMEM_FORK_RESET_MEMORY (1u << 3) uint16_t flags; /* IN: optional settings */ uint32_t pad; /* Must be set to 0 */ } fork; diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h index bb003d21d0..1673bb8703 100644 --- a/xen/include/public/vm_event.h +++ b/xen/include/public/vm_event.h @@ -127,6 +127,14 @@ * Reset the vmtrace buffer (if vmtrace is enabled) */ #define VM_EVENT_FLAG_RESET_VMTRACE (1 << 13) +/* + * Reset the VM state (if VM is fork) + */ +#define VM_EVENT_FLAG_RESET_FORK_STATE (1 << 14) +/* + * Remove unshared entries from physmap (if VM is fork) + */ +#define VM_EVENT_FLAG_RESET_FORK_MEMORY (1 << 15) /* * Reasons for the vm event request From patchwork Wed Apr 27 15:34:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 12829003 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 04FD0C433F5 for ; Wed, 27 Apr 2022 15:51:47 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.315213.533662 (Exim 4.92) (envelope-from ) id 1njjx1-0000FV-1b; Wed, 27 Apr 2022 15:51:35 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 315213.533662; Wed, 27 Apr 2022 15:51:35 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1njjx0-0000FO-U1; Wed, 27 Apr 2022 15:51:34 +0000 Received: by outflank-mailman (input) for mailman id 315213; Wed, 27 Apr 2022 15:51:33 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1njjwz-0007rz-Qm for xen-devel@lists.xenproject.org; Wed, 27 Apr 2022 15:51:33 +0000 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id e8ecea52-c641-11ec-a405-831a346695d4; Wed, 27 Apr 2022 17:51:32 +0200 (CEST) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Apr 2022 08:34:32 -0700 Received: from esimonso-mobl1.amr.corp.intel.com (HELO ubuntu.localdomain) ([10.212.23.42]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Apr 2022 08:34:31 -0700 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: e8ecea52-c641-11ec-a405-831a346695d4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1651074692; x=1682610692; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kbCPed86nvsBlhVS5WHzEURJPx5XQ+Bz2HXpoqkbpVg=; b=C8OpWO/D0yLDZ4ZQ+DAxRmYicSgCBvDwkA5P/ymKmuFbGa521DIIWBvB vnd85jFQPYrcfPur1X0S9/oznk8nkKH3W6njuIpJRcT8Om0N31CPRT6gl 04eDJSaVj07FLzbzLCh0FptsIBxuf/HaaVf6jKogcJ8hkslbp/onhrr7k LH1hvEg/1RY7amH0vFPKzUuY1Rjtbt++G9gsuZWqxBkM+4HeS6j0JEdlR HSiRH8XU0VzsHD3HH02pK5wajziWhprv3qAxnKIjAWRyvXmcKPb6xGPT9 X84BQEJtZygP4ACFfaZly0RSyozmVQc8imXg/dwRLFQo6r8XYhB08g+Ho g==; X-IronPort-AV: E=McAfee;i="6400,9594,10330"; a="328915526" X-IronPort-AV: E=Sophos;i="5.90,293,1643702400"; d="scan'208";a="328915526" X-IronPort-AV: E=Sophos;i="5.90,293,1643702400"; d="scan'208";a="680854487" From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Cc: Tamas K Lengyel , Wei Liu , Anthony PERARD , Juergen Gross Subject: [PATCH 2/3] tools/libxc: change xc_memshr_fork_reset API to match hypervisor Date: Wed, 27 Apr 2022 11:34:19 -0400 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: <7f03387eebf9de474f404ef661f80133e3725365.1651073086.git.tamas.lengyel@intel.com> References: <7f03387eebf9de474f404ef661f80133e3725365.1651073086.git.tamas.lengyel@intel.com> MIME-Version: 1.0 Need to separately specify if the reset is for the memory or for the VM state, or both. Signed-off-by: Tamas K Lengyel Reviewed-by: Roger Pau Monné --- v5: split from the hypervisor-side patch --- tools/include/xenctrl.h | 3 ++- tools/libs/ctrl/xc_memshr.c | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index 95bd5eca67..1b089a2c02 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -2290,7 +2290,8 @@ int xc_memshr_fork(xc_interface *xch, * * With VMs that have a lot of memory this call may block for a long time. */ -int xc_memshr_fork_reset(xc_interface *xch, uint32_t forked_domain); +int xc_memshr_fork_reset(xc_interface *xch, uint32_t forked_domain, + bool reset_state, bool reset_memory); /* Debug calls: return the number of pages referencing the shared frame backing * the input argument. Should be one or greater. diff --git a/tools/libs/ctrl/xc_memshr.c b/tools/libs/ctrl/xc_memshr.c index a6cfd7dccf..a0d0b894e2 100644 --- a/tools/libs/ctrl/xc_memshr.c +++ b/tools/libs/ctrl/xc_memshr.c @@ -257,12 +257,17 @@ int xc_memshr_fork(xc_interface *xch, uint32_t pdomid, uint32_t domid, return xc_memshr_memop(xch, domid, &mso); } -int xc_memshr_fork_reset(xc_interface *xch, uint32_t domid) +int xc_memshr_fork_reset(xc_interface *xch, uint32_t domid, bool reset_state, + bool reset_memory) { xen_mem_sharing_op_t mso; memset(&mso, 0, sizeof(mso)); mso.op = XENMEM_sharing_op_fork_reset; + if ( reset_state ) + mso.u.fork.flags |= XENMEM_FORK_RESET_STATE; + if ( reset_memory ) + mso.u.fork.flags |= XENMEM_FORK_RESET_MEMORY; return xc_memshr_memop(xch, domid, &mso); } From patchwork Wed Apr 27 15:34:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 12829005 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B1C6DC43217 for ; Wed, 27 Apr 2022 15:51:48 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.315214.533673 (Exim 4.92) (envelope-from ) id 1njjx3-0000Xo-Ax; Wed, 27 Apr 2022 15:51:37 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 315214.533673; Wed, 27 Apr 2022 15:51:37 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1njjx3-0000Xb-6V; Wed, 27 Apr 2022 15:51:37 +0000 Received: by outflank-mailman (input) for mailman id 315214; Wed, 27 Apr 2022 15:51:35 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1njjx1-0007rz-EW for xen-devel@lists.xenproject.org; Wed, 27 Apr 2022 15:51:35 +0000 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id e9a0b098-c641-11ec-a405-831a346695d4; Wed, 27 Apr 2022 17:51:34 +0200 (CEST) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Apr 2022 08:34:35 -0700 Received: from esimonso-mobl1.amr.corp.intel.com (HELO ubuntu.localdomain) ([10.212.23.42]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Apr 2022 08:34:32 -0700 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: e9a0b098-c641-11ec-a405-831a346695d4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1651074694; x=1682610694; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9QOZkEq66mA2UNTUZObc+xS271mkkoHO67ux88g75ZU=; b=Vp5WoSznnl0zAFUSdUKedzAECMIKygk4icmG1bmcKVbqCgVgZWQIqT5p uRqAUqFGEzquZyRvolRCj05inFSPnSYsVxHVXLagulLaOYiuUvc+aUJ2Y T3wzITLAq1Hn7AJ8NFmvdjaDQ6bhGwKy26f8El5aTlVgNpeXL+rKB1XNo zHHqdAjV2XqClzQ8CjQ6XUj03P6s0QmXuIbZ2DBwKvxOvub4i8JLjT1/t IQiyRXYvBEz2v8Y6oUNe5Epljk84hokOSdfG6A7vo13F/6HI1FQ4ePDT1 /Cd0l0slUsjpbJa+Ww72wS5vT63tw8WtMBeAZgaFc5VjvsS9Vg5/sEWN2 w==; X-IronPort-AV: E=McAfee;i="6400,9594,10330"; a="328915546" X-IronPort-AV: E=Sophos;i="5.90,293,1643702400"; d="scan'208";a="328915546" X-IronPort-AV: E=Sophos;i="5.90,293,1643702400"; d="scan'208";a="680854546" From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Cc: Tamas K Lengyel , Wei Liu , Anthony PERARD , Juergen Gross , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Tamas K Lengyel , Alexandru Isaila , Petre Pircalabu , =?utf-8?q?Roger_Pau_Monn?= =?utf-8?q?=C3=A9?= , Jun Nakajima , Kevin Tian Subject: [PATCH 3/3] x86/monitor: Add new monitor event to catch all vmexits Date: Wed, 27 Apr 2022 11:34:20 -0400 Message-Id: <65645a9d2ada525c9ffc07dce594eeff5891b5a7.1651073086.git.tamas.lengyel@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <7f03387eebf9de474f404ef661f80133e3725365.1651073086.git.tamas.lengyel@intel.com> References: <7f03387eebf9de474f404ef661f80133e3725365.1651073086.git.tamas.lengyel@intel.com> MIME-Version: 1.0 Add monitor event that hooks the vmexit handler allowing for both sync and async monitoring of events. With async monitoring an event is placed on the monitor ring for each exit and the rest of the vmexit handler resumes normally. If there are additional monitor events configured those will also place their respective events on the monitor ring. With the sync version an event is placed on the monitor ring but the handler does not get resumed, thus the sync version is only useful when the VM is not expected to resume normally after the vmexit. Our use-case is primarily with the sync version with VM forks where the fork gets reset after sync vmexit event, thus the rest of the vmexit handler can be safely skipped. This is very useful when we want to avoid Xen crashing the VM under any circumstance, for example during fuzzing. Collecting all vmexit information regardless of the root cause makes it easier to reason about the state of the VM on the monitor side, hence we opt to receive all events, even for external interrupt and NMI exits and let the monitor agent decide how to proceed. Signed-off-by: Tamas K Lengyel Reviewed-by: Roger Pau Monné Reviewed-by: Kevin Tian --- v5: wrap vmexit fields in arch.vmx structures in the public vm_event ABI --- tools/include/xenctrl.h | 2 ++ tools/libs/ctrl/xc_monitor.c | 15 +++++++++++++++ xen/arch/x86/hvm/monitor.c | 18 ++++++++++++++++++ xen/arch/x86/hvm/vmx/vmx.c | 12 ++++++++++++ xen/arch/x86/include/asm/domain.h | 2 ++ xen/arch/x86/include/asm/hvm/monitor.h | 2 ++ xen/arch/x86/include/asm/monitor.h | 3 ++- xen/arch/x86/monitor.c | 14 ++++++++++++++ xen/include/public/domctl.h | 6 ++++++ xen/include/public/vm_event.h | 12 ++++++++++++ 10 files changed, 85 insertions(+), 1 deletion(-) diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index 1b089a2c02..159eaac050 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -2096,6 +2096,8 @@ int xc_monitor_privileged_call(xc_interface *xch, uint32_t domain_id, bool enable); int xc_monitor_emul_unimplemented(xc_interface *xch, uint32_t domain_id, bool enable); +int xc_monitor_vmexit(xc_interface *xch, uint32_t domain_id, bool enable, + bool sync); /** * This function enables / disables emulation for each REP for a * REP-compatible instruction. diff --git a/tools/libs/ctrl/xc_monitor.c b/tools/libs/ctrl/xc_monitor.c index 4ac823e775..c5fa62ff30 100644 --- a/tools/libs/ctrl/xc_monitor.c +++ b/tools/libs/ctrl/xc_monitor.c @@ -246,6 +246,21 @@ int xc_monitor_emul_unimplemented(xc_interface *xch, uint32_t domain_id, return do_domctl(xch, &domctl); } +int xc_monitor_vmexit(xc_interface *xch, uint32_t domain_id, bool enable, + bool sync) +{ + DECLARE_DOMCTL; + + domctl.cmd = XEN_DOMCTL_monitor_op; + domctl.domain = domain_id; + domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE + : XEN_DOMCTL_MONITOR_OP_DISABLE; + domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_VMEXIT; + domctl.u.monitor_op.u.vmexit.sync = sync; + + return do_domctl(xch, &domctl); +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c index b44a1e1dfe..a11cd76f4d 100644 --- a/xen/arch/x86/hvm/monitor.c +++ b/xen/arch/x86/hvm/monitor.c @@ -328,6 +328,24 @@ bool hvm_monitor_check_p2m(unsigned long gla, gfn_t gfn, uint32_t pfec, return monitor_traps(curr, true, &req) >= 0; } +int hvm_monitor_vmexit(unsigned long exit_reason, + unsigned long exit_qualification) +{ + struct vcpu *curr = current; + struct arch_domain *ad = &curr->domain->arch; + vm_event_request_t req = {}; + + ASSERT(ad->monitor.vmexit_enabled); + + req.reason = VM_EVENT_REASON_VMEXIT; + req.u.vmexit.arch.vmx.reason = exit_reason; + req.u.vmexit.arch.vmx.qualification = exit_qualification; + + set_npt_base(curr, &req); + + return monitor_traps(curr, ad->monitor.vmexit_sync, &req); +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index cc8c4e9f04..4320270aae 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -4008,6 +4008,18 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) } } + if ( unlikely(currd->arch.monitor.vmexit_enabled) ) + { + int rc; + + __vmread(EXIT_QUALIFICATION, &exit_qualification); + rc = hvm_monitor_vmexit(exit_reason, exit_qualification); + if ( rc < 0 ) + goto exit_and_crash; + if ( rc ) + return; + } + /* XXX: This looks ugly, but we need a mechanism to ensure * any pending vmresume has really happened */ diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h index 35898d725f..3aa0919fa6 100644 --- a/xen/arch/x86/include/asm/domain.h +++ b/xen/arch/x86/include/asm/domain.h @@ -430,6 +430,8 @@ struct arch_domain */ unsigned int inguest_pagefault_disabled : 1; unsigned int control_register_values : 1; + unsigned int vmexit_enabled : 1; + unsigned int vmexit_sync : 1; struct monitor_msr_bitmap *msr_bitmap; uint64_t write_ctrlreg_mask[4]; } monitor; diff --git a/xen/arch/x86/include/asm/hvm/monitor.h b/xen/arch/x86/include/asm/hvm/monitor.h index a75cd8545c..639f6dfa37 100644 --- a/xen/arch/x86/include/asm/hvm/monitor.h +++ b/xen/arch/x86/include/asm/hvm/monitor.h @@ -51,6 +51,8 @@ bool hvm_monitor_emul_unimplemented(void); bool hvm_monitor_check_p2m(unsigned long gla, gfn_t gfn, uint32_t pfec, uint16_t kind); +int hvm_monitor_vmexit(unsigned long exit_reason, + unsigned long exit_qualification); #endif /* __ASM_X86_HVM_MONITOR_H__ */ diff --git a/xen/arch/x86/include/asm/monitor.h b/xen/arch/x86/include/asm/monitor.h index 01c6d63bb9..d8d54c5f23 100644 --- a/xen/arch/x86/include/asm/monitor.h +++ b/xen/arch/x86/include/asm/monitor.h @@ -89,7 +89,8 @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d) (1U << XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION) | (1U << XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG) | (1U << XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED) | - (1U << XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT)); + (1U << XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT) | + (1U << XEN_DOMCTL_MONITOR_EVENT_VMEXIT)); if ( hvm_is_singlestep_supported() ) capabilities |= (1U << XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP); diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c index 3079726a8b..30ca71432c 100644 --- a/xen/arch/x86/monitor.c +++ b/xen/arch/x86/monitor.c @@ -332,6 +332,20 @@ int arch_monitor_domctl_event(struct domain *d, break; } + case XEN_DOMCTL_MONITOR_EVENT_VMEXIT: + { + bool old_status = ad->monitor.vmexit_enabled; + + if ( unlikely(old_status == requested_status) ) + return -EEXIST; + + domain_pause(d); + ad->monitor.vmexit_enabled = requested_status; + ad->monitor.vmexit_sync = mop->u.vmexit.sync; + domain_unpause(d); + break; + } + default: /* * Should not be reached unless arch_monitor_get_capabilities() is diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index b85e6170b0..4803ed7afc 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -1057,6 +1057,7 @@ struct xen_domctl_psr_cmt_op { #define XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED 10 /* Enabled by default */ #define XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT 11 +#define XEN_DOMCTL_MONITOR_EVENT_VMEXIT 12 struct xen_domctl_monitor_op { uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */ @@ -1107,6 +1108,11 @@ struct xen_domctl_monitor_op { /* Pause vCPU until response */ uint8_t sync; } debug_exception; + + struct { + /* Send event and don't process vmexit */ + uint8_t sync; + } vmexit; } u; }; diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h index 1673bb8703..56b429a975 100644 --- a/xen/include/public/vm_event.h +++ b/xen/include/public/vm_event.h @@ -175,6 +175,8 @@ #define VM_EVENT_REASON_DESCRIPTOR_ACCESS 13 /* Current instruction is not implemented by the emulator */ #define VM_EVENT_REASON_EMUL_UNIMPLEMENTED 14 +/* VMEXIT */ +#define VM_EVENT_REASON_VMEXIT 15 /* Supported values for the vm_event_write_ctrlreg index. */ #define VM_EVENT_X86_CR0 0 @@ -394,6 +396,15 @@ struct vm_event_emul_insn_data { uint8_t data[16]; /* Has to be completely filled */ }; +struct vm_event_vmexit { + struct { + struct { + uint64_t reason; + uint64_t qualification; + } vmx; + } arch; +}; + typedef struct vm_event_st { uint32_t version; /* VM_EVENT_INTERFACE_VERSION */ uint32_t flags; /* VM_EVENT_FLAG_* */ @@ -414,6 +425,7 @@ typedef struct vm_event_st { struct vm_event_debug software_breakpoint; struct vm_event_debug debug_exception; struct vm_event_cpuid cpuid; + struct vm_event_vmexit vmexit; union { struct vm_event_interrupt_x86 x86; } interrupt;