:p
atchew
Login
Hi all, For the past few months, myself and Aqib Javid have been working to port altp2m to ARM with support from Stewart Hildebrand and Stefano Stabellini. At the recent Spring Xen Summit, Aqib and Stewart gave a presentation which discussed the motivation behind this, along with an overview of the rebasing and testing process. While this effort started as a rebase[1] of the v5 patch series[2] by Sergej Proskurin and Tamas Lengyel, I have been reworking the branch to make most of the altp2m code common between x86 and ARM. This should address the major concerns that came up during review of the original patch series. For a quick overview of altp2m functionality and scope of the patch series, here's an excerpt from Sergej's cover letter: > In this patch series, we provide an implementation of the altp2m > subsystem for ARM. Our implementation is based on the altp2m subsystem for > x86, providing additional --alternate-- views on the guest's physical > memory by means of the ARM 2nd stage translation mechanism. The patches > introduce new HVMOPs and extend the p2m subsystem. [...] To be more > precise, altp2m allows to create and switch to additional p2m views (i.e. > gfn to mfn mappings). These views can be manipulated and activated as will > through the provided HVMOPs. In this way, the active guest instance in > question can seamlessly proceed execution without noticing that anything > has changed. As of right now, I've reworked patch series up through the HVMOP_altp2m_set_domain_state command and plan to continue implementing the remaining altp2m features. I've continued the patch series versioning by labeling my notes as v6, and the patch notes from v1-v5 have been preserved where applicable. I am hoping for some feedback on the general approach I've taken with this patch series, and I can incorporate any changes requested into the actual patch series submission. This is a pretty big patch series, so I've tried to make it as easy as possible to follow. I've tried to minimize the number of changes in each patch; there are quite a lot of patches so if it would be preferred to combine some patches I can do so. Here is the general approach I used throughout the patch series to turn x86 altp2m code into common altp2m code with ARM support: - Move function(s) from arch/x86/mm/altp2m.c to common/altp2m.c, gating declarations/definitions with #ifdef CONFIG_X86 - Add any additional features to ARM code needed to implement these functions - Make any changes necessary to functions to support ARM, and remove #ifdef CONFIG_X86 This approach makes it possible to separate out code movement patches from the actual changes needed to support ARM. Furthermore, each patch in the patch series still compiles for both x86 and ARM. Additionally, I've split the patch series into a number of "phases" to make it easier to understand the context of each patch. Each patch description indicates which phase it's a part of. - Preparation (8 commits) - Common do_altp2m_op (2 commits) - get_domain_state (1 commit) - altp2m_{init,teardown} routines (12 commits) - altp2m_{get,set}_altp2m (4 commits) - Needed for altp2m_vcpu_{initialise,destroy} - altp2m_vcpu_{initialise,destroy} (2 commits) - Needed for HVMOP_set_domain_state - altp2m view visibility (5 commits) - Needed for altp2m_init_by_id, altp2m_flush - altp2m_activate_altp2m (2 commits) - Needed for altp2m_init_by_id - altp2m_init_by_id (2 commits) - Needed for HVMOP_altp2m_set_domain_state - altp2m_reset_altp2m (2 commits) - Needed for altp2m_flush - altp2m_flush (2 commits) - Needed for HVMOP_altp2m_set_domain_state - set_domain_state (1 commit) The code for this patch series can also be found on GitLab: https://gitlab.com/xen-project/people/elektrobit/xen/-/tree/altp2m-arm-rework-rfc Best, Rose Spangler [1] Rebase of original patch series: https://gitlab.com/xen-project/people/elektrobit/xen/-/commits/altp2m-arm-rebase [2] Original patch series: v1: https://lore.kernel.org/xen-devel/20160704114605.10086-1-proskurin@sec.in.tum.de/ v2: https://lore.kernel.org/xen-devel/20160801171028.11615-1-proskurin@sec.in.tum.de/ v3: https://lore.kernel.org/xen-devel/20160816221714.22041-1-proskurin@sec.in.tum.de/ v4: https://lore.kernel.org/xen-devel/20170830183258.14612-1-proskurin@sec.in.tum.de/ v5 was never submitted to mailing list, but is available on GitHub: https://github.com/sergej-proskurin/xen/tree/arm-altp2m-v5 (Resend due to threading issues in first send attempt) Rose Spangler (38): altp2m: Add template common altp2m.c/altp2m.h altp2m: Move altp2m_active to common domain struct altp2m: Move altp2m_p2m to common domain struct x86/altp2m: Rename hvm_altp2m_supported to altp2m_supported altp2m: Move altp2m_supported to arch header arm/altp2m: Add template arch-specific altp2m.c/altp2m.h arm/altp2m: Introduce CONFIG_ALTP2M Kconfig option altp2m: Rename p2m_*_altp2m functions and move declarations out of p2m.h altp2m: Move do_altp2m_op to common code altp2m: Add ARM support to do_altp2m_op arm/altp2m: Add support for HVMOP_altp2m_get_domain_state x86/p2m: Move p2m_{init,free}_one declarations to arch header x86/altp2m: Add lock functions accessible from common code altp2m: Move altp2m_{init,teardown} to common code arm/p2m: Allocate hostp2m with xzalloc arm/p2m: Move hostp2m init/teardown to individual functions arm/p2m: Invalidate root page table entries and flush TLB in p2m_flush_table arm/altp2m: Add support for altp2m init/teardown routines altp2m: Move altp2m_{get,set}_altp2m to common code arm/altp2m: Add altp2m index to arch_vcpu altp2m: Add altp2m_set_vcpu_idx arm/altp2m: Add support for altp2m_{get,set}_altp2m altp2m: Move altp2m_vcpu_{initialise,destroy} to common code arm/altp2m: Add support for altp2m_vcpu_{initialise,destroy} arm/altp2m: Add altp2m view validity/visibility indicator altp2m: Add altp2m_view_is_{valid,visible} x86/altp2m: Add altp2m_set_view_visibility_locked arm/altp2m: Add altp2m_set_view_visibility{,_locked} support arm/altp2m: Add support for HVMOP_altp2m_set_visibility x86/altp2m: Add altp2m_activate_altp2m declaration to arch header arm/altp2m: Add support for altp2m_activate_altp2m altp2m: Move altp2m_init_by_id to common code arm/altp2m: Add support for altp2m_init_by_id x86/altp2m: Add altp2m_reset_altp2m declaration to arch header arm/altp2m: Add altp2m_reset_altp2m routine altp2m: Move altp2m_flush to common code arm/altp2m: Add support for altp2m_flush arm/p2m: Add support for HVMOP_altp2m_set_domain_state Sergej Proskurin (5): arm/p2m: Cosmetic fix - substitute _gfn(ULONG_MAX) for INVALID_GFN arm/p2m: Change function prototype of p2m_alloc_table arm/p2m: Rename parameter in p2m_alloc_vmid arm/p2m: Change func prototype and impl of p2m_{alloc,free}_vmid arm/p2m: Introduce p2m_is_{hostp2m,altp2m} xen/arch/arm/Kconfig | 11 + xen/arch/arm/Makefile | 1 + xen/arch/arm/altp2m.c | 122 +++++ xen/arch/arm/domain.c | 2 +- xen/arch/arm/hvm.c | 9 + xen/arch/arm/include/asm/Makefile | 1 - xen/arch/arm/include/asm/altp2m.h | 84 ++++ xen/arch/arm/include/asm/domain.h | 19 +- xen/arch/arm/include/asm/p2m.h | 41 +- xen/arch/arm/mm.c | 2 +- xen/arch/arm/mmu/p2m.c | 162 ++++++- xen/arch/arm/p2m.c | 31 +- xen/arch/arm/traps.c | 2 +- xen/arch/x86/domain.c | 3 +- xen/arch/x86/hvm/emulate.c | 1 + xen/arch/x86/hvm/hvm.c | 413 +---------------- xen/arch/x86/hvm/monitor.c | 3 +- xen/arch/x86/hvm/vmx/vmx.c | 9 +- xen/arch/x86/include/asm/altp2m.h | 115 ++++- xen/arch/x86/include/asm/domain.h | 5 - xen/arch/x86/include/asm/hvm/hvm.h | 11 - xen/arch/x86/include/asm/p2m.h | 112 +---- xen/arch/x86/mm/altp2m.c | 242 +++------- xen/arch/x86/mm/hap/hap.c | 17 +- xen/arch/x86/mm/mem_access.c | 22 +- xen/arch/x86/mm/mem_sharing.c | 3 +- xen/arch/x86/mm/p2m-basic.c | 7 +- xen/arch/x86/mm/p2m-ept.c | 13 +- xen/arch/x86/mm/p2m-pt.c | 1 + xen/arch/x86/mm/p2m.c | 9 +- xen/arch/x86/mm/p2m.h | 6 - xen/common/Makefile | 1 + xen/common/altp2m.c | 551 +++++++++++++++++++++++ xen/common/monitor.c | 1 + xen/common/vm_event.c | 2 +- xen/drivers/passthrough/arm/ipmmu-vmsa.c | 2 +- xen/drivers/passthrough/arm/smmu-v3.c | 2 +- xen/drivers/passthrough/arm/smmu.c | 2 +- xen/include/asm-generic/altp2m.h | 5 +- xen/include/xen/altp2m.h | 98 ++++ xen/include/xen/p2m-common.h | 2 +- xen/include/xen/sched.h | 3 + 42 files changed, 1330 insertions(+), 818 deletions(-) create mode 100644 xen/arch/arm/altp2m.c create mode 100644 xen/arch/arm/include/asm/altp2m.h create mode 100644 xen/common/altp2m.c create mode 100644 xen/include/xen/altp2m.h -- 2.34.1
This commit adds an empty common altp2m.c and altp2m.h file to be added to in later commits. Creating a commit with just the empty file additions makes it easier to reorder later commits which add to these files. This commit can be squashed into the first commit which actually adds something to altp2m.c/altp2m.h for the actual submission if that would be preferred. This is commit 1/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/common/Makefile | 1 + xen/common/altp2m.c | 12 ++++++++++++ xen/include/xen/altp2m.h | 5 +++++ 3 files changed, 18 insertions(+) create mode 100644 xen/common/altp2m.c create mode 100644 xen/include/xen/altp2m.h diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ +obj-$(CONFIG_ALTP2M) += altp2m.o obj-$(CONFIG_ARGO) += argo.o obj-y += bitmap.o obj-bin-$(CONFIG_SELF_TESTS) += bitops.init.o diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <xen/altp2m.h> + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __XEN_ALTP2M_H__ +#define __XEN_ALTP2M_H__ + +#endif /* __XEN_ALTP2M_H__ */ -- 2.34.1
This commit moves altp2m_active from arch_domain on x86 to the common domain struct. Similarly to nr_altp2m, this is not an arch-specific value. Moving it to common code allows the common altp2m routines introduced later in this patch series to operate on altp2m_active without needing an altp2m_active member on arch_domain for each architecture supporting altp2m. This is commit 2/8 of the preparation phase. This commit is a refactor, and no change in functionality is intended. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/hvm/emulate.c | 1 + xen/arch/x86/hvm/hvm.c | 11 ++++++----- xen/arch/x86/hvm/monitor.c | 1 + xen/arch/x86/hvm/vmx/vmx.c | 1 + xen/arch/x86/include/asm/altp2m.h | 11 ----------- xen/arch/x86/include/asm/domain.h | 2 -- xen/arch/x86/mm/altp2m.c | 1 + xen/arch/x86/mm/hap/hap.c | 5 +++-- xen/arch/x86/mm/mem_access.c | 1 + xen/arch/x86/mm/mem_sharing.c | 1 + xen/arch/x86/mm/p2m-ept.c | 1 + xen/arch/x86/mm/p2m-pt.c | 1 + xen/arch/x86/mm/p2m.c | 1 + xen/common/monitor.c | 1 + xen/include/asm-generic/altp2m.h | 8 -------- xen/include/xen/altp2m.h | 19 +++++++++++++++++++ xen/include/xen/sched.h | 2 ++ 17 files changed, 40 insertions(+), 28 deletions(-) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -XXX,XX +XXX,XX @@ * Keir Fraser <keir@xen.org> */ +#include <xen/altp2m.h> #include <xen/init.h> #include <xen/iocap.h> #include <xen/ioreq.h> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2008, Citrix Systems, Inc. */ +#include <xen/altp2m.h> #include <xen/console.h> #include <xen/cpu.h> #include <xen/domain.h> @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( if ( (a.cmd != HVMOP_altp2m_get_domain_state) && (a.cmd != HVMOP_altp2m_set_domain_state) && - !d->arch.altp2m_active ) + !d->altp2m_active ) { rc = -EOPNOTSUPP; goto out; @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( if ( rc ) break; - ostate = d->arch.altp2m_active; - d->arch.altp2m_active = !!a.u.domain_state.state; + ostate = d->altp2m_active; + d->altp2m_active = !!a.u.domain_state.state; /* If the alternate p2m state has changed, handle appropriately */ - if ( d->arch.altp2m_active != ostate && + if ( d->altp2m_active != ostate && (ostate || !(rc = p2m_init_altp2m_by_id(d, 0))) ) { for_each_vcpu( d, v ) @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( p2m_flush_altp2m(d); } else if ( rc ) - d->arch.altp2m_active = false; + d->altp2m_active = false; domain_unpause_except_self(d); break; diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/monitor.c +++ b/xen/arch/x86/hvm/monitor.c @@ -XXX,XX +XXX,XX @@ * this program; If not, see <http://www.gnu.org/licenses/>. */ +#include <xen/altp2m.h> #include <xen/vm_event.h> #include <xen/mem_access.h> #include <xen/monitor.h> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2004, Intel Corporation. */ +#include <xen/altp2m.h> #include <xen/domain_page.h> #include <xen/guest_access.h> #include <xen/hypercall.h> diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_is_eptp_valid(const struct domain *d, mfn_x(INVALID_MFN); } -/* Alternate p2m HVM on/off per domain */ -static inline bool altp2m_active(const struct domain *d) -{ - return d->arch.altp2m_active; -} - static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) { return vcpu_altp2m(v).p2midx; @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_is_eptp_valid(const struct domain *d, return false; } -static inline bool altp2m_active(const struct domain *d) -{ - return false; -} - /* Only declaration is needed. DCE will optimise it out when linking. */ uint16_t altp2m_vcpu_idx(const struct vcpu *v); void altp2m_vcpu_initialise(struct vcpu *v); diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/domain.h +++ b/xen/arch/x86/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct arch_domain mm_lock_t nested_p2m_lock; #ifdef CONFIG_ALTP2M - /* altp2m: allow multiple copies of host p2m */ - bool altp2m_active; struct p2m_domain **altp2m_p2m; mm_lock_t altp2m_list_lock; uint64_t *altp2m_eptp; diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <asm/p2m.h> #include <asm/altp2m.h> #include <public/hvm/hvm_op.h> +#include <xen/altp2m.h> #include <xen/event.h> #include <xen/xvmalloc.h> #include "mm-locks.h" diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -XXX,XX +XXX,XX @@ * Parts of this code are Copyright (c) 2007 by XenSource Inc. */ +#include <xen/altp2m.h> #include <xen/types.h> #include <xen/mm.h> #include <xen/trace.h> @@ -XXX,XX +XXX,XX @@ int hap_enable(struct domain *d, u32 mode) goto out; } - d->arch.altp2m_active = false; + d->altp2m_active = false; } #endif /* CONFIG_ALTP2M */ @@ -XXX,XX +XXX,XX @@ void hap_teardown(struct domain *d, bool *preempted) for_each_vcpu ( d, v ) altp2m_vcpu_disable_ve(v); - d->arch.altp2m_active = false; + d->altp2m_active = false; FREE_XENHEAP_PAGE(d->arch.altp2m_eptp); FREE_XENHEAP_PAGE(d->arch.altp2m_visible_eptp); diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_access.c +++ b/xen/arch/x86/mm/mem_access.c @@ -XXX,XX +XXX,XX @@ * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al. */ +#include <xen/altp2m.h> #include <xen/guest_access.h> /* copy_from_guest() */ #include <xen/mem_access.h> #include <xen/nospec.h> diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) */ +#include <xen/altp2m.h> #include <xen/types.h> #include <xen/domain_page.h> #include <xen/event.h> diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2007, Intel Corporation. */ +#include <xen/altp2m.h> #include <xen/domain_page.h> #include <xen/sched.h> #include <public/hvm/dm_op.h> diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-pt.c +++ b/xen/arch/x86/mm/p2m-pt.c @@ -XXX,XX +XXX,XX @@ * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al. */ +#include <xen/altp2m.h> #include <xen/vm_event.h> #include <xen/event.h> #include <xen/trace.h> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -XXX,XX +XXX,XX @@ * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al. */ +#include <xen/altp2m.h> #include <xen/iommu.h> #include <xen/mem_access.h> #include <xen/vm_event.h> diff --git a/xen/common/monitor.c b/xen/common/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/monitor.c +++ b/xen/common/monitor.c @@ -XXX,XX +XXX,XX @@ * License along with this program; If not, see <http://www.gnu.org/licenses/>. */ +#include <xen/altp2m.h> #include <xen/event.h> #include <xen/monitor.h> #include <xen/sched.h> diff --git a/xen/include/asm-generic/altp2m.h b/xen/include/asm-generic/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/asm-generic/altp2m.h +++ b/xen/include/asm-generic/altp2m.h @@ -XXX,XX +XXX,XX @@ #include <xen/bug.h> -struct domain; struct vcpu; -/* Alternate p2m on/off per domain */ -static inline bool altp2m_active(const struct domain *d) -{ - /* Not implemented on GENERIC. */ - return false; -} - /* Alternate p2m VCPU */ static inline unsigned int altp2m_vcpu_idx(const struct vcpu *v) { diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ #ifndef __XEN_ALTP2M_H__ #define __XEN_ALTP2M_H__ +#include <xen/sched.h> + +#ifdef CONFIG_ALTP2M + +/* Alternate p2m HVM on/off per domain */ +static inline bool altp2m_active(const struct domain *d) +{ + return d->altp2m_active; +} + +#else /* CONFIG_ALTP2M */ + +static inline bool altp2m_active(const struct domain *d) +{ + return false; +} + +#endif /* CONFIG_ALTP2M */ + #endif /* __XEN_ALTP2M_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ struct domain } monitor; #ifdef CONFIG_ALTP2M + /* altp2m: allow multiple copies of host p2m */ + bool altp2m_active; unsigned int nr_altp2m; /* Number of altp2m tables. */ #endif -- 2.34.1
Similarly to the previous commit, this commit moves altp2m_p2m to the common domain struct. The representation of altp2m views as an array of p2m_domain pointers is the same on x86 and ARM, and it seems that this would be the case for other architectures as well. This commit is a refactor, and no change in functionality is intended. This is commit 3/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/hvm/vmx/vmx.c | 2 +- xen/arch/x86/include/asm/domain.h | 1 - xen/arch/x86/include/asm/p2m.h | 4 ++-- xen/arch/x86/mm/altp2m.c | 28 ++++++++++++++-------------- xen/arch/x86/mm/hap/hap.c | 6 +++--- xen/arch/x86/mm/mem_access.c | 8 ++++---- xen/arch/x86/mm/mem_sharing.c | 2 +- xen/arch/x86/mm/p2m-ept.c | 6 +++--- xen/arch/x86/mm/p2m.c | 8 ++++---- xen/include/xen/sched.h | 1 + 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -XXX,XX +XXX,XX @@ bool asmlinkage vmx_vmenter_helper(const struct cpu_user_regs *regs) if ( currd->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - ept = &currd->arch.altp2m_p2m[i]->ept; + ept = &currd->altp2m_p2m[i]->ept; if ( cpumask_test_cpu(cpu, ept->invalidate) ) { cpumask_clear_cpu(cpu, ept->invalidate); diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/domain.h +++ b/xen/arch/x86/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct arch_domain mm_lock_t nested_p2m_lock; #ifdef CONFIG_ALTP2M - struct p2m_domain **altp2m_p2m; mm_lock_t altp2m_list_lock; uint64_t *altp2m_eptp; uint64_t *altp2m_visible_eptp; diff --git a/xen/arch/x86/include/asm/p2m.h b/xen/arch/x86/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/p2m.h +++ b/xen/arch/x86/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ static inline struct p2m_domain *p2m_get_altp2m(struct vcpu *v) BUG_ON(index >= v->domain->nr_altp2m); - return v->domain->arch.altp2m_p2m[index]; + return v->domain->altp2m_p2m[index]; } /* set current alternate p2m table */ @@ -XXX,XX +XXX,XX @@ static inline bool p2m_set_altp2m(struct vcpu *v, unsigned int idx) atomic_dec(&orig->active_vcpus); vcpu_altp2m(v).p2midx = idx; - atomic_inc(&v->domain->arch.altp2m_p2m[idx]->active_vcpus); + atomic_inc(&v->domain->altp2m_p2m[idx]->active_vcpus); return true; } diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ int p2m_init_altp2m(struct domain *d) struct p2m_domain *hostp2m = p2m_get_hostp2m(d); mm_lock_init(&d->arch.altp2m_list_lock); - d->arch.altp2m_p2m = xvzalloc_array(struct p2m_domain *, d->nr_altp2m); + d->altp2m_p2m = xvzalloc_array(struct p2m_domain *, d->nr_altp2m); - if ( !d->arch.altp2m_p2m ) + if ( !d->altp2m_p2m ) return -ENOMEM; for ( i = 0; i < d->nr_altp2m; i++ ) { - d->arch.altp2m_p2m[i] = p2m = p2m_init_one(d); + d->altp2m_p2m[i] = p2m = p2m_init_one(d); if ( p2m == NULL ) { p2m_teardown_altp2m(d); @@ -XXX,XX +XXX,XX @@ void p2m_teardown_altp2m(struct domain *d) for ( i = 0; i < d->nr_altp2m; i++ ) { - if ( !d->arch.altp2m_p2m[i] ) + if ( !d->altp2m_p2m[i] ) continue; - p2m = d->arch.altp2m_p2m[i]; - d->arch.altp2m_p2m[i] = NULL; + p2m = d->altp2m_p2m[i]; + d->altp2m_p2m[i] = NULL; p2m_free_one(p2m); } - XVFREE(d->arch.altp2m_p2m); + XVFREE(d->altp2m_p2m); } int altp2m_get_effective_entry(struct p2m_domain *ap2m, gfn_t gfn, mfn_t *mfn, @@ -XXX,XX +XXX,XX @@ static void p2m_reset_altp2m(struct domain *d, unsigned int idx, struct p2m_domain *p2m; ASSERT(idx < d->nr_altp2m); - p2m = d->arch.altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + p2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; p2m_lock(p2m); @@ -XXX,XX +XXX,XX @@ static int p2m_activate_altp2m(struct domain *d, unsigned int idx, ASSERT(idx < d->nr_altp2m); - p2m = d->arch.altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + p2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; hostp2m = p2m_get_hostp2m(d); p2m_lock(p2m); @@ -XXX,XX +XXX,XX @@ int p2m_destroy_altp2m_by_id(struct domain *d, unsigned int idx) if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] != mfn_x(INVALID_MFN) ) { - p2m = d->arch.altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + p2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; if ( !_atomic_read(p2m->active_vcpus) ) { @@ -XXX,XX +XXX,XX @@ int p2m_change_altp2m_gfn(struct domain *d, unsigned int idx, return rc; hp2m = p2m_get_hostp2m(d); - ap2m = d->arch.altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + ap2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; p2m_lock(hp2m); p2m_lock(ap2m); @@ -XXX,XX +XXX,XX @@ int p2m_altp2m_propagate_change(struct domain *d, gfn_t gfn, if ( d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - p2m = d->arch.altp2m_p2m[i]; + p2m = d->altp2m_p2m[i]; /* Check for a dropped page that may impact this altp2m */ if ( mfn_eq(mfn, INVALID_MFN) && @@ -XXX,XX +XXX,XX @@ int p2m_set_suppress_ve_multi(struct domain *d, return -EINVAL; p2m = ap2m = - d->arch.altp2m_p2m[array_index_nospec(sve->view, d->nr_altp2m)]; + d->altp2m_p2m[array_index_nospec(sve->view, d->nr_altp2m)]; } p2m_lock(host_p2m); @@ -XXX,XX +XXX,XX @@ int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, return -EINVAL; p2m = ap2m = - d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; + d->altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; } else p2m = host_p2m; diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -XXX,XX +XXX,XX @@ int hap_enable(struct domain *d, u32 mode) for ( i = 0; i < d->nr_altp2m; i++ ) { - rv = p2m_alloc_table(d->arch.altp2m_p2m[i]); + rv = p2m_alloc_table(d->altp2m_p2m[i]); if ( rv != 0 ) goto out; } @@ -XXX,XX +XXX,XX @@ void hap_final_teardown(struct domain *d) #ifdef CONFIG_ALTP2M if ( hvm_altp2m_supported() ) for ( i = 0; i < d->nr_altp2m; i++ ) - p2m_teardown(d->arch.altp2m_p2m[i], true, NULL); + p2m_teardown(d->altp2m_p2m[i], true, NULL); #endif /* Destroy nestedp2m's first */ @@ -XXX,XX +XXX,XX @@ void hap_teardown(struct domain *d, bool *preempted) for ( i = 0; i < d->nr_altp2m; i++ ) { - p2m_teardown(d->arch.altp2m_p2m[i], false, preempted); + p2m_teardown(d->altp2m_p2m[i], false, preempted); if ( preempted && *preempted ) return; } diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_access.c +++ b/xen/arch/x86/mm/mem_access.c @@ -XXX,XX +XXX,XX @@ long p2m_set_mem_access(struct domain *d, gfn_t gfn, uint32_t nr, if ( !altp2m_is_eptp_valid(d, altp2m_idx) ) return -EINVAL; - ap2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; + ap2m = d->altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; } #endif @@ -XXX,XX +XXX,XX @@ long p2m_set_mem_access_multi(struct domain *d, if ( !altp2m_is_eptp_valid(d, altp2m_idx) ) return -EINVAL; - ap2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; + ap2m = d->altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; } #endif @@ -XXX,XX +XXX,XX @@ int p2m_get_mem_access(struct domain *d, gfn_t gfn, xenmem_access_t *access, if ( !altp2m_is_eptp_valid(d, altp2m_idx) ) return -EINVAL; - p2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; + p2m = d->altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; } #endif @@ -XXX,XX +XXX,XX @@ void arch_p2m_set_access_required(struct domain *d, bool access_required) unsigned int i; for ( i = 0; i < d->nr_altp2m; i++ ) { - struct p2m_domain *p2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *p2m = d->altp2m_p2m[i]; if ( p2m ) p2m->access_required = access_required; diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -XXX,XX +XXX,XX @@ static int nominate_page(struct domain *d, gfn_t gfn, for ( i = 0; i < d->nr_altp2m; i++ ) { - ap2m = d->arch.altp2m_p2m[i]; + ap2m = d->altp2m_p2m[i]; if ( !ap2m ) continue; diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -XXX,XX +XXX,XX @@ static void ept_set_ad_sync(struct domain *d, bool value) if ( d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - p2m = d->arch.altp2m_p2m[i]; + p2m = d->altp2m_p2m[i]; p2m_lock(p2m); p2m->ept.ad = value; @@ -XXX,XX +XXX,XX @@ void __init setup_ept_dump(void) void p2m_init_altp2m_ept(struct domain *d, unsigned int i) { struct p2m_domain *p2m = - d->arch.altp2m_p2m[array_index_nospec(i, d->nr_altp2m)]; + d->altp2m_p2m[array_index_nospec(i, d->nr_altp2m)]; struct p2m_domain *hostp2m = p2m_get_hostp2m(d); struct ept_data *ept; @@ -XXX,XX +XXX,XX @@ unsigned int p2m_find_altp2m_by_eptp(struct domain *d, uint64_t eptp) if ( d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - p2m = d->arch.altp2m_p2m[i]; + p2m = d->altp2m_p2m[i]; ept = &p2m->ept; if ( eptp == ept->eptp ) diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_change_entry_type_global(struct domain *d, { if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) { - struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *altp2m = d->altp2m_p2m[i]; p2m_lock(altp2m); change_entry_type_global(altp2m, ot, nt); @@ -XXX,XX +XXX,XX @@ bool p2m_memory_type_changed(struct domain *d) { if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) { - struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *altp2m = d->altp2m_p2m[i]; p2m_lock(altp2m); _memory_type_changed(altp2m); @@ -XXX,XX +XXX,XX @@ void p2m_change_type_range(struct domain *d, { if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) { - struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *altp2m = d->altp2m_p2m[i]; p2m_lock(altp2m); change_type_range(altp2m, start, end, ot, nt); @@ -XXX,XX +XXX,XX @@ int p2m_finish_type_change(struct domain *d, { if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) { - struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *altp2m = d->altp2m_p2m[i]; p2m_lock(altp2m); rc = finish_type_change(altp2m, first_gfn, max_nr); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ struct domain /* altp2m: allow multiple copies of host p2m */ bool altp2m_active; unsigned int nr_altp2m; /* Number of altp2m tables. */ + struct p2m_domain **altp2m_p2m; #endif #ifdef CONFIG_VMTRACE -- 2.34.1
Hi all, For the past few months, myself and Aqib Javid have been working to port altp2m to ARM with support from Stewart Hildebrand and Stefano Stabellini. At the recent Spring Xen Summit, Aqib and Stewart gave a presentation which discussed the motivation behind this, along with an overview of the rebasing and testing process. While this effort started as a rebase[1] of the v5 patch series[2] by Sergej Proskurin and Tamas Lengyel, I have been reworking the branch to make most of the altp2m code common between x86 and ARM. This should address the major concerns that came up during review of the original patch series. For a quick overview of altp2m functionality and scope of the patch series, here's an excerpt from Sergej's cover letter: > In this patch series, we provide an implementation of the altp2m > subsystem for ARM. Our implementation is based on the altp2m subsystem for > x86, providing additional --alternate-- views on the guest's physical > memory by means of the ARM 2nd stage translation mechanism. The patches > introduce new HVMOPs and extend the p2m subsystem. [...] To be more > precise, altp2m allows to create and switch to additional p2m views (i.e. > gfn to mfn mappings). These views can be manipulated and activated as will > through the provided HVMOPs. In this way, the active guest instance in > question can seamlessly proceed execution without noticing that anything > has changed. As of right now, I've reworked patch series up through the HVMOP_altp2m_set_domain_state command and plan to continue implementing the remaining altp2m features. I've continued the patch series versioning by labeling my notes as v6, and the patch notes from v1-v5 have been preserved where applicable. I am hoping for some feedback on the general approach I've taken with this patch series, and I can incorporate any changes requested into the actual patch series submission. This is a pretty big patch series, so I've tried to make it as easy as possible to follow. I've tried to minimize the number of changes in each patch; there are quite a lot of patches so if it would be preferred to combine some patches I can do so. Here is the general approach I used throughout the patch series to turn x86 altp2m code into common altp2m code with ARM support: - Move function(s) from arch/x86/mm/altp2m.c to common/altp2m.c, gating declarations/definitions with #ifdef CONFIG_X86 - Add any additional features to ARM code needed to implement these functions - Make any changes necessary to functions to support ARM, and remove #ifdef CONFIG_X86 This approach makes it possible to separate out code movement patches from the actual changes needed to support ARM. Furthermore, each patch in the patch series still compiles for both x86 and ARM. Additionally, I've split the patch series into a number of "phases" to make it easier to understand the context of each patch. Each patch description indicates which phase it's a part of. - Preparation (8 commits) - Common do_altp2m_op (2 commits) - get_domain_state (1 commit) - altp2m_{init,teardown} routines (12 commits) - altp2m_{get,set}_altp2m (4 commits) - Needed for altp2m_vcpu_{initialise,destroy} - altp2m_vcpu_{initialise,destroy} (2 commits) - Needed for HVMOP_set_domain_state - altp2m view visibility (5 commits) - Needed for altp2m_init_by_id, altp2m_flush - altp2m_activate_altp2m (2 commits) - Needed for altp2m_init_by_id - altp2m_init_by_id (2 commits) - Needed for HVMOP_altp2m_set_domain_state - altp2m_reset_altp2m (2 commits) - Needed for altp2m_flush - altp2m_flush (2 commits) - Needed for HVMOP_altp2m_set_domain_state - set_domain_state (1 commit) The code for this patch series can also be found on GitLab: https://gitlab.com/xen-project/people/elektrobit/xen/-/tree/altp2m-arm-rework-rfc Best, Rose Spangler [1] Rebase of original patch series: https://gitlab.com/xen-project/people/elektrobit/xen/-/commits/altp2m-arm-rebase [2] Original patch series: v1: https://lore.kernel.org/xen-devel/20160704114605.10086-1-proskurin@sec.in.tum.de/ v2: https://lore.kernel.org/xen-devel/20160801171028.11615-1-proskurin@sec.in.tum.de/ v3: https://lore.kernel.org/xen-devel/20160816221714.22041-1-proskurin@sec.in.tum.de/ v4: https://lore.kernel.org/xen-devel/20170830183258.14612-1-proskurin@sec.in.tum.de/ v5 was never submitted to mailing list, but is available on GitHub: https://github.com/sergej-proskurin/xen/tree/arm-altp2m-v5 (Resend due to threading issues in first send attempt) Rose Spangler (38): altp2m: Add template common altp2m.c/altp2m.h altp2m: Move altp2m_active to common domain struct altp2m: Move altp2m_p2m to common domain struct x86/altp2m: Rename hvm_altp2m_supported to altp2m_supported altp2m: Move altp2m_supported to arch header arm/altp2m: Add template arch-specific altp2m.c/altp2m.h arm/altp2m: Introduce CONFIG_ALTP2M Kconfig option altp2m: Rename p2m_*_altp2m functions and move declarations out of p2m.h altp2m: Move do_altp2m_op to common code altp2m: Add ARM support to do_altp2m_op arm/altp2m: Add support for HVMOP_altp2m_get_domain_state x86/p2m: Move p2m_{init,free}_one declarations to arch header x86/altp2m: Add lock functions accessible from common code altp2m: Move altp2m_{init,teardown} to common code arm/p2m: Allocate hostp2m with xzalloc arm/p2m: Move hostp2m init/teardown to individual functions arm/p2m: Invalidate root page table entries and flush TLB in p2m_flush_table arm/altp2m: Add support for altp2m init/teardown routines altp2m: Move altp2m_{get,set}_altp2m to common code arm/altp2m: Add altp2m index to arch_vcpu altp2m: Add altp2m_set_vcpu_idx arm/altp2m: Add support for altp2m_{get,set}_altp2m altp2m: Move altp2m_vcpu_{initialise,destroy} to common code arm/altp2m: Add support for altp2m_vcpu_{initialise,destroy} arm/altp2m: Add altp2m view validity/visibility indicator altp2m: Add altp2m_view_is_{valid,visible} x86/altp2m: Add altp2m_set_view_visibility_locked arm/altp2m: Add altp2m_set_view_visibility{,_locked} support arm/altp2m: Add support for HVMOP_altp2m_set_visibility x86/altp2m: Add altp2m_activate_altp2m declaration to arch header arm/altp2m: Add support for altp2m_activate_altp2m altp2m: Move altp2m_init_by_id to common code arm/altp2m: Add support for altp2m_init_by_id x86/altp2m: Add altp2m_reset_altp2m declaration to arch header arm/altp2m: Add altp2m_reset_altp2m routine altp2m: Move altp2m_flush to common code arm/altp2m: Add support for altp2m_flush arm/p2m: Add support for HVMOP_altp2m_set_domain_state Sergej Proskurin (5): arm/p2m: Cosmetic fix - substitute _gfn(ULONG_MAX) for INVALID_GFN arm/p2m: Change function prototype of p2m_alloc_table arm/p2m: Rename parameter in p2m_alloc_vmid arm/p2m: Change func prototype and impl of p2m_{alloc,free}_vmid arm/p2m: Introduce p2m_is_{hostp2m,altp2m} xen/arch/arm/Kconfig | 11 + xen/arch/arm/Makefile | 1 + xen/arch/arm/altp2m.c | 122 +++++ xen/arch/arm/domain.c | 2 +- xen/arch/arm/hvm.c | 9 + xen/arch/arm/include/asm/Makefile | 1 - xen/arch/arm/include/asm/altp2m.h | 84 ++++ xen/arch/arm/include/asm/domain.h | 19 +- xen/arch/arm/include/asm/p2m.h | 41 +- xen/arch/arm/mm.c | 2 +- xen/arch/arm/mmu/p2m.c | 162 ++++++- xen/arch/arm/p2m.c | 31 +- xen/arch/arm/traps.c | 2 +- xen/arch/x86/domain.c | 3 +- xen/arch/x86/hvm/emulate.c | 1 + xen/arch/x86/hvm/hvm.c | 413 +---------------- xen/arch/x86/hvm/monitor.c | 3 +- xen/arch/x86/hvm/vmx/vmx.c | 9 +- xen/arch/x86/include/asm/altp2m.h | 115 ++++- xen/arch/x86/include/asm/domain.h | 5 - xen/arch/x86/include/asm/hvm/hvm.h | 11 - xen/arch/x86/include/asm/p2m.h | 112 +---- xen/arch/x86/mm/altp2m.c | 242 +++------- xen/arch/x86/mm/hap/hap.c | 17 +- xen/arch/x86/mm/mem_access.c | 22 +- xen/arch/x86/mm/mem_sharing.c | 3 +- xen/arch/x86/mm/p2m-basic.c | 7 +- xen/arch/x86/mm/p2m-ept.c | 13 +- xen/arch/x86/mm/p2m-pt.c | 1 + xen/arch/x86/mm/p2m.c | 9 +- xen/arch/x86/mm/p2m.h | 6 - xen/common/Makefile | 1 + xen/common/altp2m.c | 551 +++++++++++++++++++++++ xen/common/monitor.c | 1 + xen/common/vm_event.c | 2 +- xen/drivers/passthrough/arm/ipmmu-vmsa.c | 2 +- xen/drivers/passthrough/arm/smmu-v3.c | 2 +- xen/drivers/passthrough/arm/smmu.c | 2 +- xen/include/asm-generic/altp2m.h | 5 +- xen/include/xen/altp2m.h | 98 ++++ xen/include/xen/p2m-common.h | 2 +- xen/include/xen/sched.h | 3 + 42 files changed, 1330 insertions(+), 818 deletions(-) create mode 100644 xen/arch/arm/altp2m.c create mode 100644 xen/arch/arm/include/asm/altp2m.h create mode 100644 xen/common/altp2m.c create mode 100644 xen/include/xen/altp2m.h -- 2.34.1
This commit adds an empty common altp2m.c and altp2m.h file to be added to in later commits. Creating a commit with just the empty file additions makes it easier to reorder later commits which add to these files. This commit can be squashed into the first commit which actually adds something to altp2m.c/altp2m.h for the actual submission if that would be preferred. This is commit 1/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/common/Makefile | 1 + xen/common/altp2m.c | 12 ++++++++++++ xen/include/xen/altp2m.h | 5 +++++ 3 files changed, 18 insertions(+) create mode 100644 xen/common/altp2m.c create mode 100644 xen/include/xen/altp2m.h diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ +obj-$(CONFIG_ALTP2M) += altp2m.o obj-$(CONFIG_ARGO) += argo.o obj-y += bitmap.o obj-bin-$(CONFIG_SELF_TESTS) += bitops.init.o diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <xen/altp2m.h> + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __XEN_ALTP2M_H__ +#define __XEN_ALTP2M_H__ + +#endif /* __XEN_ALTP2M_H__ */ -- 2.34.1
This commit moves altp2m_active from arch_domain on x86 to the common domain struct. Similarly to nr_altp2m, this is not an arch-specific value. Moving it to common code allows the common altp2m routines introduced later in this patch series to operate on altp2m_active without needing an altp2m_active member on arch_domain for each architecture supporting altp2m. This is commit 2/8 of the preparation phase. This commit is a refactor, and no change in functionality is intended. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/hvm/emulate.c | 1 + xen/arch/x86/hvm/hvm.c | 11 ++++++----- xen/arch/x86/hvm/monitor.c | 1 + xen/arch/x86/hvm/vmx/vmx.c | 1 + xen/arch/x86/include/asm/altp2m.h | 11 ----------- xen/arch/x86/include/asm/domain.h | 2 -- xen/arch/x86/mm/altp2m.c | 1 + xen/arch/x86/mm/hap/hap.c | 5 +++-- xen/arch/x86/mm/mem_access.c | 1 + xen/arch/x86/mm/mem_sharing.c | 1 + xen/arch/x86/mm/p2m-ept.c | 1 + xen/arch/x86/mm/p2m-pt.c | 1 + xen/arch/x86/mm/p2m.c | 1 + xen/common/monitor.c | 1 + xen/include/asm-generic/altp2m.h | 8 -------- xen/include/xen/altp2m.h | 19 +++++++++++++++++++ xen/include/xen/sched.h | 2 ++ 17 files changed, 40 insertions(+), 28 deletions(-) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -XXX,XX +XXX,XX @@ * Keir Fraser <keir@xen.org> */ +#include <xen/altp2m.h> #include <xen/init.h> #include <xen/iocap.h> #include <xen/ioreq.h> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2008, Citrix Systems, Inc. */ +#include <xen/altp2m.h> #include <xen/console.h> #include <xen/cpu.h> #include <xen/domain.h> @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( if ( (a.cmd != HVMOP_altp2m_get_domain_state) && (a.cmd != HVMOP_altp2m_set_domain_state) && - !d->arch.altp2m_active ) + !d->altp2m_active ) { rc = -EOPNOTSUPP; goto out; @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( if ( rc ) break; - ostate = d->arch.altp2m_active; - d->arch.altp2m_active = !!a.u.domain_state.state; + ostate = d->altp2m_active; + d->altp2m_active = !!a.u.domain_state.state; /* If the alternate p2m state has changed, handle appropriately */ - if ( d->arch.altp2m_active != ostate && + if ( d->altp2m_active != ostate && (ostate || !(rc = p2m_init_altp2m_by_id(d, 0))) ) { for_each_vcpu( d, v ) @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( p2m_flush_altp2m(d); } else if ( rc ) - d->arch.altp2m_active = false; + d->altp2m_active = false; domain_unpause_except_self(d); break; diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/monitor.c +++ b/xen/arch/x86/hvm/monitor.c @@ -XXX,XX +XXX,XX @@ * this program; If not, see <http://www.gnu.org/licenses/>. */ +#include <xen/altp2m.h> #include <xen/vm_event.h> #include <xen/mem_access.h> #include <xen/monitor.h> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2004, Intel Corporation. */ +#include <xen/altp2m.h> #include <xen/domain_page.h> #include <xen/guest_access.h> #include <xen/hypercall.h> diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_is_eptp_valid(const struct domain *d, mfn_x(INVALID_MFN); } -/* Alternate p2m HVM on/off per domain */ -static inline bool altp2m_active(const struct domain *d) -{ - return d->arch.altp2m_active; -} - static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) { return vcpu_altp2m(v).p2midx; @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_is_eptp_valid(const struct domain *d, return false; } -static inline bool altp2m_active(const struct domain *d) -{ - return false; -} - /* Only declaration is needed. DCE will optimise it out when linking. */ uint16_t altp2m_vcpu_idx(const struct vcpu *v); void altp2m_vcpu_initialise(struct vcpu *v); diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/domain.h +++ b/xen/arch/x86/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct arch_domain mm_lock_t nested_p2m_lock; #ifdef CONFIG_ALTP2M - /* altp2m: allow multiple copies of host p2m */ - bool altp2m_active; struct p2m_domain **altp2m_p2m; mm_lock_t altp2m_list_lock; uint64_t *altp2m_eptp; diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <asm/p2m.h> #include <asm/altp2m.h> #include <public/hvm/hvm_op.h> +#include <xen/altp2m.h> #include <xen/event.h> #include <xen/xvmalloc.h> #include "mm-locks.h" diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -XXX,XX +XXX,XX @@ * Parts of this code are Copyright (c) 2007 by XenSource Inc. */ +#include <xen/altp2m.h> #include <xen/types.h> #include <xen/mm.h> #include <xen/trace.h> @@ -XXX,XX +XXX,XX @@ int hap_enable(struct domain *d, u32 mode) goto out; } - d->arch.altp2m_active = false; + d->altp2m_active = false; } #endif /* CONFIG_ALTP2M */ @@ -XXX,XX +XXX,XX @@ void hap_teardown(struct domain *d, bool *preempted) for_each_vcpu ( d, v ) altp2m_vcpu_disable_ve(v); - d->arch.altp2m_active = false; + d->altp2m_active = false; FREE_XENHEAP_PAGE(d->arch.altp2m_eptp); FREE_XENHEAP_PAGE(d->arch.altp2m_visible_eptp); diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_access.c +++ b/xen/arch/x86/mm/mem_access.c @@ -XXX,XX +XXX,XX @@ * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al. */ +#include <xen/altp2m.h> #include <xen/guest_access.h> /* copy_from_guest() */ #include <xen/mem_access.h> #include <xen/nospec.h> diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) */ +#include <xen/altp2m.h> #include <xen/types.h> #include <xen/domain_page.h> #include <xen/event.h> diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2007, Intel Corporation. */ +#include <xen/altp2m.h> #include <xen/domain_page.h> #include <xen/sched.h> #include <public/hvm/dm_op.h> diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-pt.c +++ b/xen/arch/x86/mm/p2m-pt.c @@ -XXX,XX +XXX,XX @@ * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al. */ +#include <xen/altp2m.h> #include <xen/vm_event.h> #include <xen/event.h> #include <xen/trace.h> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -XXX,XX +XXX,XX @@ * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al. */ +#include <xen/altp2m.h> #include <xen/iommu.h> #include <xen/mem_access.h> #include <xen/vm_event.h> diff --git a/xen/common/monitor.c b/xen/common/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/monitor.c +++ b/xen/common/monitor.c @@ -XXX,XX +XXX,XX @@ * License along with this program; If not, see <http://www.gnu.org/licenses/>. */ +#include <xen/altp2m.h> #include <xen/event.h> #include <xen/monitor.h> #include <xen/sched.h> diff --git a/xen/include/asm-generic/altp2m.h b/xen/include/asm-generic/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/asm-generic/altp2m.h +++ b/xen/include/asm-generic/altp2m.h @@ -XXX,XX +XXX,XX @@ #include <xen/bug.h> -struct domain; struct vcpu; -/* Alternate p2m on/off per domain */ -static inline bool altp2m_active(const struct domain *d) -{ - /* Not implemented on GENERIC. */ - return false; -} - /* Alternate p2m VCPU */ static inline unsigned int altp2m_vcpu_idx(const struct vcpu *v) { diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ #ifndef __XEN_ALTP2M_H__ #define __XEN_ALTP2M_H__ +#include <xen/sched.h> + +#ifdef CONFIG_ALTP2M + +/* Alternate p2m HVM on/off per domain */ +static inline bool altp2m_active(const struct domain *d) +{ + return d->altp2m_active; +} + +#else /* CONFIG_ALTP2M */ + +static inline bool altp2m_active(const struct domain *d) +{ + return false; +} + +#endif /* CONFIG_ALTP2M */ + #endif /* __XEN_ALTP2M_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ struct domain } monitor; #ifdef CONFIG_ALTP2M + /* altp2m: allow multiple copies of host p2m */ + bool altp2m_active; unsigned int nr_altp2m; /* Number of altp2m tables. */ #endif -- 2.34.1
Similarly to the previous commit, this commit moves altp2m_p2m to the common domain struct. The representation of altp2m views as an array of p2m_domain pointers is the same on x86 and ARM, and it seems that this would be the case for other architectures as well. This commit is a refactor, and no change in functionality is intended. This is commit 3/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/hvm/vmx/vmx.c | 2 +- xen/arch/x86/include/asm/domain.h | 1 - xen/arch/x86/include/asm/p2m.h | 4 ++-- xen/arch/x86/mm/altp2m.c | 28 ++++++++++++++-------------- xen/arch/x86/mm/hap/hap.c | 6 +++--- xen/arch/x86/mm/mem_access.c | 8 ++++---- xen/arch/x86/mm/mem_sharing.c | 2 +- xen/arch/x86/mm/p2m-ept.c | 6 +++--- xen/arch/x86/mm/p2m.c | 8 ++++---- xen/include/xen/sched.h | 1 + 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -XXX,XX +XXX,XX @@ bool asmlinkage vmx_vmenter_helper(const struct cpu_user_regs *regs) if ( currd->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - ept = &currd->arch.altp2m_p2m[i]->ept; + ept = &currd->altp2m_p2m[i]->ept; if ( cpumask_test_cpu(cpu, ept->invalidate) ) { cpumask_clear_cpu(cpu, ept->invalidate); diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/domain.h +++ b/xen/arch/x86/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct arch_domain mm_lock_t nested_p2m_lock; #ifdef CONFIG_ALTP2M - struct p2m_domain **altp2m_p2m; mm_lock_t altp2m_list_lock; uint64_t *altp2m_eptp; uint64_t *altp2m_visible_eptp; diff --git a/xen/arch/x86/include/asm/p2m.h b/xen/arch/x86/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/p2m.h +++ b/xen/arch/x86/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ static inline struct p2m_domain *p2m_get_altp2m(struct vcpu *v) BUG_ON(index >= v->domain->nr_altp2m); - return v->domain->arch.altp2m_p2m[index]; + return v->domain->altp2m_p2m[index]; } /* set current alternate p2m table */ @@ -XXX,XX +XXX,XX @@ static inline bool p2m_set_altp2m(struct vcpu *v, unsigned int idx) atomic_dec(&orig->active_vcpus); vcpu_altp2m(v).p2midx = idx; - atomic_inc(&v->domain->arch.altp2m_p2m[idx]->active_vcpus); + atomic_inc(&v->domain->altp2m_p2m[idx]->active_vcpus); return true; } diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ int p2m_init_altp2m(struct domain *d) struct p2m_domain *hostp2m = p2m_get_hostp2m(d); mm_lock_init(&d->arch.altp2m_list_lock); - d->arch.altp2m_p2m = xvzalloc_array(struct p2m_domain *, d->nr_altp2m); + d->altp2m_p2m = xvzalloc_array(struct p2m_domain *, d->nr_altp2m); - if ( !d->arch.altp2m_p2m ) + if ( !d->altp2m_p2m ) return -ENOMEM; for ( i = 0; i < d->nr_altp2m; i++ ) { - d->arch.altp2m_p2m[i] = p2m = p2m_init_one(d); + d->altp2m_p2m[i] = p2m = p2m_init_one(d); if ( p2m == NULL ) { p2m_teardown_altp2m(d); @@ -XXX,XX +XXX,XX @@ void p2m_teardown_altp2m(struct domain *d) for ( i = 0; i < d->nr_altp2m; i++ ) { - if ( !d->arch.altp2m_p2m[i] ) + if ( !d->altp2m_p2m[i] ) continue; - p2m = d->arch.altp2m_p2m[i]; - d->arch.altp2m_p2m[i] = NULL; + p2m = d->altp2m_p2m[i]; + d->altp2m_p2m[i] = NULL; p2m_free_one(p2m); } - XVFREE(d->arch.altp2m_p2m); + XVFREE(d->altp2m_p2m); } int altp2m_get_effective_entry(struct p2m_domain *ap2m, gfn_t gfn, mfn_t *mfn, @@ -XXX,XX +XXX,XX @@ static void p2m_reset_altp2m(struct domain *d, unsigned int idx, struct p2m_domain *p2m; ASSERT(idx < d->nr_altp2m); - p2m = d->arch.altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + p2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; p2m_lock(p2m); @@ -XXX,XX +XXX,XX @@ static int p2m_activate_altp2m(struct domain *d, unsigned int idx, ASSERT(idx < d->nr_altp2m); - p2m = d->arch.altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + p2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; hostp2m = p2m_get_hostp2m(d); p2m_lock(p2m); @@ -XXX,XX +XXX,XX @@ int p2m_destroy_altp2m_by_id(struct domain *d, unsigned int idx) if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] != mfn_x(INVALID_MFN) ) { - p2m = d->arch.altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + p2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; if ( !_atomic_read(p2m->active_vcpus) ) { @@ -XXX,XX +XXX,XX @@ int p2m_change_altp2m_gfn(struct domain *d, unsigned int idx, return rc; hp2m = p2m_get_hostp2m(d); - ap2m = d->arch.altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + ap2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; p2m_lock(hp2m); p2m_lock(ap2m); @@ -XXX,XX +XXX,XX @@ int p2m_altp2m_propagate_change(struct domain *d, gfn_t gfn, if ( d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - p2m = d->arch.altp2m_p2m[i]; + p2m = d->altp2m_p2m[i]; /* Check for a dropped page that may impact this altp2m */ if ( mfn_eq(mfn, INVALID_MFN) && @@ -XXX,XX +XXX,XX @@ int p2m_set_suppress_ve_multi(struct domain *d, return -EINVAL; p2m = ap2m = - d->arch.altp2m_p2m[array_index_nospec(sve->view, d->nr_altp2m)]; + d->altp2m_p2m[array_index_nospec(sve->view, d->nr_altp2m)]; } p2m_lock(host_p2m); @@ -XXX,XX +XXX,XX @@ int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, return -EINVAL; p2m = ap2m = - d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; + d->altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; } else p2m = host_p2m; diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -XXX,XX +XXX,XX @@ int hap_enable(struct domain *d, u32 mode) for ( i = 0; i < d->nr_altp2m; i++ ) { - rv = p2m_alloc_table(d->arch.altp2m_p2m[i]); + rv = p2m_alloc_table(d->altp2m_p2m[i]); if ( rv != 0 ) goto out; } @@ -XXX,XX +XXX,XX @@ void hap_final_teardown(struct domain *d) #ifdef CONFIG_ALTP2M if ( hvm_altp2m_supported() ) for ( i = 0; i < d->nr_altp2m; i++ ) - p2m_teardown(d->arch.altp2m_p2m[i], true, NULL); + p2m_teardown(d->altp2m_p2m[i], true, NULL); #endif /* Destroy nestedp2m's first */ @@ -XXX,XX +XXX,XX @@ void hap_teardown(struct domain *d, bool *preempted) for ( i = 0; i < d->nr_altp2m; i++ ) { - p2m_teardown(d->arch.altp2m_p2m[i], false, preempted); + p2m_teardown(d->altp2m_p2m[i], false, preempted); if ( preempted && *preempted ) return; } diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_access.c +++ b/xen/arch/x86/mm/mem_access.c @@ -XXX,XX +XXX,XX @@ long p2m_set_mem_access(struct domain *d, gfn_t gfn, uint32_t nr, if ( !altp2m_is_eptp_valid(d, altp2m_idx) ) return -EINVAL; - ap2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; + ap2m = d->altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; } #endif @@ -XXX,XX +XXX,XX @@ long p2m_set_mem_access_multi(struct domain *d, if ( !altp2m_is_eptp_valid(d, altp2m_idx) ) return -EINVAL; - ap2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; + ap2m = d->altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; } #endif @@ -XXX,XX +XXX,XX @@ int p2m_get_mem_access(struct domain *d, gfn_t gfn, xenmem_access_t *access, if ( !altp2m_is_eptp_valid(d, altp2m_idx) ) return -EINVAL; - p2m = d->arch.altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; + p2m = d->altp2m_p2m[array_index_nospec(altp2m_idx, d->nr_altp2m)]; } #endif @@ -XXX,XX +XXX,XX @@ void arch_p2m_set_access_required(struct domain *d, bool access_required) unsigned int i; for ( i = 0; i < d->nr_altp2m; i++ ) { - struct p2m_domain *p2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *p2m = d->altp2m_p2m[i]; if ( p2m ) p2m->access_required = access_required; diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -XXX,XX +XXX,XX @@ static int nominate_page(struct domain *d, gfn_t gfn, for ( i = 0; i < d->nr_altp2m; i++ ) { - ap2m = d->arch.altp2m_p2m[i]; + ap2m = d->altp2m_p2m[i]; if ( !ap2m ) continue; diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -XXX,XX +XXX,XX @@ static void ept_set_ad_sync(struct domain *d, bool value) if ( d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - p2m = d->arch.altp2m_p2m[i]; + p2m = d->altp2m_p2m[i]; p2m_lock(p2m); p2m->ept.ad = value; @@ -XXX,XX +XXX,XX @@ void __init setup_ept_dump(void) void p2m_init_altp2m_ept(struct domain *d, unsigned int i) { struct p2m_domain *p2m = - d->arch.altp2m_p2m[array_index_nospec(i, d->nr_altp2m)]; + d->altp2m_p2m[array_index_nospec(i, d->nr_altp2m)]; struct p2m_domain *hostp2m = p2m_get_hostp2m(d); struct ept_data *ept; @@ -XXX,XX +XXX,XX @@ unsigned int p2m_find_altp2m_by_eptp(struct domain *d, uint64_t eptp) if ( d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - p2m = d->arch.altp2m_p2m[i]; + p2m = d->altp2m_p2m[i]; ept = &p2m->ept; if ( eptp == ept->eptp ) diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_change_entry_type_global(struct domain *d, { if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) { - struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *altp2m = d->altp2m_p2m[i]; p2m_lock(altp2m); change_entry_type_global(altp2m, ot, nt); @@ -XXX,XX +XXX,XX @@ bool p2m_memory_type_changed(struct domain *d) { if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) { - struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *altp2m = d->altp2m_p2m[i]; p2m_lock(altp2m); _memory_type_changed(altp2m); @@ -XXX,XX +XXX,XX @@ void p2m_change_type_range(struct domain *d, { if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) { - struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *altp2m = d->altp2m_p2m[i]; p2m_lock(altp2m); change_type_range(altp2m, start, end, ot, nt); @@ -XXX,XX +XXX,XX @@ int p2m_finish_type_change(struct domain *d, { if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) { - struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *altp2m = d->altp2m_p2m[i]; p2m_lock(altp2m); rc = finish_type_change(altp2m, first_gfn, max_nr); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -XXX,XX +XXX,XX @@ struct domain /* altp2m: allow multiple copies of host p2m */ bool altp2m_active; unsigned int nr_altp2m; /* Number of altp2m tables. */ + struct p2m_domain **altp2m_p2m; #endif #ifdef CONFIG_VMTRACE -- 2.34.1
Using a generic name for altp2m_supported makes it possible to indicate whether altp2m is supported on other architectures as well. Even if other architectures always support altp2m at a hardware level (like ARM), altp2m might not be supported due to CONFIG_ALTP2M being disabled. Therefore, the altp2m_supported function can be implemented on all architectures to indicate if the hardware supports altp2m *and* if CONFIG_ALTP2M is enabled. This is commit 4/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/domain.c | 2 +- xen/arch/x86/hvm/hvm.c | 6 +++--- xen/arch/x86/include/asm/hvm/hvm.h | 4 ++-- xen/arch/x86/mm/hap/hap.c | 6 +++--- xen/arch/x86/mm/p2m-basic.c | 4 ++-- xen/arch/x86/mm/p2m-ept.c | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -XXX,XX +XXX,XX @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config) if ( altp2m_mode ) { - if ( !hvm_altp2m_supported() ) + if ( !altp2m_supported() ) { dprintk(XENLOG_INFO, "altp2m is not supported\n"); return -EINVAL; diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ void hvm_vcpu_destroy(struct vcpu *v) ioreq_server_remove_vcpu_all(v->domain, v); - if ( hvm_altp2m_supported() ) + if ( altp2m_supported() ) altp2m_vcpu_destroy(v); nestedhvm_vcpu_destroy(v); @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( int rc = 0; uint64_t mode; - if ( !hvm_altp2m_supported() ) + if ( !altp2m_supported() ) return -EOPNOTSUPP; if ( copy_from_guest(&a, arg, 1) ) @@ -XXX,XX +XXX,XX @@ static int compat_altp2m_op( struct xen_hvm_altp2m_op *altp2m_op; } nat; - if ( !hvm_altp2m_supported() ) + if ( !altp2m_supported() ) return -EOPNOTSUPP; if ( copy_from_guest(&a, arg, 1) ) diff --git a/xen/arch/x86/include/asm/hvm/hvm.h b/xen/arch/x86/include/asm/hvm/hvm.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/hvm/hvm.h +++ b/xen/arch/x86/include/asm/hvm/hvm.h @@ -XXX,XX +XXX,XX @@ static inline bool hvm_hap_supported(void) } /* returns true if hardware supports alternate p2m's */ -static inline bool hvm_altp2m_supported(void) +static inline bool altp2m_supported(void) { return IS_ENABLED(CONFIG_ALTP2M) && hvm_funcs.caps.altp2m; } @@ -XXX,XX +XXX,XX @@ static inline bool hvm_hap_supported(void) return false; } -static inline bool hvm_altp2m_supported(void) +static inline bool altp2m_supported(void) { return false; } diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -XXX,XX +XXX,XX @@ int hap_enable(struct domain *d, u32 mode) } #ifdef CONFIG_ALTP2M - if ( hvm_altp2m_supported() ) + if ( altp2m_supported() ) { /* Init alternate p2m data */ if ( (d->arch.altp2m_eptp = alloc_xenheap_page()) == NULL ) @@ -XXX,XX +XXX,XX @@ void hap_final_teardown(struct domain *d) unsigned int i; #ifdef CONFIG_ALTP2M - if ( hvm_altp2m_supported() ) + if ( altp2m_supported() ) for ( i = 0; i < d->nr_altp2m; i++ ) p2m_teardown(d->altp2m_p2m[i], true, NULL); #endif @@ -XXX,XX +XXX,XX @@ void hap_teardown(struct domain *d, bool *preempted) #ifdef CONFIG_ALTP2M /* Leave the root pt in case we get further attempts to modify the p2m. */ - if ( hvm_altp2m_supported() ) + if ( altp2m_supported() ) { if ( altp2m_active(d) ) for_each_vcpu ( d, v ) diff --git a/xen/arch/x86/mm/p2m-basic.c b/xen/arch/x86/mm/p2m-basic.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-basic.c +++ b/xen/arch/x86/mm/p2m-basic.c @@ -XXX,XX +XXX,XX @@ int p2m_init(struct domain *d) return rc; } - rc = hvm_altp2m_supported() ? p2m_init_altp2m(d) : 0; + rc = altp2m_supported() ? p2m_init_altp2m(d) : 0; if ( rc ) { p2m_teardown_hostp2m(d); @@ -XXX,XX +XXX,XX @@ void p2m_final_teardown(struct domain *d) { if ( is_hvm_domain(d) ) { - if ( hvm_altp2m_supported() ) + if ( altp2m_supported() ) p2m_teardown_altp2m(d); /* * We must tear down nestedp2m unconditionally because diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -XXX,XX +XXX,XX @@ out: if ( is_epte_present(&old_entry) ) ept_free_entry(p2m, &old_entry, target); - if ( hvm_altp2m_supported() && entry_written && p2m_is_hostp2m(p2m) ) + if ( altp2m_supported() && entry_written && p2m_is_hostp2m(p2m) ) { ret = p2m_altp2m_propagate_change(d, _gfn(gfn), mfn, order, p2mt, p2ma); if ( !rc ) -- 2.34.1
Following from the previous commit, this commit makes altp2m_supported available through the asm/altp2m.h header. This is commit 5/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/domain.c | 1 + xen/arch/x86/include/asm/altp2m.h | 11 +++++++++++ xen/arch/x86/include/asm/hvm/hvm.h | 11 ----------- xen/include/asm-generic/altp2m.h | 7 +++++++ 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -XXX,XX +XXX,XX @@ #include <xen/softirq.h> #include <xen/wait.h> +#include <asm/altp2m.h> #include <asm/amd.h> #include <asm/cpu-policy.h> #include <asm/cpuidle.h> diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_is_eptp_valid(const struct domain *d, mfn_x(INVALID_MFN); } +/* returns true if hardware supports alternate p2m's */ +static inline bool altp2m_supported(void) +{ + return hvm_funcs.caps.altp2m; +} + static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) { return vcpu_altp2m(v).p2midx; @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_is_eptp_valid(const struct domain *d, return false; } +static inline bool altp2m_supported(void) +{ + return false; +} + /* Only declaration is needed. DCE will optimise it out when linking. */ uint16_t altp2m_vcpu_idx(const struct vcpu *v); void altp2m_vcpu_initialise(struct vcpu *v); diff --git a/xen/arch/x86/include/asm/hvm/hvm.h b/xen/arch/x86/include/asm/hvm/hvm.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/hvm/hvm.h +++ b/xen/arch/x86/include/asm/hvm/hvm.h @@ -XXX,XX +XXX,XX @@ static inline bool hvm_hap_supported(void) return hvm_funcs.caps.hap; } -/* returns true if hardware supports alternate p2m's */ -static inline bool altp2m_supported(void) -{ - return IS_ENABLED(CONFIG_ALTP2M) && hvm_funcs.caps.altp2m; -} - /* Returns true if we have the minimum hardware requirements for nested virt */ static inline bool hvm_nested_virt_supported(void) { @@ -XXX,XX +XXX,XX @@ static inline bool hvm_hap_supported(void) return false; } -static inline bool altp2m_supported(void) -{ - return false; -} - static inline bool hvm_nested_virt_supported(void) { return false; diff --git a/xen/include/asm-generic/altp2m.h b/xen/include/asm-generic/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/asm-generic/altp2m.h +++ b/xen/include/asm-generic/altp2m.h @@ -XXX,XX +XXX,XX @@ struct vcpu; +/* returns true if hardware supports alternate p2m's */ +static inline bool altp2m_supported(void) +{ + /* Not implemented on GENERIC. */ + return false; +} + /* Alternate p2m VCPU */ static inline unsigned int altp2m_vcpu_idx(const struct vcpu *v) { -- 2.34.1
Similarly to the earlier common altp2m.c/altp2m.h commit, this commit adds a template altp2m.c and altp2m.h file for ARM to be added to in later commits. Creating a commit with just the template file additions makes it easier to reorder later commits which add to these files. This commit can be squashed into the first commit which actually adds something to altp2m.c/altp2m.h for the actual submission if that would be preferred. This is commit 6/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Aqib Javaid <Aqib.Javaid@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/arm/Makefile | 1 + xen/arch/arm/altp2m.c | 16 +++++++++++++ xen/arch/arm/include/asm/Makefile | 1 - xen/arch/arm/include/asm/altp2m.h | 37 +++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 xen/arch/arm/altp2m.c create mode 100644 xen/arch/arm/include/asm/altp2m.h diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_TEE) += tee/ obj-$(CONFIG_HAS_VPCI) += vpci.o obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o +obj-$(CONFIG_ALTP2M) += altp2m.o obj-y += cpuerrata.o obj-y += cpufeature.o obj-y += decode.o diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/arm/altp2m.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * altp2m.c: Alternate p2m + * + * Copyright (c) 2016 Sergej Proskurin <proskurin@sec.in.tum.de> + */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/include/asm/Makefile b/xen/arch/arm/include/asm/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/Makefile +++ b/xen/arch/arm/include/asm/Makefile @@ -XXX,XX +XXX,XX @@ # SPDX-License-Identifier: GPL-2.0-only -generic-y += altp2m.h generic-y += device.h generic-y += hardirq.h generic-y += iocap.h diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * altp2m.h: Alternate p2m + * + * Copyright (c) 2014, Intel Corporation. + * Copyright (c) 2016, Sergej Proskurin <proskurin@sec.in.tum.de>. + */ + +#ifndef __ASM_ARM_ALTP2M_H +#define __ASM_ARM_ALTP2M_H + +#include <xen/sched.h> + +static inline bool altp2m_supported(void) +{ + /* Not implemented yet */ + return false; +} + +/* Alternate p2m VCPU */ +static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) +{ + /* Not implemented yet */ + BUG(); + return 0; +} + +#endif /* __ASM_ARM_ALTP2M_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- 2.34.1
Following the x86 implementation in commit e96831ece819, this commit adds the CONFIG_ALTP2M Kconfig option for ARM. This makes it possible to build Xen without building altp2m code. This commit also implements a stub for p2m_altp2m_check, as some implementation is needed when CONFIG_ALTP2M is enabled. This is due to a call to p2m_altp2m_check in vm_event.c which is gated by CONFIG_ALTP2M. This is commit 7/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Aqib Javaid <Aqib.Javaid@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/arm/Kconfig | 11 +++++++++++ xen/arch/arm/altp2m.c | 9 +++++++++ xen/arch/arm/include/asm/altp2m.h | 18 ++++++++++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config MPU systems supporting EL2. (UNSUPPORTED) endchoice +config ALTP2M + bool "Alternate P2M support" if EXPERT + depends on MMU + default y + help + Alternate-p2m allows a guest to manage multiple p2m guest physical + "memory views" (as opposed to a single p2m). + Useful for memory introspection. + + If unsure, stay with defaults. + source "arch/Kconfig" config ACPI diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/altp2m.c +++ b/xen/arch/arm/altp2m.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2016 Sergej Proskurin <proskurin@sec.in.tum.de> */ +#include <asm/p2m.h> + +/* Check to see if vcpu should be switched to a different p2m. */ +void p2m_altp2m_check(struct vcpu *v, uint16_t idx) +{ + /* Not yet implemented */ + BUG(); +} + /* * Local variables: * mode: C diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ #include <xen/sched.h> +#ifdef CONFIG_ALTP2M + +/* Hardware always supports altp2m on ARM */ static inline bool altp2m_supported(void) { - /* Not implemented yet */ - return false; + return true; } /* Alternate p2m VCPU */ @@ -XXX,XX +XXX,XX @@ static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) return 0; } +#else /* CONFIG_ALTP2M */ + +static inline bool altp2m_supported(void) +{ + return false; +} + +/* Only declaration is needed. DCE will optimise it out when linking. */ +uint16_t altp2m_vcpu_idx(const struct vcpu *v); + +#endif /* CONFIG_ALTP2M */ + #endif /* __ASM_ARM_ALTP2M_H */ /* -- 2.34.1
This commit renames altp2m functions with a p2m prefix. These functions were originally defined in p2m.c, hence the p2m prefix. When they were moved to altp2m.c in commit ae7584f63678, the function names were kept and the declarations remained in p2m.h. This commit finishes that move by renaming these functions to have an altp2m prefix and moving the declarations to altp2m.h. Since these functions will either be moved to the common altp2m.c, or implemented separately for ARM, it doesn't seem to make sense to continue with this naming convention. Therefore, this commit preemptively renames the x86 implementations of these functions so they can later be implemented with altp2m function name prefixes in common code or for ARM. For convenience, here is the full list of renames: - p2m_init_altp2m -> altp2m_init - p2m_teardown_altp2m -> altp2m_teardown - p2m_flush_altp2m -> altp2m_flush - p2m_altp2m_get_or_propagate -> altp2m_get_or_propagate - p2m_altp2m_propagate_change -> altp2m_propagate_change - p2m_get_altp2m -> altp2m_get_altp2m - p2m_set_altp2m -> altp2m_set_altp2m - p2m_reset_altp2m -> altp2m_reset_altp2m - p2m_activate_altp2m -> altp2m_activate_altp2m - p2m_init_altp2m_by_id -> altp2m_init_by_id - p2m_init_next_altp2m -> altp2m_init_next_available - p2m_destroy_altp2m_by_id -> altp2m_destroy_by_id - p2m_switch_domain_altp2m_by_id -> altp2m_switch_domain_altp2m_by_id - p2m_change_altp2m_gfn -> altp2m_change_gfn - p2m_set_altp2m_view_visibility -> altp2m_set_view_visibility This commit contains only function renames and code movement, and no functional change is intended. This is commit 8/8 of the preparation phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/arm/altp2m.c | 2 +- xen/arch/x86/hvm/hvm.c | 30 ++++---- xen/arch/x86/hvm/monitor.c | 2 +- xen/arch/x86/hvm/vmx/vmx.c | 6 +- xen/arch/x86/include/asm/altp2m.h | 116 +++++++++++++++++++++++++++++- xen/arch/x86/include/asm/p2m.h | 109 ---------------------------- xen/arch/x86/mm/altp2m.c | 76 ++++++++++---------- xen/arch/x86/mm/mem_access.c | 13 ++-- xen/arch/x86/mm/p2m-basic.c | 4 +- xen/arch/x86/mm/p2m-ept.c | 4 +- xen/arch/x86/mm/p2m.h | 3 - xen/common/vm_event.c | 2 +- xen/include/xen/p2m-common.h | 2 +- 13 files changed, 186 insertions(+), 183 deletions(-) diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/altp2m.c +++ b/xen/arch/arm/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <asm/p2m.h> /* Check to see if vcpu should be switched to a different p2m. */ -void p2m_altp2m_check(struct vcpu *v, uint16_t idx) +void altp2m_check(struct vcpu *v, uint16_t idx) { /* Not yet implemented */ BUG(); diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, if ( altp2m_active(currd) ) { - p2m = p2m_get_altp2m(curr); + p2m = altp2m_get_altp2m(curr); /* * Get the altp2m entry if present; or if not, propagate from * the host p2m. NB that this returns with gfn locked in the * altp2m. */ - if ( p2m_altp2m_get_or_propagate(p2m, gfn, &mfn, &p2mt, - &p2ma, &page_order) ) + if ( altp2m_get_or_propagate(p2m, gfn, &mfn, &p2mt, &p2ma, + &page_order) ) { /* Entry was copied from host -- retry fault */ rc = 1; @@ -XXX,XX +XXX,XX @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, paging_mark_pfn_dirty(currd, _pfn(gfn)); /* * If p2m is really an altp2m, unlock it before changing the type, - * as p2m_altp2m_propagate_change() needs to acquire the + * as altp2m_propagate_change() needs to acquire the * altp2m_list lock. */ if ( p2m != hostp2m ) @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( /* If the alternate p2m state has changed, handle appropriately */ if ( d->altp2m_active != ostate && - (ostate || !(rc = p2m_init_altp2m_by_id(d, 0))) ) + (ostate || !(rc = altp2m_init_by_id(d, 0))) ) { for_each_vcpu( d, v ) { @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( } if ( ostate ) - p2m_flush_altp2m(d); + altp2m_flush(d); } else if ( rc ) d->altp2m_active = false; @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( } case HVMOP_altp2m_create_p2m: - if ( !(rc = p2m_init_next_altp2m(d, &a.u.view.view, - a.u.view.hvmmem_default_access)) ) + rc = altp2m_init_next_available(d, &a.u.view.view, + a.u.view.hvmmem_default_access); + if ( !rc ) rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; break; case HVMOP_altp2m_destroy_p2m: - rc = p2m_destroy_altp2m_by_id(d, a.u.view.view); + rc = altp2m_destroy_by_id(d, a.u.view.view); break; case HVMOP_altp2m_switch_p2m: - rc = p2m_switch_domain_altp2m_by_id(d, a.u.view.view); + rc = altp2m_switch_domain_altp2m_by_id(d, a.u.view.view); break; case HVMOP_altp2m_set_suppress_ve: @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( if ( a.u.change_gfn.pad1 || a.u.change_gfn.pad2 ) rc = -EINVAL; else - rc = p2m_change_altp2m_gfn(d, a.u.change_gfn.view, - _gfn(a.u.change_gfn.old_gfn), - _gfn(a.u.change_gfn.new_gfn)); + rc = altp2m_change_gfn(d, a.u.change_gfn.view, + _gfn(a.u.change_gfn.old_gfn), + _gfn(a.u.change_gfn.new_gfn)); break; case HVMOP_altp2m_get_p2m_idx: @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( else if ( !altp2m_active(d) ) rc = -EOPNOTSUPP; else - rc = p2m_set_altp2m_view_visibility(d, idx, - a.u.set_visibility.visible); + rc = altp2m_set_view_visibility(d, idx, a.u.set_visibility.visible); break; } diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/monitor.c +++ b/xen/arch/x86/hvm/monitor.c @@ -XXX,XX +XXX,XX @@ int hvm_monitor_debug(unsigned long rip, enum hvm_monitor_debug_type type, #ifdef CONFIG_ALTP2M if ( curr->arch.hvm.fast_single_step.enabled ) { - p2m_altp2m_check(curr, curr->arch.hvm.fast_single_step.p2midx); + altp2m_check(curr, curr->arch.hvm.fast_single_step.p2midx); curr->arch.hvm.single_step = false; curr->arch.hvm.fast_single_step.enabled = false; curr->arch.hvm.fast_single_step.p2midx = 0; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_vcpu_update_eptp(struct vcpu *v) struct ept_data *ept; if ( altp2m_active(d) ) - p2m = p2m_get_altp2m(v); + p2m = altp2m_get_altp2m(v); if ( !p2m ) p2m = p2m_get_hostp2m(d); @@ -XXX,XX +XXX,XX @@ static int cf_check vmx_vcpu_emulate_vmfunc(const struct cpu_user_regs *regs) if ( !cpu_has_vmx_vmfunc && altp2m_active(curr->domain) && regs->eax == 0 && - p2m_switch_vcpu_altp2m_by_id(curr, regs->ecx) ) + altp2m_switch_vcpu_by_id(curr, regs->ecx) ) rc = X86EMUL_OKAY; return rc; @@ -XXX,XX +XXX,XX @@ void asmlinkage vmx_vmexit_handler(struct cpu_user_regs *regs) } } - p2m_set_altp2m(v, idx); + altp2m_set_altp2m(v, idx); } if ( vm_event_is_enabled(v) && diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ #ifndef __ASM_X86_ALTP2M_H #define __ASM_X86_ALTP2M_H -#ifdef CONFIG_ALTP2M #include <xen/types.h> #include <xen/sched.h> /* for struct vcpu, struct domain */ + +#include <asm/p2m.h> #include <asm/hvm/vcpu.h> /* for vcpu_altp2m */ +/* + * Common alternate p2m declarations that need to be visible + * regardless of CONFIG_ALTP2M + */ + +/* Alternate p2m paging */ +bool altp2m_get_or_propagate(struct p2m_domain *ap2m, unsigned long gfn_l, + mfn_t *mfn, p2m_type_t *p2mt, p2m_access_t *p2ma, + unsigned int *page_order); + +/* Propagate a host p2m change to all alternate p2m's */ +int altp2m_propagate_change(struct domain *d, gfn_t gfn, mfn_t mfn, + unsigned int page_order, p2m_type_t p2mt, + p2m_access_t p2ma); + +#ifdef CONFIG_ALTP2M + +#define AP2MGET_prepopulate true +#define AP2MGET_query false + static inline bool altp2m_is_eptp_valid(const struct domain *d, unsigned int idx) { @@ -XXX,XX +XXX,XX @@ static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) return vcpu_altp2m(v).p2midx; } +/* + * Alternate p2m: shadow p2m tables used for alternate memory views + */ + +/* get current alternate p2m table */ +static inline struct p2m_domain *altp2m_get_altp2m(struct vcpu *v) +{ + unsigned int index = vcpu_altp2m(v).p2midx; + + if ( index == INVALID_ALTP2M ) + return NULL; + + BUG_ON(index >= v->domain->nr_altp2m); + + return v->domain->altp2m_p2m[index]; +} + +/* set current alternate p2m table */ +static inline bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx) +{ + struct p2m_domain *orig; + + BUG_ON(idx >= v->domain->nr_altp2m); + + if ( idx == vcpu_altp2m(v).p2midx ) + return false; + + orig = altp2m_get_altp2m(v); + BUG_ON(!orig); + atomic_dec(&orig->active_vcpus); + + vcpu_altp2m(v).p2midx = idx; + atomic_inc(&v->domain->altp2m_p2m[idx]->active_vcpus); + + return true; +} + +/* Initialize altp2m views */ +int altp2m_init(struct domain *d); + +/* Free altp2m views */ +void altp2m_teardown(struct domain *d); + +/* Switch alternate p2m for a single vcpu */ +bool altp2m_switch_vcpu_by_id(struct vcpu *v, unsigned int idx); + +/* Flush all the alternate p2m's for a domain */ +void altp2m_flush(struct domain *d); + +/* Make a specific alternate p2m valid */ +int altp2m_init_by_id(struct domain *d, unsigned int idx); + +/* Find an available alternate p2m and make it valid */ +int altp2m_init_next_available(struct domain *d, uint16_t *idx, + xenmem_access_t hvmmem_default_access); + +/* Make a specific alternate p2m invalid */ +int altp2m_destroy_by_id(struct domain *d, unsigned int idx); + +/* Switch alternate p2m for entire domain */ +int altp2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx); + +/* Change a gfn->mfn mapping */ +int altp2m_change_gfn(struct domain *d, unsigned int idx, gfn_t old_gfn, + gfn_t new_gfn); + +/* Set a specific p2m view visibility */ +int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, + uint8_t visible); + +/* + * Looks up altp2m entry. If the entry is not found it looks up the entry in + * hostp2m. + * The prepopulate param is used to set the found entry in altp2m. + */ +int altp2m_get_effective_entry(struct p2m_domain *ap2m, gfn_t gfn, mfn_t *mfn, + p2m_type_t *t, p2m_access_t *a, + bool prepopulate); + /* Alternate p2m VCPU */ void altp2m_vcpu_initialise(struct vcpu *v); void altp2m_vcpu_destroy(struct vcpu *v); @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_supported(void) return false; } +static inline int _altp2m_get_effective_entry(struct p2m_domain *ap2m, + gfn_t gfn, mfn_t *mfn, + p2m_type_t *t, p2m_access_t *a) +{ + ASSERT_UNREACHABLE(); + return -EOPNOTSUPP; +} +#define altp2m_get_effective_entry(ap2m, gfn, mfn, t, a, prepopulate) \ + _altp2m_get_effective_entry(ap2m, gfn, mfn, t, a) + /* Only declaration is needed. DCE will optimise it out when linking. */ +int altp2m_init(struct domain *d); +void altp2m_teardown(struct domain *d); +struct p2m_domain *altp2m_get_altp2m(struct vcpu *v); +bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx); uint16_t altp2m_vcpu_idx(const struct vcpu *v); void altp2m_vcpu_initialise(struct vcpu *v); void altp2m_vcpu_destroy(struct vcpu *v); diff --git a/xen/arch/x86/include/asm/p2m.h b/xen/arch/x86/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/p2m.h +++ b/xen/arch/x86/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ static inline gfn_t mfn_to_gfn(const struct domain *d, mfn_t mfn) return _gfn(mfn_x(mfn)); } -#ifdef CONFIG_ALTP2M -#define AP2MGET_prepopulate true -#define AP2MGET_query false - -/* - * Looks up altp2m entry. If the entry is not found it looks up the entry in - * hostp2m. - * The prepopulate param is used to set the found entry in altp2m. - */ -int altp2m_get_effective_entry(struct p2m_domain *ap2m, gfn_t gfn, mfn_t *mfn, - p2m_type_t *t, p2m_access_t *a, - bool prepopulate); -#else -static inline int _altp2m_get_effective_entry(struct p2m_domain *ap2m, - gfn_t gfn, mfn_t *mfn, - p2m_type_t *t, p2m_access_t *a) -{ - ASSERT_UNREACHABLE(); - return -EOPNOTSUPP; -} -#define altp2m_get_effective_entry(ap2m, gfn, mfn, t, a, prepopulate) \ - _altp2m_get_effective_entry(ap2m, gfn, mfn, t, a) -#endif - /* Init the datastructures for later use by the p2m code */ int p2m_init(struct domain *d); @@ -XXX,XX +XXX,XX @@ void shadow_p2m_init(struct p2m_domain *p2m); void cf_check nestedp2m_write_p2m_entry_post( struct p2m_domain *p2m, unsigned int oflags); -#ifdef CONFIG_ALTP2M - -/* - * Alternate p2m: shadow p2m tables used for alternate memory views - */ - -/* get current alternate p2m table */ -static inline struct p2m_domain *p2m_get_altp2m(struct vcpu *v) -{ - unsigned int index = vcpu_altp2m(v).p2midx; - - if ( index == INVALID_ALTP2M ) - return NULL; - - BUG_ON(index >= v->domain->nr_altp2m); - - return v->domain->altp2m_p2m[index]; -} - -/* set current alternate p2m table */ -static inline bool p2m_set_altp2m(struct vcpu *v, unsigned int idx) -{ - struct p2m_domain *orig; - - BUG_ON(idx >= v->domain->nr_altp2m); - - if ( idx == vcpu_altp2m(v).p2midx ) - return false; - - orig = p2m_get_altp2m(v); - BUG_ON(!orig); - atomic_dec(&orig->active_vcpus); - - vcpu_altp2m(v).p2midx = idx; - atomic_inc(&v->domain->altp2m_p2m[idx]->active_vcpus); - - return true; -} - -/* Switch alternate p2m for a single vcpu */ -bool p2m_switch_vcpu_altp2m_by_id(struct vcpu *v, unsigned int idx); - -/* Flush all the alternate p2m's for a domain */ -void p2m_flush_altp2m(struct domain *d); - -/* Make a specific alternate p2m valid */ -int p2m_init_altp2m_by_id(struct domain *d, unsigned int idx); - -/* Find an available alternate p2m and make it valid */ -int p2m_init_next_altp2m(struct domain *d, uint16_t *idx, - xenmem_access_t hvmmem_default_access); - -/* Make a specific alternate p2m invalid */ -int p2m_destroy_altp2m_by_id(struct domain *d, unsigned int idx); - -/* Switch alternate p2m for entire domain */ -int p2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx); - -/* Change a gfn->mfn mapping */ -int p2m_change_altp2m_gfn(struct domain *d, unsigned int idx, - gfn_t old_gfn, gfn_t new_gfn); - -/* Set a specific p2m view visibility */ -int p2m_set_altp2m_view_visibility(struct domain *d, unsigned int altp2m_idx, - uint8_t visible); - -#else /* !CONFIG_ALTP2M */ -struct p2m_domain *p2m_get_altp2m(struct vcpu *v); -bool p2m_set_altp2m(struct vcpu *v, unsigned int idx); -#endif /* CONFIG_ALTP2M */ - -/* - * Common alternate p2m declarations that need to be visible - * regardless of CONFIG_ALTP2M - */ - -/* Alternate p2m paging */ -bool p2m_altp2m_get_or_propagate(struct p2m_domain *ap2m, unsigned long gfn_l, - mfn_t *mfn, p2m_type_t *p2mt, - p2m_access_t *p2ma, unsigned int *page_order); - -/* Propagate a host p2m change to all alternate p2m's */ -int p2m_altp2m_propagate_change(struct domain *d, gfn_t gfn, - mfn_t mfn, unsigned int page_order, - p2m_type_t p2mt, p2m_access_t p2ma); #endif /* CONFIG_HVM */ /* p2m access to IOMMU flags */ diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ altp2m_vcpu_initialise(struct vcpu *v) vcpu_pause(v); vcpu_altp2m(v).p2midx = 0; - atomic_inc(&p2m_get_altp2m(v)->active_vcpus); + atomic_inc(&altp2m_get_altp2m(v)->active_vcpus); altp2m_vcpu_update_p2m(v); @@ -XXX,XX +XXX,XX @@ altp2m_vcpu_destroy(struct vcpu *v) if ( v != current ) vcpu_pause(v); - if ( (p2m = p2m_get_altp2m(v)) ) + if ( (p2m = altp2m_get_altp2m(v)) ) atomic_dec(&p2m->active_vcpus); altp2m_vcpu_disable_ve(v); @@ -XXX,XX +XXX,XX @@ void altp2m_vcpu_disable_ve(struct vcpu *v) } } -int p2m_init_altp2m(struct domain *d) +int altp2m_init(struct domain *d) { unsigned int i; struct p2m_domain *p2m; @@ -XXX,XX +XXX,XX @@ int p2m_init_altp2m(struct domain *d) d->altp2m_p2m[i] = p2m = p2m_init_one(d); if ( p2m == NULL ) { - p2m_teardown_altp2m(d); + altp2m_teardown(d); return -ENOMEM; } p2m->p2m_class = p2m_alternate; @@ -XXX,XX +XXX,XX @@ int p2m_init_altp2m(struct domain *d) return 0; } -void p2m_teardown_altp2m(struct domain *d) +void altp2m_teardown(struct domain *d) { unsigned int i; struct p2m_domain *p2m; @@ -XXX,XX +XXX,XX @@ int altp2m_get_effective_entry(struct p2m_domain *ap2m, gfn_t gfn, mfn_t *mfn, return 0; } -void p2m_altp2m_check(struct vcpu *v, uint16_t idx) +void altp2m_check(struct vcpu *v, uint16_t idx) { if ( altp2m_active(v->domain) ) - p2m_switch_vcpu_altp2m_by_id(v, idx); + altp2m_switch_vcpu_by_id(v, idx); } -bool p2m_switch_vcpu_altp2m_by_id(struct vcpu *v, unsigned int idx) +bool altp2m_switch_vcpu_by_id(struct vcpu *v, unsigned int idx) { struct domain *d = v->domain; bool rc = false; @@ -XXX,XX +XXX,XX @@ bool p2m_switch_vcpu_altp2m_by_id(struct vcpu *v, unsigned int idx) if ( d->arch.altp2m_eptp[idx] != mfn_x(INVALID_MFN) ) { - if ( p2m_set_altp2m(v, idx) ) + if ( altp2m_set_altp2m(v, idx) ) altp2m_vcpu_update_p2m(v); rc = 1; } @@ -XXX,XX +XXX,XX @@ bool p2m_switch_vcpu_altp2m_by_id(struct vcpu *v, unsigned int idx) * the host's entry to the altp2m (retaining page order), and indicate * that the caller should re-try the faulting instruction. */ -bool p2m_altp2m_get_or_propagate(struct p2m_domain *ap2m, unsigned long gfn_l, - mfn_t *mfn, p2m_type_t *p2mt, - p2m_access_t *p2ma, unsigned int *page_order) +bool altp2m_get_or_propagate(struct p2m_domain *ap2m, unsigned long gfn_l, + mfn_t *mfn, p2m_type_t *p2mt, p2m_access_t *p2ma, + unsigned int *page_order) { p2m_type_t ap2mt; p2m_access_t ap2ma; @@ -XXX,XX +XXX,XX @@ enum altp2m_reset_type { ALTP2M_DEACTIVATE }; -static void p2m_reset_altp2m(struct domain *d, unsigned int idx, - enum altp2m_reset_type reset_type) +static void altp2m_reset_altp2m(struct domain *d, unsigned int idx, + enum altp2m_reset_type reset_type) { struct p2m_domain *p2m; @@ -XXX,XX +XXX,XX @@ static void p2m_reset_altp2m(struct domain *d, unsigned int idx, p2m_unlock(p2m); } -void p2m_flush_altp2m(struct domain *d) +void altp2m_flush(struct domain *d) { unsigned int i; @@ -XXX,XX +XXX,XX @@ void p2m_flush_altp2m(struct domain *d) for ( i = 0; i < d->nr_altp2m; i++ ) { - p2m_reset_altp2m(d, i, ALTP2M_DEACTIVATE); + altp2m_reset_altp2m(d, i, ALTP2M_DEACTIVATE); d->arch.altp2m_eptp[i] = mfn_x(INVALID_MFN); d->arch.altp2m_visible_eptp[i] = mfn_x(INVALID_MFN); } @@ -XXX,XX +XXX,XX @@ void p2m_flush_altp2m(struct domain *d) altp2m_list_unlock(d); } -static int p2m_activate_altp2m(struct domain *d, unsigned int idx, - p2m_access_t hvmmem_default_access) +static int altp2m_activate_altp2m(struct domain *d, unsigned int idx, + p2m_access_t hvmmem_default_access) { struct p2m_domain *hostp2m, *p2m; int rc; @@ -XXX,XX +XXX,XX @@ static int p2m_activate_altp2m(struct domain *d, unsigned int idx, p2m_unlock(p2m); return rc; -} + } -int p2m_init_altp2m_by_id(struct domain *d, unsigned int idx) +int altp2m_init_by_id(struct domain *d, unsigned int idx) { int rc = -EINVAL; struct p2m_domain *hostp2m = p2m_get_hostp2m(d); @@ -XXX,XX +XXX,XX @@ int p2m_init_altp2m_by_id(struct domain *d, unsigned int idx) if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] == mfn_x(INVALID_MFN) ) - rc = p2m_activate_altp2m(d, idx, hostp2m->default_access); + rc = altp2m_activate_altp2m(d, idx, hostp2m->default_access); altp2m_list_unlock(d); return rc; } -int p2m_init_next_altp2m(struct domain *d, uint16_t *idx, - xenmem_access_t hvmmem_default_access) +int altp2m_init_next_available(struct domain *d, uint16_t *idx, + xenmem_access_t hvmmem_default_access) { int rc = -EINVAL; unsigned int i; @@ -XXX,XX +XXX,XX @@ int p2m_init_next_altp2m(struct domain *d, uint16_t *idx, if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) continue; - rc = p2m_activate_altp2m(d, i, a); + rc = altp2m_activate_altp2m(d, i, a); if ( !rc ) *idx = i; @@ -XXX,XX +XXX,XX @@ int p2m_init_next_altp2m(struct domain *d, uint16_t *idx, return rc; } -int p2m_destroy_altp2m_by_id(struct domain *d, unsigned int idx) +int altp2m_destroy_by_id(struct domain *d, unsigned int idx) { struct p2m_domain *p2m; int rc = -EBUSY; @@ -XXX,XX +XXX,XX @@ int p2m_destroy_altp2m_by_id(struct domain *d, unsigned int idx) if ( !_atomic_read(p2m->active_vcpus) ) { - p2m_reset_altp2m(d, idx, ALTP2M_DEACTIVATE); + altp2m_reset_altp2m(d, idx, ALTP2M_DEACTIVATE); d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] = mfn_x(INVALID_MFN); d->arch.altp2m_visible_eptp[array_index_nospec(idx, MAX_EPTP)] = @@ -XXX,XX +XXX,XX @@ int p2m_destroy_altp2m_by_id(struct domain *d, unsigned int idx) return rc; } -int p2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx) +int altp2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx) { struct vcpu *v; int rc = -EINVAL; @@ -XXX,XX +XXX,XX @@ int p2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx) if ( d->arch.altp2m_visible_eptp[idx] != mfn_x(INVALID_MFN) ) { for_each_vcpu( d, v ) - if ( p2m_set_altp2m(v, idx) ) + if ( altp2m_set_altp2m(v, idx) ) altp2m_vcpu_update_p2m(v); rc = 0; @@ -XXX,XX +XXX,XX @@ int p2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx) return rc; } -int p2m_change_altp2m_gfn(struct domain *d, unsigned int idx, - gfn_t old_gfn, gfn_t new_gfn) +int altp2m_change_gfn(struct domain *d, unsigned int idx, gfn_t old_gfn, + gfn_t new_gfn) { struct p2m_domain *hp2m, *ap2m; p2m_access_t a; @@ -XXX,XX +XXX,XX @@ int p2m_change_altp2m_gfn(struct domain *d, unsigned int idx, p2m_unlock(ap2m); p2m_unlock(hp2m); return rc; -} + } -int p2m_altp2m_propagate_change(struct domain *d, gfn_t gfn, - mfn_t mfn, unsigned int page_order, - p2m_type_t p2mt, p2m_access_t p2ma) +int altp2m_propagate_change(struct domain *d, gfn_t gfn, mfn_t mfn, + unsigned int page_order, p2m_type_t p2mt, + p2m_access_t p2ma) { struct p2m_domain *p2m; unsigned int i; @@ -XXX,XX +XXX,XX @@ int p2m_altp2m_propagate_change(struct domain *d, gfn_t gfn, { if ( !reset_count++ ) { - p2m_reset_altp2m(d, i, ALTP2M_RESET); + altp2m_reset_altp2m(d, i, ALTP2M_RESET); last_reset_idx = i; } else @@ -XXX,XX +XXX,XX @@ int p2m_altp2m_propagate_change(struct domain *d, gfn_t gfn, d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) continue; - p2m_reset_altp2m(d, i, ALTP2M_RESET); + altp2m_reset_altp2m(d, i, ALTP2M_RESET); } ret = 0; @@ -XXX,XX +XXX,XX @@ int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, return rc; } -int p2m_set_altp2m_view_visibility(struct domain *d, unsigned int altp2m_idx, - uint8_t visible) +int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, + uint8_t visible) { int rc = 0; diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_access.c +++ b/xen/arch/x86/mm/mem_access.c @@ -XXX,XX +XXX,XX @@ bool p2m_mem_access_emulate_check(struct vcpu *v, struct p2m_domain *p2m = NULL; if ( altp2m_active(d) ) - p2m = p2m_get_altp2m(v); + p2m = altp2m_get_altp2m(v); if ( !p2m ) p2m = p2m_get_hostp2m(d); @@ -XXX,XX +XXX,XX @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla, int rc; if ( altp2m_active(d) ) - p2m = p2m_get_altp2m(v); + p2m = altp2m_get_altp2m(v); if ( !p2m ) p2m = p2m_get_hostp2m(d); @@ -XXX,XX +XXX,XX @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla, return (p2ma != p2m_access_n2rwx); } -static int p2m_set_altp2m_mem_access(struct domain *d, struct p2m_domain *hp2m, - struct p2m_domain *ap2m, p2m_access_t a, - gfn_t gfn) +static int altp2m_set_altp2m_mem_access(struct domain *d, + struct p2m_domain *hp2m, + struct p2m_domain *ap2m, p2m_access_t a, + gfn_t gfn) { mfn_t mfn; p2m_type_t t; @@ -XXX,XX +XXX,XX @@ static int set_mem_access(struct domain *d, struct p2m_domain *p2m, if ( ap2m ) { - rc = p2m_set_altp2m_mem_access(d, p2m, ap2m, a, gfn); + rc = altp2m_set_altp2m_mem_access(d, p2m, ap2m, a, gfn); /* If the corresponding mfn is invalid we will want to just skip it */ if ( rc == -ESRCH ) rc = 0; diff --git a/xen/arch/x86/mm/p2m-basic.c b/xen/arch/x86/mm/p2m-basic.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-basic.c +++ b/xen/arch/x86/mm/p2m-basic.c @@ -XXX,XX +XXX,XX @@ int p2m_init(struct domain *d) return rc; } - rc = altp2m_supported() ? p2m_init_altp2m(d) : 0; + rc = altp2m_supported() ? altp2m_init(d) : 0; if ( rc ) { p2m_teardown_hostp2m(d); @@ -XXX,XX +XXX,XX @@ void p2m_final_teardown(struct domain *d) if ( is_hvm_domain(d) ) { if ( altp2m_supported() ) - p2m_teardown_altp2m(d); + altp2m_teardown(d); /* * We must tear down nestedp2m unconditionally because * we initialise it unconditionally. diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -XXX,XX +XXX,XX @@ bool ept_handle_misconfig(uint64_t gpa) int rc; if ( altp2m_active(curr->domain) ) - p2m = p2m_get_altp2m(curr); + p2m = altp2m_get_altp2m(curr); p2m_lock(p2m); @@ -XXX,XX +XXX,XX @@ out: if ( altp2m_supported() && entry_written && p2m_is_hostp2m(p2m) ) { - ret = p2m_altp2m_propagate_change(d, _gfn(gfn), mfn, order, p2mt, p2ma); + ret = altp2m_propagate_change(d, _gfn(gfn), mfn, order, p2mt, p2ma); if ( !rc ) rc = ret; } diff --git a/xen/arch/x86/mm/p2m.h b/xen/arch/x86/mm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m.h +++ b/xen/arch/x86/mm/p2m.h @@ -XXX,XX +XXX,XX @@ static inline int p2m_init_logdirty(struct p2m_domain *p2m) { return 0; } static inline void p2m_free_logdirty(struct p2m_domain *p2m) {} #endif -int p2m_init_altp2m(struct domain *d); -void p2m_teardown_altp2m(struct domain *d); - void p2m_flush_table_locked(struct p2m_domain *p2m); int __must_check p2m_remove_entry(struct p2m_domain *p2m, gfn_t gfn, mfn_t mfn, unsigned int page_order); diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/vm_event.c +++ b/xen/common/vm_event.c @@ -XXX,XX +XXX,XX @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved) /* Check for altp2m switch */ if ( IS_ENABLED(CONFIG_ALTP2M) && rsp.flags & VM_EVENT_FLAG_ALTERNATE_P2M ) - p2m_altp2m_check(v, rsp.altp2m_idx); + altp2m_check(v, rsp.altp2m_idx); if ( rsp.flags & VM_EVENT_FLAG_SET_REGISTERS ) vm_event_set_registers(v, &rsp); diff --git a/xen/include/xen/p2m-common.h b/xen/include/xen/p2m-common.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/p2m-common.h +++ b/xen/include/xen/p2m-common.h @@ -XXX,XX +XXX,XX @@ int unmap_mmio_regions(struct domain *d, mfn_t mfn); /* Check to see if vcpu should be switched to a different p2m. */ -void p2m_altp2m_check(struct vcpu *v, uint16_t idx); +void altp2m_check(struct vcpu *v, uint16_t idx); /* * Populate-on-Demand -- 2.34.1
This commit moves the altp2m HVMOP implementation to common code, making it possible to re-use it across architectures. In this commit, the entire implementation is gated behind CONFIG_X86, with no changes to the body of do_altp2m_op. A stub implementation is added for ARM, which will be removed once do_altp2m_op has been modified to add ARM support. This commit contains only code movement, and no change in functionality is intended. This is commit 1/2 of the common do_altp2m_op phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Aqib Javaid <Aqib.Javaid@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/hvm/hvm.c | 400 ------------------------------------- xen/common/altp2m.c | 413 +++++++++++++++++++++++++++++++++++++++ xen/include/xen/altp2m.h | 11 ++ 3 files changed, 424 insertions(+), 400 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ static int hvmop_get_param( return rc; } -/* - * altp2m operations are envisioned as being used in several different - * modes: - * - * - external: All control and decisions are made by an external agent - * running domain 0. - * - * - internal: altp2m operations are used exclusively by an in-guest - * agent to protect itself from the guest kernel and in-guest - * attackers. - * - * - coordinated: An in-guest agent handles #VE and VMFUNCs locally, - * but makes requests of an agent running outside the domain for - * bigger changes (such as modifying altp2m entires). - * - * This corresponds to the three values for HVM_PARAM_ALTP2M - * (external, mixed, limited). All three models have advantages and - * disadvantages. - * - * Normally hypercalls made by a program in domain 0 in order to - * control a guest would be DOMCTLs rather than HVMOPs. But in order - * to properly enable the 'internal' use case, as well as to avoid - * fragmentation, all altp2m subops should come under this single - * HVMOP. - * - * Note that 'internal' mode (HVM_PARAM_ALTP2M == XEN_ALTP2M_mixed) - * has not been evaluated for safety from a security perspective. - * Before using this mode in a security-critical environment, each - * subop should be evaluated for safety, with unsafe subops - * blacklisted in xsm_hvm_altp2mhvm_op(). - */ -static int do_altp2m_op( - XEN_GUEST_HANDLE_PARAM(void) arg) -{ -#ifdef CONFIG_ALTP2M - struct xen_hvm_altp2m_op a; - struct domain *d = NULL; - int rc = 0; - uint64_t mode; - - if ( !altp2m_supported() ) - return -EOPNOTSUPP; - - if ( copy_from_guest(&a, arg, 1) ) - return -EFAULT; - - if ( a.pad1 || a.pad2 || - (a.version != HVMOP_ALTP2M_INTERFACE_VERSION) ) - return -EINVAL; - - switch ( a.cmd ) - { - case HVMOP_altp2m_get_domain_state: - case HVMOP_altp2m_set_domain_state: - case HVMOP_altp2m_vcpu_enable_notify: - case HVMOP_altp2m_vcpu_disable_notify: - case HVMOP_altp2m_create_p2m: - case HVMOP_altp2m_destroy_p2m: - case HVMOP_altp2m_switch_p2m: - case HVMOP_altp2m_set_suppress_ve: - case HVMOP_altp2m_set_suppress_ve_multi: - case HVMOP_altp2m_get_suppress_ve: - case HVMOP_altp2m_set_mem_access: - case HVMOP_altp2m_set_mem_access_multi: - case HVMOP_altp2m_get_mem_access: - case HVMOP_altp2m_change_gfn: - case HVMOP_altp2m_get_p2m_idx: - case HVMOP_altp2m_set_visibility: - break; - - default: - return -EOPNOTSUPP; - } - - d = rcu_lock_domain_by_any_id(a.domain); - - if ( d == NULL ) - return -ESRCH; - - if ( !is_hvm_domain(d) ) - { - rc = -EOPNOTSUPP; - goto out; - } - - if ( (a.cmd != HVMOP_altp2m_get_domain_state) && - (a.cmd != HVMOP_altp2m_set_domain_state) && - !d->altp2m_active ) - { - rc = -EOPNOTSUPP; - goto out; - } - - mode = d->arch.hvm.params[HVM_PARAM_ALTP2M]; - - if ( XEN_ALTP2M_disabled == mode ) - { - rc = -EINVAL; - goto out; - } - - if ( d->nr_altp2m == 0 ) - { - rc = -EOPNOTSUPP; - goto out; - } - - if ( (rc = xsm_hvm_altp2mhvm_op(XSM_OTHER, d, mode, a.cmd)) ) - goto out; - - switch ( a.cmd ) - { - case HVMOP_altp2m_get_domain_state: - a.u.domain_state.state = altp2m_active(d); - rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; - break; - - case HVMOP_altp2m_set_domain_state: - { - struct vcpu *v; - bool ostate; - - if ( nestedhvm_enabled(d) ) - { - rc = -EINVAL; - break; - } - - rc = domain_pause_except_self(d); - if ( rc ) - break; - - ostate = d->altp2m_active; - d->altp2m_active = !!a.u.domain_state.state; - - /* If the alternate p2m state has changed, handle appropriately */ - if ( d->altp2m_active != ostate && - (ostate || !(rc = altp2m_init_by_id(d, 0))) ) - { - for_each_vcpu( d, v ) - { - if ( !ostate ) - altp2m_vcpu_initialise(v); - else - altp2m_vcpu_destroy(v); - } - - if ( ostate ) - altp2m_flush(d); - } - else if ( rc ) - d->altp2m_active = false; - - domain_unpause_except_self(d); - break; - } - - case HVMOP_altp2m_vcpu_enable_notify: - { - struct vcpu *v; - - if ( a.u.enable_notify.pad || - a.u.enable_notify.vcpu_id >= d->max_vcpus ) - { - rc = -EINVAL; - break; - } - - if ( !cpu_has_vmx_virt_exceptions ) - { - rc = -EOPNOTSUPP; - break; - } - - v = d->vcpu[a.u.enable_notify.vcpu_id]; - - rc = altp2m_vcpu_enable_ve(v, _gfn(a.u.enable_notify.gfn)); - break; - } - - case HVMOP_altp2m_vcpu_disable_notify: - { - struct vcpu *v; - - if ( a.u.disable_notify.vcpu_id >= d->max_vcpus ) - { - rc = -EINVAL; - break; - } - - if ( !cpu_has_vmx_virt_exceptions ) - { - rc = -EOPNOTSUPP; - break; - } - - v = d->vcpu[a.u.enable_notify.vcpu_id]; - - altp2m_vcpu_disable_ve(v); - break; - } - - case HVMOP_altp2m_create_p2m: - rc = altp2m_init_next_available(d, &a.u.view.view, - a.u.view.hvmmem_default_access); - if ( !rc ) - rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; - break; - - case HVMOP_altp2m_destroy_p2m: - rc = altp2m_destroy_by_id(d, a.u.view.view); - break; - - case HVMOP_altp2m_switch_p2m: - rc = altp2m_switch_domain_altp2m_by_id(d, a.u.view.view); - break; - - case HVMOP_altp2m_set_suppress_ve: - if ( a.u.suppress_ve.pad1 || a.u.suppress_ve.pad2 ) - rc = -EINVAL; - else - { - gfn_t gfn = _gfn(a.u.suppress_ve.gfn); - unsigned int altp2m_idx = a.u.suppress_ve.view; - bool suppress_ve = a.u.suppress_ve.suppress_ve; - - rc = p2m_set_suppress_ve(d, gfn, suppress_ve, altp2m_idx); - } - break; - - case HVMOP_altp2m_set_suppress_ve_multi: - { - uint64_t max_phys_addr = (1UL << d->arch.cpuid->extd.maxphysaddr) - 1; - - a.u.suppress_ve_multi.last_gfn = min(a.u.suppress_ve_multi.last_gfn, - max_phys_addr); - - if ( a.u.suppress_ve_multi.pad1 || - a.u.suppress_ve_multi.first_gfn > a.u.suppress_ve_multi.last_gfn ) - rc = -EINVAL; - else - { - rc = p2m_set_suppress_ve_multi(d, &a.u.suppress_ve_multi); - if ( (!rc || rc == -ERESTART) && __copy_to_guest(arg, &a, 1) ) - rc = -EFAULT; - } - break; - } - - case HVMOP_altp2m_get_suppress_ve: - if ( a.u.suppress_ve.pad1 || a.u.suppress_ve.pad2 ) - rc = -EINVAL; - else - { - gfn_t gfn = _gfn(a.u.suppress_ve.gfn); - unsigned int altp2m_idx = a.u.suppress_ve.view; - bool suppress_ve; - - rc = p2m_get_suppress_ve(d, gfn, &suppress_ve, altp2m_idx); - if ( !rc ) - { - a.u.suppress_ve.suppress_ve = suppress_ve; - rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; - } - } - break; - - case HVMOP_altp2m_set_mem_access: - if ( !vm_event_is_enabled(current) ) - { - rc = -EOPNOTSUPP; - break; - } - - if ( a.u.mem_access.pad ) - rc = -EINVAL; - else - rc = p2m_set_mem_access(d, _gfn(a.u.mem_access.gfn), 1, 0, 0, - a.u.mem_access.access, - a.u.mem_access.view); - break; - - case HVMOP_altp2m_set_mem_access_multi: - if ( !vm_event_is_enabled(current) ) - { - rc = -EOPNOTSUPP; - break; - } - - if ( a.u.set_mem_access_multi.pad || - a.u.set_mem_access_multi.opaque > a.u.set_mem_access_multi.nr ) - { - rc = -EINVAL; - break; - } - - /* - * Unlike XENMEM_access_op_set_access_multi, we don't need any bits of - * the 'continuation' counter to be zero (to stash a command in). - * However, 0x40 is a good 'stride' to make sure that we make - * a reasonable amount of forward progress before yielding, - * so use a mask of 0x3F here. - */ - rc = p2m_set_mem_access_multi(d, a.u.set_mem_access_multi.pfn_list, - a.u.set_mem_access_multi.access_list, - a.u.set_mem_access_multi.nr, - a.u.set_mem_access_multi.opaque, - 0x3F, - a.u.set_mem_access_multi.view); - if ( rc > 0 ) - { - a.u.set_mem_access_multi.opaque = rc; - rc = -ERESTART; - if ( __copy_field_to_guest(guest_handle_cast(arg, xen_hvm_altp2m_op_t), - &a, u.set_mem_access_multi.opaque) ) - rc = -EFAULT; - } - break; - - case HVMOP_altp2m_get_mem_access: - if ( !vm_event_is_enabled(current) ) - { - rc = -EOPNOTSUPP; - break; - } - - if ( a.u.mem_access.pad ) - rc = -EINVAL; - else - { - xenmem_access_t access; - - rc = p2m_get_mem_access(d, _gfn(a.u.mem_access.gfn), &access, - a.u.mem_access.view); - if ( !rc ) - { - a.u.mem_access.access = access; - rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; - } - } - break; - - case HVMOP_altp2m_change_gfn: - if ( a.u.change_gfn.pad1 || a.u.change_gfn.pad2 ) - rc = -EINVAL; - else - rc = altp2m_change_gfn(d, a.u.change_gfn.view, - _gfn(a.u.change_gfn.old_gfn), - _gfn(a.u.change_gfn.new_gfn)); - break; - - case HVMOP_altp2m_get_p2m_idx: - { - struct vcpu *v; - - if ( !altp2m_active(d) ) - { - rc = -EOPNOTSUPP; - break; - } - - if ( (v = domain_vcpu(d, a.u.get_vcpu_p2m_idx.vcpu_id)) == NULL ) - { - rc = -EINVAL; - break; - } - - a.u.get_vcpu_p2m_idx.altp2m_idx = altp2m_vcpu_idx(v); - rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; - break; - } - - case HVMOP_altp2m_set_visibility: - { - unsigned int idx = a.u.set_visibility.altp2m_idx; - - if ( a.u.set_visibility.pad ) - rc = -EINVAL; - else if ( !altp2m_active(d) ) - rc = -EOPNOTSUPP; - else - rc = altp2m_set_view_visibility(d, idx, a.u.set_visibility.visible); - break; - } - - default: - ASSERT_UNREACHABLE(); - rc = -EOPNOTSUPP; - break; - } - - out: - rcu_unlock_domain(d); - - return rc; -#else /* !CONFIG_ALTP2M */ - return -EOPNOTSUPP; -#endif /* CONFIG_ALTP2M */ -} - DEFINE_XEN_GUEST_HANDLE(compat_hvm_altp2m_op_t); /* diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include <xen/altp2m.h> +#include <xen/guest_access.h> +#include <xen/vm_event.h> + +#include <asm/altp2m.h> + +#include <public/hvm/params.h> + +#include <xsm/xsm.h> + +#ifdef CONFIG_X86 +#include <asm/hvm/nestedhvm.h> +/* + * altp2m operations are envisioned as being used in several different + * modes: + * + * - external: All control and decisions are made by an external agent + * running domain 0. + * + * - internal: altp2m operations are used exclusively by an in-guest + * agent to protect itself from the guest kernel and in-guest + * attackers. + * + * - coordinated: An in-guest agent handles #VE and VMFUNCs locally, + * but makes requests of an agent running outside the domain for + * bigger changes (such as modifying altp2m entires). + * + * This corresponds to the three values for HVM_PARAM_ALTP2M + * (external, mixed, limited). All three models have advantages and + * disadvantages. + * + * Normally hypercalls made by a program in domain 0 in order to + * control a guest would be DOMCTLs rather than HVMOPs. But in order + * to properly enable the 'internal' use case, as well as to avoid + * fragmentation, all altp2m subops should come under this single + * HVMOP. + * + * Note that 'internal' mode (HVM_PARAM_ALTP2M == XEN_ALTP2M_mixed) + * has not been evaluated for safety from a security perspective. + * Before using this mode in a security-critical environment, each + * subop should be evaluated for safety, with unsafe subops + * blacklisted in xsm_hvm_altp2mhvm_op(). + */ +int do_altp2m_op( + XEN_GUEST_HANDLE_PARAM(void) arg) +{ + struct xen_hvm_altp2m_op a; + struct domain *d = NULL; + int rc = 0; + uint64_t mode; + + if ( !altp2m_supported() ) + return -EOPNOTSUPP; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + if ( a.pad1 || a.pad2 || + (a.version != HVMOP_ALTP2M_INTERFACE_VERSION) ) + return -EINVAL; + + switch ( a.cmd ) + { + case HVMOP_altp2m_get_domain_state: + case HVMOP_altp2m_set_domain_state: + case HVMOP_altp2m_vcpu_enable_notify: + case HVMOP_altp2m_vcpu_disable_notify: + case HVMOP_altp2m_create_p2m: + case HVMOP_altp2m_destroy_p2m: + case HVMOP_altp2m_switch_p2m: + case HVMOP_altp2m_set_suppress_ve: + case HVMOP_altp2m_set_suppress_ve_multi: + case HVMOP_altp2m_get_suppress_ve: + case HVMOP_altp2m_set_mem_access: + case HVMOP_altp2m_set_mem_access_multi: + case HVMOP_altp2m_get_mem_access: + case HVMOP_altp2m_change_gfn: + case HVMOP_altp2m_get_p2m_idx: + case HVMOP_altp2m_set_visibility: + break; + + default: + return -EOPNOTSUPP; + } + + d = rcu_lock_domain_by_any_id(a.domain); + + if ( d == NULL ) + return -ESRCH; + + if ( !is_hvm_domain(d) ) + { + rc = -EOPNOTSUPP; + goto out; + } + + if ( (a.cmd != HVMOP_altp2m_get_domain_state) && + (a.cmd != HVMOP_altp2m_set_domain_state) && + !d->altp2m_active ) + { + rc = -EOPNOTSUPP; + goto out; + } + + mode = d->arch.hvm.params[HVM_PARAM_ALTP2M]; + + if ( XEN_ALTP2M_disabled == mode ) + { + rc = -EINVAL; + goto out; + } + + if ( d->nr_altp2m == 0 ) + { + rc = -EOPNOTSUPP; + goto out; + } + + if ( (rc = xsm_hvm_altp2mhvm_op(XSM_OTHER, d, mode, a.cmd)) ) + goto out; + + switch ( a.cmd ) + { + case HVMOP_altp2m_get_domain_state: + a.u.domain_state.state = altp2m_active(d); + rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + break; + + case HVMOP_altp2m_set_domain_state: + { + struct vcpu *v; + bool ostate; + + if ( nestedhvm_enabled(d) ) + { + rc = -EINVAL; + break; + } + + rc = domain_pause_except_self(d); + if ( rc ) + break; + + ostate = d->altp2m_active; + d->altp2m_active = !!a.u.domain_state.state; + + /* If the alternate p2m state has changed, handle appropriately */ + if ( d->altp2m_active != ostate && + (ostate || !(rc = altp2m_init_by_id(d, 0))) ) + { + for_each_vcpu( d, v ) + { + if ( !ostate ) + altp2m_vcpu_initialise(v); + else + altp2m_vcpu_destroy(v); + } + + if ( ostate ) + altp2m_flush(d); + } + else if ( rc ) + d->altp2m_active = false; + + domain_unpause_except_self(d); + break; + } + + case HVMOP_altp2m_vcpu_enable_notify: + { + struct vcpu *v; + + if ( a.u.enable_notify.pad || + a.u.enable_notify.vcpu_id >= d->max_vcpus ) + { + rc = -EINVAL; + break; + } + + if ( !cpu_has_vmx_virt_exceptions ) + { + rc = -EOPNOTSUPP; + break; + } + + v = d->vcpu[a.u.enable_notify.vcpu_id]; + + rc = altp2m_vcpu_enable_ve(v, _gfn(a.u.enable_notify.gfn)); + break; + } + + case HVMOP_altp2m_vcpu_disable_notify: + { + struct vcpu *v; + + if ( a.u.disable_notify.vcpu_id >= d->max_vcpus ) + { + rc = -EINVAL; + break; + } + + if ( !cpu_has_vmx_virt_exceptions ) + { + rc = -EOPNOTSUPP; + break; + } + + v = d->vcpu[a.u.enable_notify.vcpu_id]; + + altp2m_vcpu_disable_ve(v); + break; + } + + case HVMOP_altp2m_create_p2m: + rc = altp2m_init_next_available(d, &a.u.view.view, + a.u.view.hvmmem_default_access); + if ( !rc ) + rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + break; + + case HVMOP_altp2m_destroy_p2m: + rc = altp2m_destroy_by_id(d, a.u.view.view); + break; + + case HVMOP_altp2m_switch_p2m: + rc = altp2m_switch_domain_altp2m_by_id(d, a.u.view.view); + break; + + case HVMOP_altp2m_set_suppress_ve: + if ( a.u.suppress_ve.pad1 || a.u.suppress_ve.pad2 ) + rc = -EINVAL; + else + { + gfn_t gfn = _gfn(a.u.suppress_ve.gfn); + unsigned int altp2m_idx = a.u.suppress_ve.view; + bool suppress_ve = a.u.suppress_ve.suppress_ve; + + rc = p2m_set_suppress_ve(d, gfn, suppress_ve, altp2m_idx); + } + break; + + case HVMOP_altp2m_set_suppress_ve_multi: + { + uint64_t max_phys_addr = (1UL << d->arch.cpuid->extd.maxphysaddr) - 1; + + a.u.suppress_ve_multi.last_gfn = min(a.u.suppress_ve_multi.last_gfn, + max_phys_addr); + + if ( a.u.suppress_ve_multi.pad1 || + a.u.suppress_ve_multi.first_gfn > a.u.suppress_ve_multi.last_gfn ) + rc = -EINVAL; + else + { + rc = p2m_set_suppress_ve_multi(d, &a.u.suppress_ve_multi); + if ( (!rc || rc == -ERESTART) && __copy_to_guest(arg, &a, 1) ) + rc = -EFAULT; + } + break; + } + + case HVMOP_altp2m_get_suppress_ve: + if ( a.u.suppress_ve.pad1 || a.u.suppress_ve.pad2 ) + rc = -EINVAL; + else + { + gfn_t gfn = _gfn(a.u.suppress_ve.gfn); + unsigned int altp2m_idx = a.u.suppress_ve.view; + bool suppress_ve; + + rc = p2m_get_suppress_ve(d, gfn, &suppress_ve, altp2m_idx); + if ( !rc ) + { + a.u.suppress_ve.suppress_ve = suppress_ve; + rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + } + } + break; + + case HVMOP_altp2m_set_mem_access: + if ( !vm_event_is_enabled(current) ) + { + rc = -EOPNOTSUPP; + break; + } + + if ( a.u.mem_access.pad ) + rc = -EINVAL; + else + rc = p2m_set_mem_access(d, _gfn(a.u.mem_access.gfn), 1, 0, 0, + a.u.mem_access.access, + a.u.mem_access.view); + break; + + case HVMOP_altp2m_set_mem_access_multi: + if ( !vm_event_is_enabled(current) ) + { + rc = -EOPNOTSUPP; + break; + } + + if ( a.u.set_mem_access_multi.pad || + a.u.set_mem_access_multi.opaque > a.u.set_mem_access_multi.nr ) + { + rc = -EINVAL; + break; + } + + /* + * Unlike XENMEM_access_op_set_access_multi, we don't need any bits of + * the 'continuation' counter to be zero (to stash a command in). + * However, 0x40 is a good 'stride' to make sure that we make + * a reasonable amount of forward progress before yielding, + * so use a mask of 0x3F here. + */ + rc = p2m_set_mem_access_multi(d, a.u.set_mem_access_multi.pfn_list, + a.u.set_mem_access_multi.access_list, + a.u.set_mem_access_multi.nr, + a.u.set_mem_access_multi.opaque, + 0x3F, + a.u.set_mem_access_multi.view); + if ( rc > 0 ) + { + a.u.set_mem_access_multi.opaque = rc; + rc = -ERESTART; + if ( __copy_field_to_guest(guest_handle_cast(arg, xen_hvm_altp2m_op_t), + &a, u.set_mem_access_multi.opaque) ) + rc = -EFAULT; + } + break; + + case HVMOP_altp2m_get_mem_access: + if ( !vm_event_is_enabled(current) ) + { + rc = -EOPNOTSUPP; + break; + } + + if ( a.u.mem_access.pad ) + rc = -EINVAL; + else + { + xenmem_access_t access; + + rc = p2m_get_mem_access(d, _gfn(a.u.mem_access.gfn), &access, + a.u.mem_access.view); + if ( !rc ) + { + a.u.mem_access.access = access; + rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + } + } + break; + + case HVMOP_altp2m_change_gfn: + if ( a.u.change_gfn.pad1 || a.u.change_gfn.pad2 ) + rc = -EINVAL; + else + rc = altp2m_change_gfn(d, a.u.change_gfn.view, + _gfn(a.u.change_gfn.old_gfn), + _gfn(a.u.change_gfn.new_gfn)); + break; + + case HVMOP_altp2m_get_p2m_idx: + { + struct vcpu *v; + + if ( !altp2m_active(d) ) + { + rc = -EOPNOTSUPP; + break; + } + + if ( (v = domain_vcpu(d, a.u.get_vcpu_p2m_idx.vcpu_id)) == NULL ) + { + rc = -EINVAL; + break; + } + + a.u.get_vcpu_p2m_idx.altp2m_idx = altp2m_vcpu_idx(v); + rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + break; + } + + case HVMOP_altp2m_set_visibility: + { + unsigned int idx = a.u.set_visibility.altp2m_idx; + + if ( a.u.set_visibility.pad ) + rc = -EINVAL; + else if ( !altp2m_active(d) ) + rc = -EOPNOTSUPP; + else + rc = altp2m_set_view_visibility(d, idx, a.u.set_visibility.visible); + break; + } + + default: + ASSERT_UNREACHABLE(); + rc = -EOPNOTSUPP; + break; + } + + out: + rcu_unlock_domain(d); + + return rc; +} +#else +int do_altp2m_op( + XEN_GUEST_HANDLE_PARAM(void) arg) +{ + return -EOPNOTSUPP; +} +#endif /* * Local variables: diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ #ifndef __XEN_ALTP2M_H__ #define __XEN_ALTP2M_H__ +#include <xen/errno.h> +#include <xen/param.h> #include <xen/sched.h> +#include <public/hvm/hvm_op.h> + #ifdef CONFIG_ALTP2M /* Alternate p2m HVM on/off per domain */ @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_active(const struct domain *d) return d->altp2m_active; } +int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg); + #else /* CONFIG_ALTP2M */ static inline bool altp2m_active(const struct domain *d) @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_active(const struct domain *d) return false; } +static inline int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_ALTP2M */ #endif /* __XEN_ALTP2M_H__ */ -- 2.34.1
This commit makes the minimum required changes necessary for do_altp2m_op to compile on ARM. All altp2m commands in the switch statement are gated by CONFIG_X86, with a default case of returning EOPNOTSUPP. This allows future commits to move the #ifdef CONFIG_X86 down as support for ARM is added. Additionally, a call to do_altp2m_op is added in the ARM HVMOP code. This is commit 2/2 of the common do_altp2m_op phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> --- v6: Replaced patches 2 and 3 from v4/v5 patch set with this patch. Made HVM_PARAM_ALTP2M read-only, following the change to the x86 implementation in commit 0291089f6ea8. The DOMCTL to enable altp2m on ARM is implemented in a later commit in this patch series. --- xen/arch/arm/hvm.c | 9 +++++++++ xen/common/altp2m.c | 29 ++++++++++++++--------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/xen/arch/arm/hvm.c b/xen/arch/arm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/hvm.c +++ b/xen/arch/arm/hvm.c @@ -XXX,XX +XXX,XX @@ * Arch-specific hardware virtual machine abstractions. */ +#include <xen/altp2m.h> #include <xen/init.h> #include <xen/lib.h> #include <xen/errno.h> @@ -XXX,XX +XXX,XX @@ static int hvm_allow_set_param(const struct domain *d, unsigned int param) { switch ( param ) { + /* The following parameters are read-only. */ + case HVM_PARAM_ALTP2M: + return -EEXIST; + /* * The following parameters are intended for toolstack usage only. * They may not be set by the domain. @@ -XXX,XX +XXX,XX @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) rc = -EINVAL; break; + case HVMOP_altp2m: + rc = do_altp2m_op(arg); + break; + default: { gdprintk(XENLOG_DEBUG, "HVMOP op=%lu: not implemented\n", op); diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <xsm/xsm.h> -#ifdef CONFIG_X86 +#if defined(CONFIG_X86) && defined(CONFIG_HVM) #include <asm/hvm/nestedhvm.h> +#endif + /* * altp2m operations are envisioned as being used in several different * modes: @@ -XXX,XX +XXX,XX @@ * - external: All control and decisions are made by an external agent * running domain 0. * - * - internal: altp2m operations are used exclusively by an in-guest - * agent to protect itself from the guest kernel and in-guest - * attackers. + * - internal (x86 only): altp2m operations are used exclusively by an + * in-guest agent to protect itself from the guest kernel and + * in-guest attackers. * - * - coordinated: An in-guest agent handles #VE and VMFUNCs locally, - * but makes requests of an agent running outside the domain for - * bigger changes (such as modifying altp2m entires). + * - coordinated (x86 only): An in-guest agent handles #VE and VMFUNCs + * locally, but makes requests of an agent running outside the + * domain for bigger changes (such as modifying altp2m entires). * * This corresponds to the three values for HVM_PARAM_ALTP2M * (external, mixed, limited). All three models have advantages and @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( if ( (a.cmd != HVMOP_altp2m_get_domain_state) && (a.cmd != HVMOP_altp2m_set_domain_state) && - !d->altp2m_active ) + !altp2m_active(d) ) { rc = -EOPNOTSUPP; goto out; @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( switch ( a.cmd ) { +#ifdef CONFIG_X86 case HVMOP_altp2m_get_domain_state: a.u.domain_state.state = altp2m_active(d); rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( rc = altp2m_set_view_visibility(d, idx, a.u.set_visibility.visible); break; } +#endif /* CONFIG_X86 */ default: +#ifdef CONFIG_X86 ASSERT_UNREACHABLE(); +#endif rc = -EOPNOTSUPP; break; } @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( return rc; } -#else -int do_altp2m_op( - XEN_GUEST_HANDLE_PARAM(void) arg) -{ - return -EOPNOTSUPP; -} -#endif /* * Local variables: -- 2.34.1
This commit adds support for the altp2m_get_domain_state HVMOP on ARM. All code used in the command implementation already works on ARM, so no further changes beyond moving the #ifdef are necessary. This is commit 1/1 of the get_domain_state phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. This commit can be squashed into the previous commit for the actual submission if that would be preferred, but I thought it might be easier to understand the command #ifdef gate approach by splitting this into a separate patch. --- xen/common/altp2m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( switch ( a.cmd ) { -#ifdef CONFIG_X86 case HVMOP_altp2m_get_domain_state: a.u.domain_state.state = altp2m_active(d); rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; break; +#ifdef CONFIG_X86 case HVMOP_altp2m_set_domain_state: { struct vcpu *v; -- 2.34.1
This commit moves the p2m_init_one and p2m_free_one declarations from the x86-only p2m.h header file to the asm/p2m.h header. This makes it possible to use these functions in the common altp2m init/teardown routines. This is commit 1/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/p2m.h | 3 +++ xen/arch/x86/mm/p2m.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/include/asm/p2m.h b/xen/arch/x86/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/p2m.h +++ b/xen/arch/x86/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ int p2m_alloc_table(struct p2m_domain *p2m); void p2m_teardown(struct p2m_domain *p2m, bool remove_root, bool *preempted); void p2m_final_teardown(struct domain *d); +struct p2m_domain *p2m_init_one(struct domain *d); +void p2m_free_one(struct p2m_domain *p2m); + /* Add/remove a page to/from a domain's p2m table. */ int p2m_add_page(struct domain *d, gfn_t gfn, mfn_t mfn, unsigned int page_order, p2m_type_t t); diff --git a/xen/arch/x86/mm/p2m.h b/xen/arch/x86/mm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m.h +++ b/xen/arch/x86/mm/p2m.h @@ -XXX,XX +XXX,XX @@ #ifndef __ARCH_MM_P2M_H__ #define __ARCH_MM_P2M_H__ -struct p2m_domain *p2m_init_one(struct domain *d); -void p2m_free_one(struct p2m_domain *p2m); - void p2m_pod_init(struct p2m_domain *p2m); #ifdef CONFIG_HVM -- 2.34.1
This commit adds three altp2m_lock functions which wrap the corresponding altp2m_list_lock functions present in "mm-locks.h". The "mm-locks.h" file is only accessible in x86 code. In order to make altp2m common across architectures, it must be possible to acquire the altp2m lock without including an x86-specific header file. These functions cannot be static inline like their "mm-locks.h" counterparts, since "mm-locks.h" is only included in source files, not header files. Therefore, these functions might introduce a slight function call overhead over their "mm-locks.h" counterparts. However, the altp2m lock is mostly used in init/teardown routines and HVMOP implementations. For these cases, the altp2m_list_lock functions have been switched out for the altp2m_lock functions so they can be later migrated to common code. The only other function using the altp2m lock is altp2m_get_or_propagate, which is in the hot path of the page fault handler, so the altp2m_list_lock calls have not been replaced for that function. This is commit 2/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. This seems like the solution which makes the most sense here, but it would be nicer if it could be static inline. I'm also not sure if the "mm-locks.h" functions are really supposed to be exposed outside of their translation unit like this, so feedback on this is appreciated. --- xen/arch/x86/include/asm/altp2m.h | 4 +++ xen/arch/x86/mm/altp2m.c | 42 ++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ int p2m_set_suppress_ve_multi(struct domain *d, int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, unsigned int altp2m_idx); +void altp2m_lock_init(struct domain *d); +void altp2m_lock(struct domain *d); +void altp2m_unlock(struct domain *d); + #else static inline bool altp2m_is_eptp_valid(const struct domain *d, diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ int altp2m_init(struct domain *d) struct p2m_domain *p2m; struct p2m_domain *hostp2m = p2m_get_hostp2m(d); - mm_lock_init(&d->arch.altp2m_list_lock); + altp2m_lock_init(d); d->altp2m_p2m = xvzalloc_array(struct p2m_domain *, d->nr_altp2m); if ( !d->altp2m_p2m ) @@ -XXX,XX +XXX,XX @@ bool altp2m_switch_vcpu_by_id(struct vcpu *v, unsigned int idx) if ( idx >= d->nr_altp2m ) return rc; - altp2m_list_lock(d); + altp2m_lock(d); if ( d->arch.altp2m_eptp[idx] != mfn_x(INVALID_MFN) ) { @@ -XXX,XX +XXX,XX @@ bool altp2m_switch_vcpu_by_id(struct vcpu *v, unsigned int idx) rc = 1; } - altp2m_list_unlock(d); + altp2m_unlock(d); return rc; } @@ -XXX,XX +XXX,XX @@ void altp2m_flush(struct domain *d) { unsigned int i; - altp2m_list_lock(d); + altp2m_lock(d); for ( i = 0; i < d->nr_altp2m; i++ ) { @@ -XXX,XX +XXX,XX @@ void altp2m_flush(struct domain *d) d->arch.altp2m_visible_eptp[i] = mfn_x(INVALID_MFN); } - altp2m_list_unlock(d); + altp2m_unlock(d); } static int altp2m_activate_altp2m(struct domain *d, unsigned int idx, @@ -XXX,XX +XXX,XX @@ int altp2m_init_by_id(struct domain *d, unsigned int idx) if ( idx >= d->nr_altp2m ) return rc; - altp2m_list_lock(d); + altp2m_lock(d); if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] == mfn_x(INVALID_MFN) ) rc = altp2m_activate_altp2m(d, idx, hostp2m->default_access); - altp2m_list_unlock(d); + altp2m_unlock(d); return rc; } @@ -XXX,XX +XXX,XX @@ int altp2m_init_next_available(struct domain *d, uint16_t *idx, !xenmem_access_to_p2m_access(hostp2m, hvmmem_default_access, &a) ) return rc; - altp2m_list_lock(d); + altp2m_lock(d); for ( i = 0; i < d->nr_altp2m; i++ ) { @@ -XXX,XX +XXX,XX @@ int altp2m_init_next_available(struct domain *d, uint16_t *idx, break; } - altp2m_list_unlock(d); + altp2m_unlock(d); return rc; } @@ -XXX,XX +XXX,XX @@ int altp2m_destroy_by_id(struct domain *d, unsigned int idx) return rc; rc = -EBUSY; - altp2m_list_lock(d); + altp2m_lock(d); if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] != mfn_x(INVALID_MFN) ) @@ -XXX,XX +XXX,XX @@ int altp2m_destroy_by_id(struct domain *d, unsigned int idx) } } - altp2m_list_unlock(d); + altp2m_unlock(d); domain_unpause_except_self(d); @@ -XXX,XX +XXX,XX @@ int altp2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx) return rc; rc = -EINVAL; - altp2m_list_lock(d); + altp2m_lock(d); if ( d->arch.altp2m_visible_eptp[idx] != mfn_x(INVALID_MFN) ) { @@ -XXX,XX +XXX,XX @@ int altp2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx) rc = 0; } - altp2m_list_unlock(d); + altp2m_unlock(d); domain_unpause_except_self(d); @@ -XXX,XX +XXX,XX @@ int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, { int rc = 0; - altp2m_list_lock(d); + altp2m_lock(d); if ( !altp2m_is_eptp_valid(d, altp2m_idx) ) rc = -EINVAL; @@ -XXX,XX +XXX,XX @@ int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, d->arch.altp2m_visible_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] = mfn_x(INVALID_MFN); - altp2m_list_unlock(d); + altp2m_unlock(d); return rc; } +void altp2m_lock_init(struct domain *d) { + mm_lock_init(&d->arch.altp2m_list_lock); +} + +void altp2m_lock(struct domain *d) { + altp2m_list_lock(d); +} + +void altp2m_unlock(struct domain *d) { + altp2m_list_unlock(d); +} + /* * Local variables: * mode: C -- 2.34.1
This commit moves the init and teardown routines into common code. The functions are gated by CONFIG_X86, so there is effectively no difference despite common code normally being compiled for ARM. This commit contains only renames/code movement, and no functional change is intended. This is commit 3/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/altp2m.h | 8 ----- xen/arch/x86/mm/altp2m.c | 45 ---------------------------- xen/arch/x86/mm/p2m-basic.c | 1 + xen/common/altp2m.c | 49 +++++++++++++++++++++++++++++++ xen/include/xen/altp2m.h | 13 ++++++++ 5 files changed, 63 insertions(+), 53 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx) return true; } -/* Initialize altp2m views */ -int altp2m_init(struct domain *d); - -/* Free altp2m views */ -void altp2m_teardown(struct domain *d); - /* Switch alternate p2m for a single vcpu */ bool altp2m_switch_vcpu_by_id(struct vcpu *v, unsigned int idx); @@ -XXX,XX +XXX,XX @@ static inline int _altp2m_get_effective_entry(struct p2m_domain *ap2m, _altp2m_get_effective_entry(ap2m, gfn, mfn, t, a) /* Only declaration is needed. DCE will optimise it out when linking. */ -int altp2m_init(struct domain *d); -void altp2m_teardown(struct domain *d); struct p2m_domain *altp2m_get_altp2m(struct vcpu *v); bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx); uint16_t altp2m_vcpu_idx(const struct vcpu *v); diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ void altp2m_vcpu_disable_ve(struct vcpu *v) } } -int altp2m_init(struct domain *d) -{ - unsigned int i; - struct p2m_domain *p2m; - struct p2m_domain *hostp2m = p2m_get_hostp2m(d); - - altp2m_lock_init(d); - d->altp2m_p2m = xvzalloc_array(struct p2m_domain *, d->nr_altp2m); - - if ( !d->altp2m_p2m ) - return -ENOMEM; - - for ( i = 0; i < d->nr_altp2m; i++ ) - { - d->altp2m_p2m[i] = p2m = p2m_init_one(d); - if ( p2m == NULL ) - { - altp2m_teardown(d); - return -ENOMEM; - } - p2m->p2m_class = p2m_alternate; - p2m->access_required = hostp2m->access_required; - _atomic_set(&p2m->active_vcpus, 0); - } - - return 0; -} - -void altp2m_teardown(struct domain *d) -{ - unsigned int i; - struct p2m_domain *p2m; - - for ( i = 0; i < d->nr_altp2m; i++ ) - { - if ( !d->altp2m_p2m[i] ) - continue; - p2m = d->altp2m_p2m[i]; - d->altp2m_p2m[i] = NULL; - p2m_free_one(p2m); - } - - XVFREE(d->altp2m_p2m); -} - int altp2m_get_effective_entry(struct p2m_domain *ap2m, gfn_t gfn, mfn_t *mfn, p2m_type_t *t, p2m_access_t *a, bool prepopulate) diff --git a/xen/arch/x86/mm/p2m-basic.c b/xen/arch/x86/mm/p2m-basic.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m-basic.c +++ b/xen/arch/x86/mm/p2m-basic.c @@ -XXX,XX +XXX,XX @@ * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al. */ +#include <xen/altp2m.h> #include <xen/event.h> #include <xen/types.h> #include <asm/altp2m.h> diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <xen/altp2m.h> #include <xen/guest_access.h> #include <xen/vm_event.h> +#include <xen/xvmalloc.h> #include <asm/altp2m.h> +#include <asm/p2m.h> #include <public/hvm/params.h> @@ -XXX,XX +XXX,XX @@ #include <asm/hvm/nestedhvm.h> #endif +#if CONFIG_X86 +int altp2m_init(struct domain *d) +{ + unsigned int i; + struct p2m_domain *p2m; + struct p2m_domain *hostp2m = p2m_get_hostp2m(d); + + altp2m_lock_init(d); + d->altp2m_p2m = xvzalloc_array(struct p2m_domain *, d->nr_altp2m); + + if ( !d->altp2m_p2m ) + return -ENOMEM; + + for ( i = 0; i < d->nr_altp2m; i++ ) + { + d->altp2m_p2m[i] = p2m = p2m_init_one(d); + if ( p2m == NULL ) + { + altp2m_teardown(d); + return -ENOMEM; + } + p2m->p2m_class = p2m_alternate; + p2m->access_required = hostp2m->access_required; + _atomic_set(&p2m->active_vcpus, 0); + } + + return 0; +} + +void altp2m_teardown(struct domain *d) +{ + unsigned int i; + struct p2m_domain *p2m; + + for ( i = 0; i < d->nr_altp2m; i++ ) + { + if ( !d->altp2m_p2m[i] ) + continue; + p2m = d->altp2m_p2m[i]; + d->altp2m_p2m[i] = NULL; + p2m_free_one(p2m); + } + + XVFREE(d->altp2m_p2m); +} +#endif /* CONFIG_X86 */ + /* * altp2m operations are envisioned as being used in several different * modes: diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ #include <public/hvm/hvm_op.h> +/* + * Common alternate p2m declarations that need to be visible + * regardless of CONFIG_ALTP2M + */ + +#ifdef CONFIG_X86 +/* Initialize altp2m views */ +int altp2m_init(struct domain *d); + +/* Free altp2m views */ +void altp2m_teardown(struct domain *d); +#endif + #ifdef CONFIG_ALTP2M /* Alternate p2m HVM on/off per domain */ -- 2.34.1
This commit replaces the concrete p2m_domain member in arch_domain with a pointer to p2m_domain, which is allocated with xzalloc during p2m initialization. In the following commits, the altp2m_init and altp2m_teardown routines from x86 are be moved to common code. These routines (respectively) allocate and free the p2m_domain structs for altp2m views. While it would be possible to have special code paths for allocating/freeing altp2m views while keeping the hostp2m as an concrete member, this results in code duplication and increases complexity without any clear benefit. Therefore, switching the hostp2m to be allocated separately from arch_domain (similarly to x86) makes it possible to use the same functions for both allocation/teardown/freeing of the hostp2m and altp2m views. This is commit 4/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/arm/domain.c | 2 +- xen/arch/arm/include/asm/domain.h | 2 +- xen/arch/arm/include/asm/p2m.h | 2 +- xen/arch/arm/mm.c | 2 +- xen/arch/arm/mmu/p2m.c | 27 +++++++++++++++++++++--- xen/arch/arm/traps.c | 2 +- xen/drivers/passthrough/arm/ipmmu-vmsa.c | 2 +- xen/drivers/passthrough/arm/smmu-v3.c | 2 +- xen/drivers/passthrough/arm/smmu.c | 2 +- 9 files changed, 32 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -XXX,XX +XXX,XX @@ int domain_relinquish_resources(struct domain *d) * We are about to free the intermediate page-tables, so clear the * root to prevent any walk to use them. */ - p2m_clear_root_pages(&d->arch.p2m); + p2m_clear_root_pages(d->arch.p2m); PROGRESS(p2m): ret = p2m_teardown(d); diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/domain.h +++ b/xen/arch/arm/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct arch_domain #endif /* Virtual MMU */ - struct p2m_domain p2m; + struct p2m_domain *p2m; struct hvm_domain hvm; diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ static inline int get_page_and_type(struct page_info *page, } /* get host p2m table */ -#define p2m_get_hostp2m(d) (&(d)->arch.p2m) +#define p2m_get_hostp2m(d) ((d)->arch.p2m) static inline bool p2m_vm_event_sanity_check(struct domain *d) { diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mm.c +++ b/xen/arch/arm/mm.c @@ -XXX,XX +XXX,XX @@ bool page_is_offlinable(mfn_t mfn) unsigned long domain_get_maximum_gpfn(struct domain *d) { - return gfn_x(d->arch.p2m.max_mapped_gfn); + return gfn_x(d->arch.p2m->max_mapped_gfn); } void share_xen_page_with_guest(struct page_info *page, struct domain *d, diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mmu/p2m.c +++ b/xen/arch/arm/mmu/p2m.c @@ -XXX,XX +XXX,XX @@ #include <xen/lib.h> #include <xen/sched.h> #include <xen/softirq.h> +#include <xen/xmalloc.h> #include <asm/alternative.h> #include <asm/event.h> @@ -XXX,XX +XXX,XX @@ void p2m_final_teardown(struct domain *d) /* p2m not actually initialized */ if ( !p2m->domain ) - return; + goto free_p2m; /* * No need to call relinquish_p2m_mapping() here because @@ -XXX,XX +XXX,XX @@ void p2m_final_teardown(struct domain *d) radix_tree_destroy(&p2m->mem_access_settings, NULL); p2m->domain = NULL; + +free_p2m: + xfree(p2m); } -int p2m_init(struct domain *d) +static int p2m_initialise(struct domain *d, struct p2m_domain *p2m) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); int rc; unsigned int cpu; @@ -XXX,XX +XXX,XX @@ int p2m_init(struct domain *d) return 0; } +int p2m_init(struct domain *d) +{ + struct p2m_domain *p2m = xzalloc(struct p2m_domain); + int rc; + + if ( !p2m ) + return -ENOMEM; + + rc = p2m_initialise(d, p2m); + + if ( !rc ) + d->arch.p2m = p2m; + else + xfree(p2m); + + return rc; +} + /* * The function will go through the p2m and remove page reference when it * is required. The mapping will be removed from the p2m. diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -XXX,XX +XXX,XX @@ void vcpu_show_registers(struct vcpu *v) #endif #ifdef CONFIG_MMU - ctxt.vttbr_el2 = v->domain->arch.p2m.vttbr; + ctxt.vttbr_el2 = v->domain->arch.p2m->vttbr; #endif _show_registers(&v->arch.cpu_info->guest_cpu_user_regs, &ctxt, 1, v); diff --git a/xen/drivers/passthrough/arm/ipmmu-vmsa.c b/xen/drivers/passthrough/arm/ipmmu-vmsa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/passthrough/arm/ipmmu-vmsa.c +++ b/xen/drivers/passthrough/arm/ipmmu-vmsa.c @@ -XXX,XX +XXX,XX @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) * Use P2M table for this Xen domain. */ ASSERT(domain->d != NULL); - ttbr = page_to_maddr(domain->d->arch.p2m.root); + ttbr = page_to_maddr(domain->d->arch.p2m->root); dev_info(domain->mmu->root->dev, "%pd: Set IPMMU context %u (pgd 0x%"PRIx64")\n", domain->d, domain->context_id, ttbr); diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/passthrough/arm/smmu-v3.c +++ b/xen/drivers/passthrough/arm/smmu-v3.c @@ -XXX,XX +XXX,XX @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, vtcr->tsz = 64 - p2m_ipa_bits; vtcr->sl = 2 - P2M_ROOT_LEVEL; - arm_lpae_s2_cfg.vttbr = page_to_maddr(smmu_domain->d->arch.p2m.root); + arm_lpae_s2_cfg.vttbr = page_to_maddr(smmu_domain->d->arch.p2m->root); vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits); if (vmid < 0) diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/passthrough/arm/smmu.c +++ b/xen/drivers/passthrough/arm/smmu.c @@ -XXX,XX +XXX,XX @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) /* TTBR0 */ /* Xen: The page table is shared with the P2M code */ ASSERT(smmu_domain->cfg.domain != NULL); - p2maddr = page_to_maddr(smmu_domain->cfg.domain->arch.p2m.root); + p2maddr = page_to_maddr(smmu_domain->cfg.domain->arch.p2m->root); dev_notice(smmu->dev, "d%u: p2maddr 0x%"PRIpaddr"\n", smmu_domain->cfg.domain->domain_id, p2maddr); -- 2.34.1
From: Sergej Proskurin <proskurin@sec.in.tum.de> In ./xen/arch/arm/p2m.c, we compare the gfn's with INVALID_GFN throughout the code. Thus it makes sense to use the macro INVALID_GFN instead of a hard coded value to initialize "p2m->lowest_mapped_gfn". This is commit 5/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> --- xen/arch/arm/mmu/p2m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mmu/p2m.c +++ b/xen/arch/arm/mmu/p2m.c @@ -XXX,XX +XXX,XX @@ static int p2m_initialise(struct domain *d, struct p2m_domain *p2m) p2m->vmid = INVALID_VMID; p2m->max_mapped_gfn = _gfn(0); - p2m->lowest_mapped_gfn = _gfn(ULONG_MAX); + p2m->lowest_mapped_gfn = INVALID_GFN; p2m->default_access = p2m_access_rwx; p2m->mem_access_enabled = false; -- 2.34.1
This commit pulls out generic init/teardown functionality out of "p2m_init" and "p2m_teardown" into "p2m_init_one", "p2m_teardown_one", "p2m_free_one", and "p2m_flush_table" functions. This allows our future implementation to reuse existing code for the initialization/teardown of altp2m views. On failure, the p2m_init_one function returns a null pointer. This means p2m_init_one doesn't return an error code, which prevents it from propagating the exact error from p2m_initialise (specifically, ENOMEM if allocation fails and EBUSY if the VMID pool is exhausted). However, returning a p2m_domain pointer simplifies usage for callers of p2m_init_one, as they can receive an allocated and initialized p2m_domain without needing to handle allocation separately. Therefore, the main p2m_init function will now return ENOMEM instead of EBUSY when the VMID pool is exhausted. This is commit 6/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> --- Cc: Stefano Stabellini <sstabellini@kernel.org> Cc: Julien Grall <julien.grall@arm.com> --- v2: Added the function p2m_flush_table to the previous version. v3: Removed struct vttbr. Moved define INVALID_VTTBR to p2m.h. Exported function prototypes of "p2m_flush_table", "p2m_init_one", and "p2m_teardown_one" in p2m.h. Extended the function "p2m_flush_table" by additionally resetting the fields lowest_mapped_gfn and max_mapped_gfn. Added a "p2m_flush_tlb" call in "p2m_flush_table". On altp2m reset in function "altp2m_reset", it is important to flush the TLBs after clearing the root table pages and before clearing the intermediate altp2m page tables to prevent illegal access to stalled TLB entries on currently active VCPUs. Added a check checking whether p2m->root is NULL in p2m_flush_table. Renamed the function "p2m_free_one" to "p2m_teardown_one". Removed resetting p2m->vttbr in "p2m_teardown_one", as it the p2m will be destroyed afterwards. Moved call to "p2m_alloc_table" back to "p2m_init_one". Moved the introduction of the type p2m_class_t out of this patch. Moved the backpointer to the struct domain out of the struct p2m_domain. v4: Replaced the former use of clear_and_clean_page in p2m_flush_table by a routine that invalidates every p2m entry atomically. This avoids inconsistencies on CPUs that continue to use the views that are to be flushed (e.g., see altp2m_reset). Removed unnecessary initializations in the functions "p2m_init_one" and "p2m_teardown_one". Removed the define INVALID_VTTBR as it is not used any more. Cosmetic fixes. v6: Reworked to accommodate the hostp2m being allocated separately from arch_domain. Split p2m_teardown_one into p2m_teardown_one and p2m_free_one, with both having the same semantics as their x86 counterparts. The previous version of this patch also added code to p2m_flush_table. This has been split out into a separate commit to minimize the number of actual changes in this commit. Updated to account for the introduction of p2m_final_teardown. The code which previously was used to reclaim resources from the hostp2m during p2m_final_teardown was extracted into p2m_free_one. Now, p2m_final_teardown will call p2m_free_one on the hostp2m instead. The check for whether the p2m was actually initialized was moved into p2m_free_one. This means there is a slight behavior change where p2m_teardown_allocation will always be called, even if the p2m_domain was never initialized. I'm not sure if this is really a big deal (it does require the lock to be obtained, but this shouldn't be an issue at final teardown?), but if it is then I can duplicate the check from p2m_free_one to the top of p2m_final_teardown, which would replicate the previous behavior. For the sake of making the p2m_init_one function simple to use (and match the x86 function prototype), it returns a null pointer on error rather than an error code. While on x86 an error from p2m_init_one is always due to an ENOMEM return code (from xzalloc, zalloc_cpumask_var), on ARM p2m_initialise (called by p2m_init_one) can actually return EBUSY if the VMID pool is exhausted. Therefore, in this error case the null pointer return value of p2m_init_one obscures the true error code (EBUSY). Callers of p2m_init_one always return ENOMEM when p2m_init_one returns a null pointer, so this error will be propagated up as ENOMEM rather than EBUSY. The alternative to this would be to have callers pass a null **p2m_domain to p2m_init_one while still returning an integer return code. In order to preserve a common altp2m_init routine, this change would also have to be made on x86 (where there wouldn't be any real benefit, the return code is truly only ever ENOMEM). Therefore, it seems like an acceptable tradeoff to me to obscure the error in this case, but if other folks think we should handle this differently than I can revisit this. The p2m_teardown_allocation call and p2m_init_one return code changes mentioned above should be the only actual behavior changes in this patch, otherwise it should be just code movement. --- xen/arch/arm/include/asm/p2m.h | 12 ++++++ xen/arch/arm/mmu/p2m.c | 77 +++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ int p2m_init(struct domain *d); int p2m_teardown(struct domain *d); void p2m_final_teardown(struct domain *d); +/* Flushes the page table held by the p2m. */ +int p2m_flush_table(struct p2m_domain *p2m); + +/* Initialize the p2m structure. */ +struct p2m_domain *p2m_init_one(struct domain *d); + +/* Release resources held by the p2m structure. */ +int p2m_teardown_one(struct p2m_domain *p2m); + +/* Free the p2m structure allocation. */ +void p2m_free_one(struct p2m_domain *p2m); + /* * Remove mapping refcount on each mapping page in the p2m * diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mmu/p2m.c +++ b/xen/arch/arm/mmu/p2m.c @@ -XXX,XX +XXX,XX @@ static int p2m_alloc_table(struct domain *d) return 0; } -int p2m_teardown(struct domain *d) +int p2m_flush_table(struct p2m_domain *p2m) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); unsigned long count = 0; struct page_info *pg; - int rc = 0; - - p2m_write_lock(p2m); while ( (pg = page_list_remove_head(&p2m->pages)) ) { @@ -XXX,XX +XXX,XX @@ int p2m_teardown(struct domain *d) /* Arbitrarily preempt every 512 iterations */ if ( !(count % 512) && hypercall_preempt_check() ) { - rc = -ERESTART; - break; + return -ERESTART; } } + return 0; +} + +int p2m_teardown_one(struct p2m_domain *p2m) +{ + int rc; + + p2m_write_lock(p2m); + rc = p2m_flush_table(p2m); p2m_write_unlock(p2m); return rc; } -void p2m_final_teardown(struct domain *d) +int p2m_teardown(struct domain *d) { struct p2m_domain *p2m = p2m_get_hostp2m(d); - /* p2m not actually initialized */ - if ( !p2m->domain ) - goto free_p2m; + return p2m_teardown_one(p2m); +} + +void p2m_final_teardown(struct domain *d) +{ + struct p2m_domain *p2m = p2m_get_hostp2m(d); /* * No need to call relinquish_p2m_mapping() here because @@ -XXX,XX +XXX,XX @@ void p2m_final_teardown(struct domain *d) * where relinquish_p2m_mapping() has been called. */ - ASSERT(page_list_empty(&p2m->pages)); - while ( p2m_teardown_allocation(d) == -ERESTART ) continue; /* No preemption support here */ ASSERT(page_list_empty(&d->arch.paging.p2m_freelist)); + p2m_free_one(p2m); +} + +void p2m_free_one(struct p2m_domain *p2m) +{ + /* p2m not actually initialized */ + if ( !p2m->domain ) + goto free_p2m; + + ASSERT(page_list_empty(&p2m->pages)); + if ( p2m->root ) free_domheap_pages(p2m->root, P2M_ROOT_ORDER); p2m->root = NULL; - p2m_free_vmid(d); + p2m_free_vmid(p2m->domain); radix_tree_destroy(&p2m->mem_access_settings, NULL); @@ -XXX,XX +XXX,XX @@ static int p2m_initialise(struct domain *d, struct p2m_domain *p2m) unsigned int cpu; rwlock_init(&p2m->lock); - spin_lock_init(&d->arch.paging.lock); INIT_PAGE_LIST_HEAD(&p2m->pages); - INIT_PAGE_LIST_HEAD(&d->arch.paging.p2m_freelist); p2m->vmid = INVALID_VMID; p2m->max_mapped_gfn = _gfn(0); @@ -XXX,XX +XXX,XX @@ static int p2m_initialise(struct domain *d, struct p2m_domain *p2m) return 0; } -int p2m_init(struct domain *d) +struct p2m_domain *p2m_init_one(struct domain *d) { struct p2m_domain *p2m = xzalloc(struct p2m_domain); - int rc; + + if ( !p2m ) + return NULL; + + if ( !p2m_initialise(d, p2m) ) + return p2m; + + xfree(p2m); + return NULL; +} + +static int p2m_init_hostp2m(struct domain *d) +{ + struct p2m_domain *p2m = p2m_init_one(d); if ( !p2m ) return -ENOMEM; - rc = p2m_initialise(d, p2m); + d->arch.p2m = p2m; + return 0; +} - if ( !rc ) - d->arch.p2m = p2m; - else - xfree(p2m); +int p2m_init(struct domain *d) +{ + spin_lock_init(&d->arch.paging.lock); + INIT_PAGE_LIST_HEAD(&d->arch.paging.p2m_freelist); - return rc; + return p2m_init_hostp2m(d); } /* -- 2.34.1
This commit invalidates the root page table entries and flushes the TLB when the table is flushed. The TLB is flushed to ensure that altp2m views after being reset or torn down. Previously, the code in p2m_flush_table was only used to free p2m pages during domain teardown. This function will later be used to teardown/reset altp2m views of a still-running domain, so the page table entries must be properly invalidated. Additionally, the p2m_invalidate_root function is split into p2m_invalidate_root and p2m_invalidate_root_locked. The p2m_flush_table function already holds the lock, so it calls p2m_invalidate_root_locked directly, as opposed to the existing callers which don't already hold the lock. This is commit 7/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> --- v3: Added a "p2m_flush_tlb" call in "p2m_flush_table". On altp2m reset in function "altp2m_reset", it is important to flush the TLBs after clearing the root table pages and before clearing the intermediate altp2m page tables to prevent illegal access to stalled TLB entries on currently active VCPUs. v4: Replaced the former use of clear_and_clean_page in p2m_flush_table by a routine that invalidates every p2m entry atomically. This avoids inconsistencies on CPUs that continue to use the views that are to be flushed (e.g., see altp2m_reset). v6: Introduced this patch. While the code in this patch is mostly new, it is the same in spirit as the p2m_flush_table additions in the original patch series, so the relevant comments have been reproduced above. In the v4/v5 versions of this patch series, this patch was a part of the previous patch. It has been split out to minimize the number of functionality changes in the previous patch. Additionally, the original patch series used a routine here which was nearly identical to p2m_invalidate_root, which was implemented a few years after the patch series. Therefore, the existing p2m_invalidate_root implementation is used here instead. Also, since the original patch series p2m_teardown (and by extension p2m_flush_table, as it was extracted from p2m_teardown) was made preemptible. As a consequence of this, introducing a call to p2m_invalidate_root here also means that p2m_invalidate_root and p2m_tlb_flush_sync is called each time p2m_flush_table is called, even if a previous call to p2m_flush_table was preempted. This might cause some additional overhead, as p2m_flush_table will iterate over the root page tables and flush the TLB before it can return to freeing p2m pages. I'm not sure if there's a better way of handling this, or if the overhead here is negligible/acceptable. I'm not sure how IOMMU interacts with altp2m here. I haven't looked into it extensively, so I would appreciate some feedback here. I've just copied over the iommu_use_hap_pt conditional from p2m_domain_creation_finished, but this is probably not the right behavior since we probably still need to invalidate the altp2m view page tables on flush somehow. Is the issue with invalidating root page tables when using IOMMU only relevant for the hostp2m, or is it also relevant for the altp2m views? --- xen/arch/arm/mmu/p2m.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mmu/p2m.c +++ b/xen/arch/arm/mmu/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_clear_root_pages(struct p2m_domain *p2m) * p2m_invalid_root() should not be called when the P2M is shared with * the IOMMU because it will cause IOMMU fault. */ -static void p2m_invalidate_root(struct p2m_domain *p2m) +static void p2m_invalidate_root_locked(struct p2m_domain *p2m) { unsigned int i; ASSERT(!iommu_use_hap_pt(p2m->domain)); - p2m_write_lock(p2m); - for ( i = 0; i < P2M_ROOT_PAGES; i++ ) p2m_invalidate_table(p2m, page_to_mfn(p2m->root + i)); +} +static void p2m_invalidate_root(struct p2m_domain *p2m) +{ + p2m_write_lock(p2m); + p2m_invalidate_root_locked(p2m); p2m_write_unlock(p2m); } @@ -XXX,XX +XXX,XX @@ int p2m_flush_table(struct p2m_domain *p2m) unsigned long count = 0; struct page_info *pg; + /* TODO: How does IOMMU interact with altp2m? */ + if ( !iommu_use_hap_pt(p2m->domain) ) + { + p2m_invalidate_root_locked(p2m); + p2m_tlb_flush_sync(p2m); + } + while ( (pg = page_list_remove_head(&p2m->pages)) ) { p2m_free_page(p2m->domain, pg); -- 2.34.1
From: Sergej Proskurin <proskurin@sec.in.tum.de> The function "p2m_alloc_table" should be able to allocate 2nd stage translation tables not only for the host's p2m but also for alternate p2m's. This commit is a refactor and contains no functional changes. This is commit 8/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> Acked-by: Julien Grall <julien.grall@arm.com> --- v2: Removed altp2m table initialization from "p2m_table_init". v3: Removed initialization of the field d->arch.altp2m_active in "p2m_table_init" to avoid altp2m initialization throughout different files. Merged the function "p2m_alloc_table" and "p2m_table_init". --- xen/arch/arm/mmu/p2m.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mmu/p2m.c +++ b/xen/arch/arm/mmu/p2m.c @@ -XXX,XX +XXX,XX @@ static struct page_info *p2m_allocate_root(void) return page; } -static int p2m_alloc_table(struct domain *d) +static int p2m_alloc_table(struct p2m_domain *p2m) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); - p2m->root = p2m_allocate_root(); if ( !p2m->root ) return -ENOMEM; @@ -XXX,XX +XXX,XX @@ static int p2m_initialise(struct domain *d, struct p2m_domain *p2m) if ( rc ) return rc; - rc = p2m_alloc_table(d); + rc = p2m_alloc_table(p2m); if ( rc ) return rc; -- 2.34.1
From: Sergej Proskurin <proskurin@sec.in.tum.de> This commit does not change or introduce any additional functionality but rather is a part of the following commit that alters the functionality of the function "p2m_alloc_vmid". This is commit 9/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> --- xen/arch/arm/p2m.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -XXX,XX +XXX,XX @@ int p2m_alloc_vmid(struct domain *d) { struct p2m_domain *p2m = p2m_get_hostp2m(d); - int rc, nr; + int rc, vmid; spin_lock(&vmid_alloc_lock); - nr = find_first_zero_bit(vmid_mask, MAX_VMID); + vmid = find_first_zero_bit(vmid_mask, MAX_VMID); - ASSERT(nr != INVALID_VMID); + ASSERT(vmid != INVALID_VMID); - if ( nr == MAX_VMID ) + if ( vmid == MAX_VMID ) { rc = -EBUSY; printk(XENLOG_ERR "p2m.c: dom%d: VMID pool exhausted\n", d->domain_id); goto out; } - set_bit(nr, vmid_mask); + set_bit(vmid, vmid_mask); - p2m->vmid = nr; + p2m->vmid = vmid; rc = 0; -- 2.34.1
From: Sergej Proskurin <proskurin@sec.in.tum.de> This commit changes the prototype and implementation of the functions "p2m_alloc_vmid" and "p2m_free_vmid". The function "p2m_alloc_vmid" does not expect the struct domain as argument anymore and returns an allocated vmid. The function "p2m_free_vmid" takes only the vmid that is to be freed as argument. This is commit 10/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> --- v3: Changed function prototypes and implementation of the functions "p2m_alloc_vmid" and "p2m_free_vmid". Changes in "p2m_alloc_vmid": This function does not expect any arguments. Also, in this commit, the function "p2m_alloc_vmid" returns either the successfully allocated vmid or the value INVALID_VMID. Thus, it is now the responsibility of the caller to set the returned vmid in the associated fields. Changes in "p2m_free_vmid": This function expects now only the vmid of type uint8_t. --- xen/arch/arm/include/asm/p2m.h | 4 ++-- xen/arch/arm/mmu/p2m.c | 8 ++++---- xen/arch/arm/p2m.c | 23 ++++++++--------------- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ static inline bool arch_acquire_resource_check(struct domain *d) void p2m_restrict_ipa_bits(unsigned int ipa_bits); void p2m_vmid_allocator_init(void); -int p2m_alloc_vmid(struct domain *d); -void p2m_free_vmid(struct domain *d); +uint8_t p2m_alloc_vmid(void); +void p2m_free_vmid(uint8_t vmid); /* Second stage paging setup, to be called on all CPUs */ void setup_virt_paging(void); diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mmu/p2m.c +++ b/xen/arch/arm/mmu/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_free_one(struct p2m_domain *p2m) p2m->root = NULL; - p2m_free_vmid(p2m->domain); + p2m_free_vmid(p2m->vmid); radix_tree_destroy(&p2m->mem_access_settings, NULL); @@ -XXX,XX +XXX,XX @@ static int p2m_initialise(struct domain *d, struct p2m_domain *p2m) */ p2m->domain = d; - rc = p2m_alloc_vmid(d); - if ( rc ) - return rc; + p2m->vmid = p2m_alloc_vmid(); + if ( p2m->vmid == INVALID_VMID ) + return -EBUSY; rc = p2m_alloc_table(p2m); if ( rc ) diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_vmid_allocator_init(void) set_bit(INVALID_VMID, vmid_mask); } -int p2m_alloc_vmid(struct domain *d) +uint8_t p2m_alloc_vmid(void) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); - - int rc, vmid; + uint8_t vmid; spin_lock(&vmid_alloc_lock); @@ -XXX,XX +XXX,XX @@ int p2m_alloc_vmid(struct domain *d) if ( vmid == MAX_VMID ) { - rc = -EBUSY; - printk(XENLOG_ERR "p2m.c: dom%d: VMID pool exhausted\n", d->domain_id); + vmid = INVALID_VMID; + printk(XENLOG_ERR "p2m.c: VMID pool exhausted\n"); goto out; } set_bit(vmid, vmid_mask); - p2m->vmid = vmid; - - rc = 0; - out: spin_unlock(&vmid_alloc_lock); - return rc; + return vmid; } -void p2m_free_vmid(struct domain *d) +void p2m_free_vmid(uint8_t vmid) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); spin_lock(&vmid_alloc_lock); - if ( p2m->vmid != INVALID_VMID ) - clear_bit(p2m->vmid, vmid_mask); + if ( vmid != INVALID_VMID ) + clear_bit(vmid, vmid_mask); spin_unlock(&vmid_alloc_lock); } -- 2.34.1
From: Sergej Proskurin <proskurin@sec.in.tum.de> This commit adds a p2m class to the struct p2m_domain to distinguish between the host's original p2m and alternate p2m's. The need for this functionality will be shown in the following commits. This is commit 11/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> --- v4: Change return type of p2m_is_(hostp2m|altp2m) from bool_t to bool. --- xen/arch/arm/include/asm/p2m.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ struct domain; extern void memory_type_changed(struct domain *d); +typedef enum { + p2m_host, + p2m_alternate, +} p2m_class_t; + /* Per-p2m-table state */ struct p2m_domain { /* @@ -XXX,XX +XXX,XX @@ struct p2m_domain { /* Keeping track on which CPU this p2m was used and for which vCPU */ uint8_t last_vcpu_ran[NR_CPUS]; + + /* Choose between: host/alternate. */ + p2m_class_t p2m_class; }; /* @@ -XXX,XX +XXX,XX @@ static inline int get_page_and_type(struct page_info *page, /* get host p2m table */ #define p2m_get_hostp2m(d) ((d)->arch.p2m) +static inline bool p2m_is_hostp2m(const struct p2m_domain *p2m) +{ + return p2m->p2m_class == p2m_host; +} + +static inline bool p2m_is_altp2m(const struct p2m_domain *p2m) +{ + return p2m->p2m_class == p2m_alternate; +} + static inline bool p2m_vm_event_sanity_check(struct domain *d) { return true; -- 2.34.1
The p2m initialization now invokes initialization routines responsible for the allocation and initialization of altp2m structures. The same applies to teardown routines. This commit adds the prerequisites for the common altp2m_init and altp2m_teardown functions to work on ARM; No further changes were necessary other than removing the CONFIG_X86 gating. This is commit 12/12 of the altp2m_init/altp2m_teardown routines phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> Signed-off-by: Aqib Javaid <Aqib.Javaid@elektrobit.com> --- v2: Shared code between host/altp2m init/teardown functions. Added conditional init/teardown of altp2m. Altp2m related functions are moved to altp2m.c v3: Removed locking the altp2m_lock in altp2m_teardown. Locking this lock at this point is unnecessary. Removed re-setting altp2m_vttbr, altp2m_p2m, and altp2m_active values in the function "altp2m_teardown". Re-setting these values is unnecessary as the entire domain will be destroyed right afterwards. Removed check for "altp2m_enabled" in "p2m_init" as altp2m has not yet been enabled by libxl at this point. Removed check for "altp2m_enabled" before tearing down altp2m within the function "p2m_teardown" so that altp2m gets destroyed even if the HVM_PARAM_ALTP2M gets reset before "p2m_teardown" is called. Added initialization of the field d->arch.altp2m_active in "altp2m_init". Removed check for already initialized vmid's in "altp2m_init_one", as "altp2m_init_one" is now called always with an uninitialized p2m. Removed the array altp2m_vttbr[] in struct arch_domain. v4: Removed initialization of altp2m_p2m[] to NULL in altp2m_init, as the "struct arch_domain" is already initialized to zero. We moved the definition of the macro MAX_ALTP2M to a common place in a separate commit. v6: Reworked to use common altp2m init and teardown routines. Added altp2m_lock_init macro for use in altp2m_init. Split altp2m initialization in p2m_init into a separate function, p2m_init_altp2m, to more easily gate code behind CONFIG_ALTP2M. Pulled in addition of active_vcpus from a later patch in the patch series. Split teardown and free of altp2m views into p2m_teardown and p2m_teardown_final (part of altp2m_teardown), respectively. --- xen/arch/arm/include/asm/altp2m.h | 4 +++ xen/arch/arm/include/asm/domain.h | 8 ++++++ xen/arch/arm/include/asm/p2m.h | 5 ++++ xen/arch/arm/mmu/p2m.c | 44 ++++++++++++++++++++++++++++++- xen/common/altp2m.c | 2 -- xen/include/xen/altp2m.h | 2 -- 6 files changed, 60 insertions(+), 5 deletions(-) diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_supported(void) return true; } +#define altp2m_lock_init(d) spin_lock_init(&(d)->arch.altp2m_lock) +#define altp2m_lock(d) spin_lock(&(d)->arch.altp2m_lock) +#define altp2m_unlock(d) spin_unlock(&(d)->arch.altp2m_lock) + /* Alternate p2m VCPU */ static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) { diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/domain.h +++ b/xen/arch/arm/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct arch_domain #endif struct resume_info resume_ctx; + +#ifdef CONFIG_ALTP2M + /* + * Lock that protects critical altp2m operations that must not be performed + * concurrently. + */ + spinlock_t altp2m_lock; +#endif } __cacheline_aligned; struct arch_vcpu diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ #include <asm/current.h> #include <asm/hsr.h> +#include <asm/atomic.h> + #define paddr_bits PADDR_BITS /* Holds the bit size of IPAs in p2m tables. */ @@ -XXX,XX +XXX,XX @@ struct p2m_domain { /* Keeping track on which CPU this p2m was used and for which vCPU */ uint8_t last_vcpu_ran[NR_CPUS]; + /* Alternate p2m: count of vcpu's currently using this p2m. */ + atomic_t active_vcpus; + /* Choose between: host/alternate. */ p2m_class_t p2m_class; }; diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mmu/p2m.c +++ b/xen/arch/arm/mmu/p2m.c @@ -XXX,XX +XXX,XX @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include <xen/altp2m.h> #include <xen/cpu.h> #include <xen/domain_page.h> #include <xen/ioreq.h> @@ -XXX,XX +XXX,XX @@ #include <xen/softirq.h> #include <xen/xmalloc.h> +#include <asm/altp2m.h> #include <asm/alternative.h> #include <asm/event.h> #include <asm/flushtlb.h> @@ -XXX,XX +XXX,XX @@ int p2m_teardown(struct domain *d) { struct p2m_domain *p2m = p2m_get_hostp2m(d); +#ifdef CONFIG_ALTP2M + unsigned int i; + int rc; + + d->altp2m_active = false; + + for ( i = 0; i < d->nr_altp2m; i++ ) + { + rc = p2m_teardown_one(d->altp2m_p2m[i]); + if ( rc ) + return rc; + } +#endif + return p2m_teardown_one(p2m); } @@ -XXX,XX +XXX,XX @@ void p2m_final_teardown(struct domain *d) * where relinquish_p2m_mapping() has been called. */ + if ( altp2m_supported() ) + altp2m_teardown(d); + while ( p2m_teardown_allocation(d) == -ERESTART ) continue; /* No preemption support here */ ASSERT(page_list_empty(&d->arch.paging.p2m_freelist)); @@ -XXX,XX +XXX,XX @@ struct p2m_domain *p2m_init_one(struct domain *d) return NULL; } +static int p2m_init_altp2m(struct domain *d) +{ +#ifdef CONFIG_ALTP2M + int rc; + + rc = altp2m_init(d); + if ( rc ) + { + p2m_free_one(p2m_get_hostp2m(d)); + return rc; + } + + d->altp2m_active = false; +#endif + + return 0; +} + static int p2m_init_hostp2m(struct domain *d) { struct p2m_domain *p2m = p2m_init_one(d); @@ -XXX,XX +XXX,XX @@ static int p2m_init_hostp2m(struct domain *d) int p2m_init(struct domain *d) { + int rc; spin_lock_init(&d->arch.paging.lock); INIT_PAGE_LIST_HEAD(&d->arch.paging.p2m_freelist); - return p2m_init_hostp2m(d); + rc = p2m_init_hostp2m(d); + if ( rc ) + return rc; + + return p2m_init_altp2m(d); } /* diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <asm/hvm/nestedhvm.h> #endif -#if CONFIG_X86 int altp2m_init(struct domain *d) { unsigned int i; @@ -XXX,XX +XXX,XX @@ void altp2m_teardown(struct domain *d) XVFREE(d->altp2m_p2m); } -#endif /* CONFIG_X86 */ /* * altp2m operations are envisioned as being used in several different diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ * regardless of CONFIG_ALTP2M */ -#ifdef CONFIG_X86 /* Initialize altp2m views */ int altp2m_init(struct domain *d); /* Free altp2m views */ void altp2m_teardown(struct domain *d); -#endif #ifdef CONFIG_ALTP2M -- 2.34.1
This commit moves the altp2m_get_altp2m and altp2m_set_altp2m functions to the common code. This make sit possible to use them in other common routines (namely, altp2m_vcpu_{initialise,destroy}). This commit contains only code movement, and no change in functionality is intended. This is commit 1/4 of the altp2m_{get,set}_altp2m phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/altp2m.h | 35 ------------------------- xen/arch/x86/include/asm/domain.h | 2 -- xen/common/altp2m.c | 1 - xen/include/xen/altp2m.h | 43 +++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) * Alternate p2m: shadow p2m tables used for alternate memory views */ -/* get current alternate p2m table */ -static inline struct p2m_domain *altp2m_get_altp2m(struct vcpu *v) -{ - unsigned int index = vcpu_altp2m(v).p2midx; - - if ( index == INVALID_ALTP2M ) - return NULL; - - BUG_ON(index >= v->domain->nr_altp2m); - - return v->domain->altp2m_p2m[index]; -} - -/* set current alternate p2m table */ -static inline bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx) -{ - struct p2m_domain *orig; - - BUG_ON(idx >= v->domain->nr_altp2m); - - if ( idx == vcpu_altp2m(v).p2midx ) - return false; - - orig = altp2m_get_altp2m(v); - BUG_ON(!orig); - atomic_dec(&orig->active_vcpus); - - vcpu_altp2m(v).p2midx = idx; - atomic_inc(&v->domain->altp2m_p2m[idx]->active_vcpus); - - return true; -} - /* Switch alternate p2m for a single vcpu */ bool altp2m_switch_vcpu_by_id(struct vcpu *v, unsigned int idx); @@ -XXX,XX +XXX,XX @@ static inline int _altp2m_get_effective_entry(struct p2m_domain *ap2m, _altp2m_get_effective_entry(ap2m, gfn, mfn, t, a) /* Only declaration is needed. DCE will optimise it out when linking. */ -struct p2m_domain *altp2m_get_altp2m(struct vcpu *v); -bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx); uint16_t altp2m_vcpu_idx(const struct vcpu *v); void altp2m_vcpu_initialise(struct vcpu *v); void altp2m_vcpu_destroy(struct vcpu *v); diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/domain.h +++ b/xen/arch/x86/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct paging_vcpu { #define MAX_NR_ALTP2M MAX_EPTP #define MAX_NESTEDP2M 10 -#define INVALID_ALTP2M 0xffff - struct p2m_domain; struct time_scale { int shift; diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <xen/xvmalloc.h> #include <asm/altp2m.h> -#include <asm/p2m.h> #include <public/hvm/params.h> diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ #include <public/hvm/hvm_op.h> +#include <asm/p2m.h> + +#define INVALID_ALTP2M 0xffff + /* * Common alternate p2m declarations that need to be visible * regardless of CONFIG_ALTP2M @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_active(const struct domain *d) return d->altp2m_active; } +#ifdef CONFIG_X86 +/* get current alternate p2m table */ +static inline struct p2m_domain *altp2m_get_altp2m(struct vcpu *v) +{ + unsigned int index = vcpu_altp2m(v).p2midx; + + if ( index == INVALID_ALTP2M ) + return NULL; + + BUG_ON(index >= v->domain->nr_altp2m); + + return v->domain->altp2m_p2m[index]; +} + +/* set current alternate p2m table */ +static inline bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx) +{ + struct p2m_domain *orig; + + BUG_ON(idx >= v->domain->nr_altp2m); + + if ( idx == vcpu_altp2m(v).p2midx ) + return false; + + orig = altp2m_get_altp2m(v); + BUG_ON(!orig); + atomic_dec(&orig->active_vcpus); + + vcpu_altp2m(v).p2midx = idx; + atomic_inc(&v->domain->altp2m_p2m[idx]->active_vcpus); + + return true; +} +#endif + int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg); #else /* CONFIG_ALTP2M */ @@ -XXX,XX +XXX,XX @@ static inline int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg) return -EOPNOTSUPP; } +/* Only declaration is needed. DCE will optimise it out when linking. */ +struct p2m_domain *altp2m_get_altp2m(struct vcpu *v); +bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx); + #endif /* CONFIG_ALTP2M */ #endif /* __XEN_ALTP2M_H__ */ -- 2.34.1
This commit adds ap2m_idx to the VCPU struct on ARM. This makes it possible to track the current altp2m view being used by a VCPU. This is commit 2/4 of the altp2m_{get,set}_altp2m phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de> --- v6: This patch was originally part of the "arm/p2m: Add HVMOP_altp2m_set_domain_state" patch from the v4/v5 patch series. It has been extracted into its own commit to make the patch series easier to follow. If it would be preferred, this commit can be squashed into another commit. Added support for the CONFIG_ALTP2M option. --- xen/arch/arm/include/asm/altp2m.h | 4 +--- xen/arch/arm/include/asm/domain.h | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_supported(void) /* Alternate p2m VCPU */ static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) { - /* Not implemented yet */ - BUG(); - return 0; + return v->arch.ap2m_idx; } #else /* CONFIG_ALTP2M */ diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/domain.h +++ b/xen/arch/arm/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct arch_vcpu struct vtimer virt_timer; bool vtimer_initialized; +#if CONFIG_ALTP2M + /* Alternate p2m index */ + uint16_t ap2m_idx; +#endif + /* * The full P2M may require some cleaning (e.g when emulation * set/way). As the action can take a long time, it requires -- 2.34.1
This commit adds the altp2m_set_vcpu_idx function for both x86 and ARM. Since the altp2m VCPU index is stored differently depending on which architecture is used, the altp2m_set_vcpu_idx function makes it possible to set this value in an architecture independent way for common code routines. This is commit 3/4 of the altp2m_{get,set}_altp2m phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/arm/include/asm/altp2m.h | 5 +++++ xen/arch/x86/include/asm/altp2m.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) return v->arch.ap2m_idx; } +static inline void altp2m_set_vcpu_idx(struct vcpu *v, unsigned int idx) +{ + v->arch.ap2m_idx = idx; +} + #else /* CONFIG_ALTP2M */ static inline bool altp2m_supported(void) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) return vcpu_altp2m(v).p2midx; } +static inline void altp2m_set_vcpu_idx(struct vcpu *v, unsigned int idx) +{ + vcpu_altp2m(v).p2midx = idx; +} + /* * Alternate p2m: shadow p2m tables used for alternate memory views */ -- 2.34.1
This commit adds support for altp2m_get_altp2m and altp2m_set_altp2m on ARM. The x86-specific VCPU accesses have been replaced with the architecture independent functions altp2m_vcpu_idx and altp2m_set_vcpu_idx. This is commit 4/4 of the altp2m_{get,set}_altp2m phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/include/xen/altp2m.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ #include <public/hvm/hvm_op.h> +#include <asm/altp2m.h> #include <asm/p2m.h> #define INVALID_ALTP2M 0xffff @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_active(const struct domain *d) return d->altp2m_active; } -#ifdef CONFIG_X86 /* get current alternate p2m table */ static inline struct p2m_domain *altp2m_get_altp2m(struct vcpu *v) { - unsigned int index = vcpu_altp2m(v).p2midx; + unsigned int index = altp2m_vcpu_idx(v); if ( index == INVALID_ALTP2M ) return NULL; @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx) BUG_ON(idx >= v->domain->nr_altp2m); - if ( idx == vcpu_altp2m(v).p2midx ) + if ( idx == altp2m_vcpu_idx(v) ) return false; orig = altp2m_get_altp2m(v); BUG_ON(!orig); atomic_dec(&orig->active_vcpus); - vcpu_altp2m(v).p2midx = idx; + altp2m_set_vcpu_idx(v, idx); atomic_inc(&v->domain->altp2m_p2m[idx]->active_vcpus); return true; } -#endif int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg); -- 2.34.1
This commit moves the altp2m_vcpu_initialise and altp2m_vcpu_destroy functions to common code. This makes it possible to use them in the common implementation of HVMOP_altp2m_set_domain_state. This commit contains only code movement, and no change in functionality is intended. This is commit 1/2 of the altp2m_vcpu_{initialise,destroy} phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/altp2m.h | 6 ----- xen/arch/x86/mm/altp2m.c | 41 ------------------------------- xen/common/altp2m.c | 41 +++++++++++++++++++++++++++++++ xen/include/xen/altp2m.h | 6 +++++ 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ int altp2m_get_effective_entry(struct p2m_domain *ap2m, gfn_t gfn, mfn_t *mfn, p2m_type_t *t, p2m_access_t *a, bool prepopulate); -/* Alternate p2m VCPU */ -void altp2m_vcpu_initialise(struct vcpu *v); -void altp2m_vcpu_destroy(struct vcpu *v); - int altp2m_vcpu_enable_ve(struct vcpu *v, gfn_t gfn); void altp2m_vcpu_disable_ve(struct vcpu *v); @@ -XXX,XX +XXX,XX @@ static inline int _altp2m_get_effective_entry(struct p2m_domain *ap2m, /* Only declaration is needed. DCE will optimise it out when linking. */ uint16_t altp2m_vcpu_idx(const struct vcpu *v); -void altp2m_vcpu_initialise(struct vcpu *v); -void altp2m_vcpu_destroy(struct vcpu *v); int altp2m_vcpu_enable_ve(struct vcpu *v, gfn_t gfn); void altp2m_vcpu_disable_ve(struct vcpu *v); diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ #include "mm-locks.h" #include "p2m.h" -void -altp2m_vcpu_initialise(struct vcpu *v) -{ - if ( !v->domain->nr_altp2m ) - return; - - if ( v != current ) - vcpu_pause(v); - - vcpu_altp2m(v).p2midx = 0; - atomic_inc(&altp2m_get_altp2m(v)->active_vcpus); - - altp2m_vcpu_update_p2m(v); - - if ( v != current ) - vcpu_unpause(v); -} - -void -altp2m_vcpu_destroy(struct vcpu *v) -{ - struct p2m_domain *p2m; - - if ( !v->domain->nr_altp2m ) - return; - - if ( v != current ) - vcpu_pause(v); - - if ( (p2m = altp2m_get_altp2m(v)) ) - atomic_dec(&p2m->active_vcpus); - - altp2m_vcpu_disable_ve(v); - - vcpu_altp2m(v).p2midx = INVALID_ALTP2M; - altp2m_vcpu_update_p2m(v); - - if ( v != current ) - vcpu_unpause(v); -} - int altp2m_vcpu_enable_ve(struct vcpu *v, gfn_t gfn) { struct domain *d = v->domain; diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ void altp2m_teardown(struct domain *d) XVFREE(d->altp2m_p2m); } +#ifdef CONFIG_X86 +void altp2m_vcpu_initialise(struct vcpu *v) +{ + if ( !v->domain->nr_altp2m ) + return; + + if ( v != current ) + vcpu_pause(v); + + vcpu_altp2m(v).p2midx = 0; + atomic_inc(&altp2m_get_altp2m(v)->active_vcpus); + + altp2m_vcpu_update_p2m(v); + + if ( v != current ) + vcpu_unpause(v); +} + +void altp2m_vcpu_destroy(struct vcpu *v) +{ + struct p2m_domain *p2m; + + if ( !v->domain->nr_altp2m ) + return; + + if ( v != current ) + vcpu_pause(v); + + if ( (p2m = altp2m_get_altp2m(v)) ) + atomic_dec(&p2m->active_vcpus); + + altp2m_vcpu_disable_ve(v); + + vcpu_altp2m(v).p2midx = INVALID_ALTP2M; + altp2m_vcpu_update_p2m(v); + + if ( v != current ) + vcpu_unpause(v); +} +#endif + /* * altp2m operations are envisioned as being used in several different * modes: diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ int altp2m_init(struct domain *d); /* Free altp2m views */ void altp2m_teardown(struct domain *d); +#ifdef CONFIG_X86 +/* Alternate p2m VCPU */ +void altp2m_vcpu_initialise(struct vcpu *v); +void altp2m_vcpu_destroy(struct vcpu *v); +#endif + #ifdef CONFIG_ALTP2M /* Alternate p2m HVM on/off per domain */ -- 2.34.1
This commit adds support for the altp2m_vcpu_initialise and altp2m_vcpu_destroy functions on ARM. The x86-specific function calls, altp2m_vcpu_disable_ve and altp2m_vcpu_update_p2m, are gated with #ifdef CONFIG_X86. This is commit 2/2 of the altp2m_vcpu_{initialise,destroy} phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. The equivalent to this patch in the v4/v5 was originally part of the patch named "arm/altp2m: Add HVMOP_altp2m_set_domain_state". In that patch, the check that the VCPU passed to altp2m_vcpu_initialise isn't the current CPU was removed. This was because ARM only implements the external altp2m mode, meaning the current VCPU could never be a VCPU of the guest for which altp2m is being initialized for. Therefore, skipping this check was a slight optimization. I've removed that here because altp2m_vcpu_initialise is only called during an HVMOP, and skipping this check on ARM (especially when x86 also implements the external altp2m mode) causes more confusion than the slight optimization is worth in my view. --- xen/common/altp2m.c | 14 ++++++++++---- xen/include/xen/altp2m.h | 2 -- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <xsm/xsm.h> #if defined(CONFIG_X86) && defined(CONFIG_HVM) +#include <asm/hvm/hvm.h> #include <asm/hvm/nestedhvm.h> #endif @@ -XXX,XX +XXX,XX @@ void altp2m_teardown(struct domain *d) XVFREE(d->altp2m_p2m); } -#ifdef CONFIG_X86 void altp2m_vcpu_initialise(struct vcpu *v) { if ( !v->domain->nr_altp2m ) @@ -XXX,XX +XXX,XX @@ void altp2m_vcpu_initialise(struct vcpu *v) if ( v != current ) vcpu_pause(v); - vcpu_altp2m(v).p2midx = 0; + altp2m_set_vcpu_idx(v, 0); atomic_inc(&altp2m_get_altp2m(v)->active_vcpus); +#ifdef CONFIG_X86 altp2m_vcpu_update_p2m(v); +#endif if ( v != current ) vcpu_unpause(v); @@ -XXX,XX +XXX,XX @@ void altp2m_vcpu_destroy(struct vcpu *v) if ( (p2m = altp2m_get_altp2m(v)) ) atomic_dec(&p2m->active_vcpus); +#ifdef CONFIG_X86 altp2m_vcpu_disable_ve(v); +#endif - vcpu_altp2m(v).p2midx = INVALID_ALTP2M; + altp2m_set_vcpu_idx(v, INVALID_ALTP2M); + +#ifdef CONFIG_X86 altp2m_vcpu_update_p2m(v); +#endif if ( v != current ) vcpu_unpause(v); } -#endif /* * altp2m operations are envisioned as being used in several different diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ int altp2m_init(struct domain *d); /* Free altp2m views */ void altp2m_teardown(struct domain *d); -#ifdef CONFIG_X86 /* Alternate p2m VCPU */ void altp2m_vcpu_initialise(struct vcpu *v); void altp2m_vcpu_destroy(struct vcpu *v); -#endif #ifdef CONFIG_ALTP2M -- 2.34.1
This commit adds the altp2m_view_state enum, which indicates whether an altp2m view is invalid, visible, or invisible. The altp2m_state array is comprised of altp2m_view_state values, where each entry corresponds to the altp2m view with the same entry. This is analogous to the altp2m_eptp and altp2m_visible_eptp arrays on x86. This addition is necessary to tell whether an altp2m is valid, in addition to whether it is visible. Since all altp2m views are allocated up-front during p2m initialization, there must be an additional mechanism to determine whether an altp2m view is valid. Since the implementation of HVMOP_altp2m_set_visibility also needs an additional mechanism to determine whether a view is visible, it makes sense to combine altp2m view validity and visibility into a single mechanism. Therefore, the altp2m_state array is used to track both view validitity and visibility. This is commit 1/5 of the altp2m view validity/visibility phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. In the v4/v5 patch series, view validity was determined by simply checking if the altp2m p2m_domain pointer is NULL. This isn't possible in the v6 patch series, since altp2m views are allocated up-front during altp2m_init. Since the altp2m_view_state enum definition has to be available in asm/domain.h, this commit removes the sched.h dependency from altp2m.h. Unfortunately, this means that it's not possible to have static inline functions in altp2m.h which need a complete definition of arch_domain and arch_vcpu. If there would be a better place to put the altp2m_view_state definition, feedback would be appreciated. --- xen/arch/arm/altp2m.c | 13 +++++++++++++ xen/arch/arm/include/asm/altp2m.h | 23 +++++++++++++---------- xen/arch/arm/include/asm/domain.h | 4 ++++ xen/arch/arm/mmu/p2m.c | 14 +++++++++++++- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/altp2m.c +++ b/xen/arch/arm/altp2m.c @@ -XXX,XX +XXX,XX @@ * Copyright (c) 2016 Sergej Proskurin <proskurin@sec.in.tum.de> */ +#include <xen/sched.h> + #include <asm/p2m.h> /* Check to see if vcpu should be switched to a different p2m. */ @@ -XXX,XX +XXX,XX @@ void altp2m_check(struct vcpu *v, uint16_t idx) BUG(); } +/* Alternate p2m VCPU */ +uint16_t altp2m_vcpu_idx(const struct vcpu *v) +{ + return v->arch.ap2m_idx; +} + +void altp2m_set_vcpu_idx(struct vcpu *v, unsigned int idx) +{ + v->arch.ap2m_idx = idx; +} + /* * Local variables: * mode: C diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ #ifndef __ASM_ARM_ALTP2M_H #define __ASM_ARM_ALTP2M_H -#include <xen/sched.h> +#include <xen/mem_access.h> + +struct domain; +struct vcpu; #ifdef CONFIG_ALTP2M @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_supported(void) #define altp2m_unlock(d) spin_unlock(&(d)->arch.altp2m_lock) /* Alternate p2m VCPU */ -static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v) -{ - return v->arch.ap2m_idx; -} - -static inline void altp2m_set_vcpu_idx(struct vcpu *v, unsigned int idx) -{ - v->arch.ap2m_idx = idx; -} +uint16_t altp2m_vcpu_idx(const struct vcpu *v); +void altp2m_set_vcpu_idx(struct vcpu *v, unsigned int idx); + +/* The current state of an altp2m view */ +enum altp2m_view_state { + ALTP2M_INVALID, + ALTP2M_VISIBLE, + ALTP2M_INVISIBLE, +}; #else /* CONFIG_ALTP2M */ diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/domain.h +++ b/xen/arch/arm/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ #include <xen/cache.h> #include <xen/timer.h> +#include <asm/altp2m.h> #include <asm/page.h> #include <asm/p2m.h> #include <asm/suspend.h> @@ -XXX,XX +XXX,XX @@ struct arch_domain * concurrently. */ spinlock_t altp2m_lock; + + /* Validity/visibility of altp2m views */ + enum altp2m_view_state *altp2m_state; #endif } __cacheline_aligned; diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mmu/p2m.c +++ b/xen/arch/arm/mmu/p2m.c @@ -XXX,XX +XXX,XX @@ int p2m_teardown(struct domain *d) d->altp2m_active = false; + FREE_XENHEAP_PAGE(d->arch.altp2m_state); + for ( i = 0; i < d->nr_altp2m; i++ ) { rc = p2m_teardown_one(d->altp2m_p2m[i]); @@ -XXX,XX +XXX,XX @@ struct p2m_domain *p2m_init_one(struct domain *d) static int p2m_init_altp2m(struct domain *d) { #ifdef CONFIG_ALTP2M - int rc; + int rc, i; rc = altp2m_init(d); if ( rc ) @@ -XXX,XX +XXX,XX @@ static int p2m_init_altp2m(struct domain *d) return rc; } + if ( (d->arch.altp2m_state = alloc_xenheap_page()) == NULL ) + { + return -ENOMEM; + } + + for ( i = 0; i < d->nr_altp2m; i++ ) + { + d->arch.altp2m_state[i] = ALTP2M_INVALID; + } + d->altp2m_active = false; #endif -- 2.34.1
This commit adds arch independent helper functions to determine whether a view is valid or visible. This makes it possible to determine whether a view is valid and/or visible in common altp2m routines (namely, altp2m_init_by_id). This is commit 2/5 of the altp2m view validity/visibility phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> Signed-off-by: Aqib Javaid <Aqib.Javaid@elektrobit.com> --- v6: Introduced this patch. These functions could be used to replace the equivalent calls in x86 code if that would be preferred. For now, they are only used in common code. The altp2m_view_is_valid function also has overlap with the altp2m_is_ept_valid function, but that function has an additional ASSERT and check that idx < d->nr_altp2m, so I wasn't sure if that function should be repurposed for this. If renaming that function instead of introducing a new function on x86 would be preferred, then I can do that. Additionally, these functions don't have bounds checks since the functions are intended to replace code which don't have bounds checks currently. Bounds checks could be added here if that would be preferred. --- xen/arch/arm/altp2m.c | 10 ++++++++++ xen/arch/arm/include/asm/altp2m.h | 3 +++ xen/arch/x86/include/asm/altp2m.h | 10 ++++++++++ 3 files changed, 23 insertions(+) diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/altp2m.c +++ b/xen/arch/arm/altp2m.c @@ -XXX,XX +XXX,XX @@ void altp2m_set_vcpu_idx(struct vcpu *v, unsigned int idx) v->arch.ap2m_idx = idx; } +bool altp2m_view_is_valid(struct domain *d, unsigned int idx) +{ + return d->arch.altp2m_state[array_index_nospec(idx, d->nr_altp2m)] != ALTP2M_INVALID; +} + +bool altp2m_view_is_visible(struct domain *d, unsigned int idx) +{ + return d->arch.altp2m_state[array_index_nospec(idx, d->nr_altp2m)] == ALTP2M_VISIBLE; +} + /* * Local variables: * mode: C diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_supported(void) uint16_t altp2m_vcpu_idx(const struct vcpu *v); void altp2m_set_vcpu_idx(struct vcpu *v, unsigned int idx); +bool altp2m_view_is_valid(struct domain *d, unsigned int idx); +bool altp2m_view_is_visible(struct domain *d, unsigned int idx); + /* The current state of an altp2m view */ enum altp2m_view_state { ALTP2M_INVALID, diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline void altp2m_set_vcpu_idx(struct vcpu *v, unsigned int idx) vcpu_altp2m(v).p2midx = idx; } +static inline bool altp2m_view_is_valid(struct domain *d, unsigned int idx) +{ + return d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] != mfn_x(INVALID_MFN); +} + +static inline bool altp2m_view_is_visible(struct domain *d, unsigned int idx) +{ + return d->arch.altp2m_visible_eptp[array_index_nospec(idx, MAX_EPTP)] != mfn_x(INVALID_MFN); +} + /* * Alternate p2m: shadow p2m tables used for alternate memory views */ -- 2.34.1
This commit splits the altp2m_set_view_visibility into two functions, where the altp2m_set_view_visibility_locked variant has the preconditions that the altp2m lock is held. This makes it possible to change a view's visibility in an architecture independent way in code that already holds the altp2m lock (namely, altp2m_flush). This is commit 3/5 of the altp2m view validity/visibility phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/altp2m.h | 4 ++++ xen/arch/x86/mm/altp2m.c | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ int altp2m_change_gfn(struct domain *d, unsigned int idx, gfn_t old_gfn, int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, uint8_t visible); +/* Set a specific p2m view visibility (with lock already held) */ +int altp2m_set_view_visibility_locked(struct domain *d, unsigned int altp2m_idx, + uint8_t visible); + /* * Looks up altp2m entry. If the entry is not found it looks up the entry in * hostp2m. diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, uint8_t visible) { - int rc = 0; + int rc; altp2m_lock(d); + rc = altp2m_set_view_visibility_locked(d, altp2m_idx, visible); + altp2m_unlock(d); + + return rc; +} + +int altp2m_set_view_visibility_locked(struct domain *d, unsigned int altp2m_idx, + uint8_t visible) +{ + int rc = 0; if ( !altp2m_is_eptp_valid(d, altp2m_idx) ) rc = -EINVAL; @@ -XXX,XX +XXX,XX @@ int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, d->arch.altp2m_visible_eptp[array_index_nospec(altp2m_idx, MAX_EPTP)] = mfn_x(INVALID_MFN); - altp2m_unlock(d); - return rc; } -- 2.34.1
This commit adds the altp2m_set_view_visibility and altp2m_set_view_visibility_locked functions on ARM. This makes it possible to set the altp2m view visibility in common altp2m routines (namely, altp2m_flush). This is commit 4/5 of the altp2m view validity/visibility phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/arm/altp2m.c | 30 ++++++++++++++++++++++++++++++ xen/arch/arm/include/asm/altp2m.h | 8 ++++++++ 2 files changed, 38 insertions(+) diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/altp2m.c +++ b/xen/arch/arm/altp2m.c @@ -XXX,XX +XXX,XX @@ bool altp2m_view_is_visible(struct domain *d, unsigned int idx) return d->arch.altp2m_state[array_index_nospec(idx, d->nr_altp2m)] == ALTP2M_VISIBLE; } +int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, + uint8_t visible) +{ + int rc; + + altp2m_lock(d); + rc = altp2m_set_view_visibility_locked(d, altp2m_idx, visible); + altp2m_unlock(d); + + return rc; +} + +int altp2m_set_view_visibility_locked(struct domain *d, unsigned int altp2m_idx, + uint8_t visible) +{ + int rc = 0; + + if ( altp2m_idx >= d->nr_altp2m || !altp2m_view_is_valid(d, altp2m_idx) ) + rc = -EINVAL; + else if ( visible ) + d->arch.altp2m_state[array_index_nospec(altp2m_idx, d->nr_altp2m)] = + ALTP2M_VISIBLE; + else + d->arch.altp2m_state[array_index_nospec(altp2m_idx, d->nr_altp2m)] = + ALTP2M_INVISIBLE; + + return rc; +} + + /* * Local variables: * mode: C diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ enum altp2m_view_state { ALTP2M_INVISIBLE, }; +/* Set a specific p2m view visibility */ +int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, + uint8_t visible); + +/* Set a specific p2m view visibility (with lock already held) */ +int altp2m_set_view_visibility_locked(struct domain *d, unsigned int altp2m_idx, + uint8_t visible); + #else /* CONFIG_ALTP2M */ static inline bool altp2m_supported(void) -- 2.34.1
This commit adds support for the HVMOP_altp2m_set_visibility command on ARM. With altp2m_set_view_visibility being implemented, no further changes beyond updating the #ifdef CONFIG_X86 gates are necessary. This is commit 5/5 of the altp2m view validity/visibility phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/common/altp2m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; break; } +#endif /* CONFIG_X86 */ case HVMOP_altp2m_set_visibility: { @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( rc = altp2m_set_view_visibility(d, idx, a.u.set_visibility.visible); break; } -#endif /* CONFIG_X86 */ default: #ifdef CONFIG_X86 -- 2.34.1
This commit adds a declaration for altp2m_activate_altp2m to the x86 asm/altp2m.h header. This makes it possible to call the function in common altp2m routines (namely, altp2m_init_by_id). This is commit 1/2 of the altp2m_activate_altp2m phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/altp2m.h | 4 ++++ xen/arch/x86/mm/altp2m.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ int altp2m_init_next_available(struct domain *d, uint16_t *idx, /* Make a specific alternate p2m invalid */ int altp2m_destroy_by_id(struct domain *d, unsigned int idx); +/* Activate an altp2m view */ +int altp2m_activate_altp2m(struct domain *d, unsigned int idx, + p2m_access_t hvmmem_default_access); + /* Switch alternate p2m for entire domain */ int altp2m_switch_domain_altp2m_by_id(struct domain *d, unsigned int idx); diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ void altp2m_flush(struct domain *d) altp2m_unlock(d); } -static int altp2m_activate_altp2m(struct domain *d, unsigned int idx, - p2m_access_t hvmmem_default_access) +int altp2m_activate_altp2m(struct domain *d, unsigned int idx, + p2m_access_t hvmmem_default_access) { struct p2m_domain *hostp2m, *p2m; int rc; -- 2.34.1
This commit adds the altp2m_activate_altp2m function on ARM. This makes it possible to activate altp2m views in common altp2m routines (namely, altp2m_init_by_id). This is commit 2/2 of the altp2m_activate_altp2m phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. While the ARM version of this function is very similar to the x86 version of this function, I still think it makes sense to have this implemented on both architectures instead of using a common implementation. A significant portion of the function would need to be #ifdef CONFIG_X86/#else CONFIG_ARM gated (like p2m->min_mapped_gfn vs. p2m->lowest_mapped_gfn on ARM, for example). This would become even more of an issue if other architectures implement altp2m in the future, so I think it's best to keep these architecture specific. --- xen/arch/arm/altp2m.c | 26 +++++++++++++++++++++++++- xen/arch/arm/include/asm/altp2m.h | 4 ++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/altp2m.c +++ b/xen/arch/arm/altp2m.c @@ -XXX,XX +XXX,XX @@ bool altp2m_view_is_visible(struct domain *d, unsigned int idx) return d->arch.altp2m_state[array_index_nospec(idx, d->nr_altp2m)] == ALTP2M_VISIBLE; } +int altp2m_activate_altp2m(struct domain *d, unsigned int idx, + p2m_access_t hvmmem_default_access) +{ + struct p2m_domain *hostp2m, *p2m; + + ASSERT(idx < d->nr_altp2m); + + p2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + hostp2m = p2m_get_hostp2m(d); + + p2m_write_lock(p2m); + + p2m->default_access = hvmmem_default_access; + p2m->domain = hostp2m->domain; + + p2m->lowest_mapped_gfn = INVALID_GFN; + p2m->max_mapped_gfn = _gfn(0); + + d->arch.altp2m_state[idx] = ALTP2M_VISIBLE; + + p2m_write_unlock(p2m); + + return 0; +} + int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, uint8_t visible) { @@ -XXX,XX +XXX,XX @@ int altp2m_set_view_visibility_locked(struct domain *d, unsigned int altp2m_idx, return rc; } - /* * Local variables: * mode: C diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ int altp2m_set_view_visibility(struct domain *d, unsigned int altp2m_idx, int altp2m_set_view_visibility_locked(struct domain *d, unsigned int altp2m_idx, uint8_t visible); +/* Activate an altp2m view */ +int altp2m_activate_altp2m(struct domain *d, unsigned int idx, + p2m_access_t hvmmem_default_access); + #else /* CONFIG_ALTP2M */ static inline bool altp2m_supported(void) -- 2.34.1
This commit moves the altp2m_init_by_id function to common code, gated to only compile on x86. This makes it possible to call in the common HVMOP_altp2m_set_domain_state command implementation. This commit contains only code movement, and no change in functionality is intended. This is commit 1/2 of the altp2m_init_by_id phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/altp2m.h | 3 --- xen/arch/x86/mm/altp2m.c | 18 ------------------ xen/common/altp2m.c | 20 ++++++++++++++++++++ xen/include/xen/altp2m.h | 5 +++++ 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ bool altp2m_switch_vcpu_by_id(struct vcpu *v, unsigned int idx); /* Flush all the alternate p2m's for a domain */ void altp2m_flush(struct domain *d); -/* Make a specific alternate p2m valid */ -int altp2m_init_by_id(struct domain *d, unsigned int idx); - /* Find an available alternate p2m and make it valid */ int altp2m_init_next_available(struct domain *d, uint16_t *idx, xenmem_access_t hvmmem_default_access); diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ int altp2m_activate_altp2m(struct domain *d, unsigned int idx, return rc; } -int altp2m_init_by_id(struct domain *d, unsigned int idx) -{ - int rc = -EINVAL; - struct p2m_domain *hostp2m = p2m_get_hostp2m(d); - - if ( idx >= d->nr_altp2m ) - return rc; - - altp2m_lock(d); - - if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] == - mfn_x(INVALID_MFN) ) - rc = altp2m_activate_altp2m(d, idx, hostp2m->default_access); - - altp2m_unlock(d); - return rc; -} - int altp2m_init_next_available(struct domain *d, uint16_t *idx, xenmem_access_t hvmmem_default_access) { diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ void altp2m_vcpu_destroy(struct vcpu *v) vcpu_unpause(v); } +#ifdef CONFIG_X86 +int altp2m_init_by_id(struct domain *d, unsigned int idx) +{ + int rc = -EINVAL; + struct p2m_domain *hostp2m = p2m_get_hostp2m(d); + + if ( idx >= d->nr_altp2m ) + return rc; + + altp2m_lock(d); + + if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] == + mfn_x(INVALID_MFN) ) + rc = altp2m_activate_altp2m(d, idx, hostp2m->default_access); + + altp2m_unlock(d); + return rc; +} +#endif + /* * altp2m operations are envisioned as being used in several different * modes: diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx) int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg); +#ifdef CONFIG_X86 +/* Make a specific alternate p2m valid */ +int altp2m_init_by_id(struct domain *d, unsigned int idx); +#endif + #else /* CONFIG_ALTP2M */ static inline bool altp2m_active(const struct domain *d) -- 2.34.1
This commit makes altp2m_init_by_id compatible with ARM by replacing the x86 domain validity check with an architecture independent check. This makes it possible to call the function in the common HVMOP_altp2m_set_domain state implementation. This is commit 2/2 of the altp2m_init_by_id phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/common/altp2m.c | 5 +---- xen/include/xen/altp2m.h | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ void altp2m_vcpu_destroy(struct vcpu *v) vcpu_unpause(v); } -#ifdef CONFIG_X86 int altp2m_init_by_id(struct domain *d, unsigned int idx) { int rc = -EINVAL; @@ -XXX,XX +XXX,XX @@ int altp2m_init_by_id(struct domain *d, unsigned int idx) altp2m_lock(d); - if ( d->arch.altp2m_eptp[array_index_nospec(idx, MAX_EPTP)] == - mfn_x(INVALID_MFN) ) + if ( !altp2m_view_is_valid(d, idx) ) rc = altp2m_activate_altp2m(d, idx, hostp2m->default_access); altp2m_unlock(d); return rc; } -#endif /* * altp2m operations are envisioned as being used in several different diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_set_altp2m(struct vcpu *v, unsigned int idx) int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg); -#ifdef CONFIG_X86 /* Make a specific alternate p2m valid */ int altp2m_init_by_id(struct domain *d, unsigned int idx); -#endif #else /* CONFIG_ALTP2M */ -- 2.34.1
This commit makes altp2m_reset_altp2m non-static and adds a declaration to the asm/altp2m.h header. This makes it possible to call this function in common altp2m routines. The altp2m_reset_type enum (which is the type of one of the parameters of altp2m_reset) is also moved to the asm/altp2m.h header. This is commit 1/2 of the altp2m_reset_altp2m phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/altp2m.h | 8 ++++++++ xen/arch/x86/mm/altp2m.c | 9 ++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ int altp2m_init_next_available(struct domain *d, uint16_t *idx, /* Make a specific alternate p2m invalid */ int altp2m_destroy_by_id(struct domain *d, unsigned int idx); +/* Reset an altp2m view */ +enum altp2m_reset_type { + ALTP2M_RESET, + ALTP2M_DEACTIVATE +}; +void altp2m_reset_altp2m(struct domain *d, unsigned int idx, + enum altp2m_reset_type reset_type); + /* Activate an altp2m view */ int altp2m_activate_altp2m(struct domain *d, unsigned int idx, p2m_access_t hvmmem_default_access); diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ bool altp2m_get_or_propagate(struct p2m_domain *ap2m, unsigned long gfn_l, return true; } -enum altp2m_reset_type { - ALTP2M_RESET, - ALTP2M_DEACTIVATE -}; - -static void altp2m_reset_altp2m(struct domain *d, unsigned int idx, - enum altp2m_reset_type reset_type) +void altp2m_reset_altp2m(struct domain *d, unsigned int idx, + enum altp2m_reset_type reset_type) { struct p2m_domain *p2m; -- 2.34.1
This commit adds the altp2m_reset_altp2m routine on ARM. This will later be used as part of the altp2m_flush routine. This is commit 2/2 of the altp2m_reset_altp2m phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. I'm not sure if duplicating the altp2m_reset_type enum is really the best way to handle this. The distinction isn't even relevant on ARM since the logdirty ranges don't need to be freed. However, the function prototype has to be the same in order to call it on both x86 and ARM. Ideally the altp2m_reset_type enum would be part of a header that asm/altp2m.h includes on both architectures. The main xen/altp2m.h header can't fill this role since it includes asm/altp2m.h, so it would be a circular include. Introducing *another* header file to just hold altp2m_reset_type also isn't great, so I chose to just duplicate the enum. Any better ideas here would be appreciated. --- xen/arch/arm/altp2m.c | 20 ++++++++++++++++++++ xen/arch/arm/include/asm/altp2m.h | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/altp2m.c +++ b/xen/arch/arm/altp2m.c @@ -XXX,XX +XXX,XX @@ #include <xen/sched.h> +#include <asm/altp2m.h> #include <asm/p2m.h> /* Check to see if vcpu should be switched to a different p2m. */ @@ -XXX,XX +XXX,XX @@ bool altp2m_view_is_visible(struct domain *d, unsigned int idx) return d->arch.altp2m_state[array_index_nospec(idx, d->nr_altp2m)] == ALTP2M_VISIBLE; } +void altp2m_reset_altp2m(struct domain *d, unsigned int idx, + enum altp2m_reset_type reset_type) +{ + struct p2m_domain *p2m; + + ASSERT(idx < d->nr_altp2m); + p2m = d->altp2m_p2m[array_index_nospec(idx, d->nr_altp2m)]; + + p2m_write_lock(p2m); + + while ( p2m_flush_table(p2m) == -ERESTART ) + continue; /* No preemption support here */ + + p2m->lowest_mapped_gfn = INVALID_GFN; + p2m->max_mapped_gfn = _gfn(0); + + p2m_write_unlock(p2m); +} + int altp2m_activate_altp2m(struct domain *d, unsigned int idx, p2m_access_t hvmmem_default_access) { diff --git a/xen/arch/arm/include/asm/altp2m.h b/xen/arch/arm/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/altp2m.h +++ b/xen/arch/arm/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ int altp2m_set_view_visibility_locked(struct domain *d, unsigned int altp2m_idx, int altp2m_activate_altp2m(struct domain *d, unsigned int idx, p2m_access_t hvmmem_default_access); +/* Reset an altp2m view */ +enum altp2m_reset_type { + ALTP2M_RESET, + ALTP2M_DEACTIVATE +}; +void altp2m_reset_altp2m(struct domain *d, unsigned int idx, + enum altp2m_reset_type reset_type); + #else /* CONFIG_ALTP2M */ static inline bool altp2m_supported(void) -- 2.34.1
This commit moves the altp2m_flush function to common code. This makes it possible to call in the common implementation of HVMOP_set_domain_state. This commit contains only code movement, and no change in functionality is intended. This is commit 1/2 of the altp2m_flush phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. --- xen/arch/x86/include/asm/altp2m.h | 2 -- xen/arch/x86/mm/altp2m.c | 16 ---------------- xen/common/altp2m.c | 18 ++++++++++++++++++ xen/include/xen/altp2m.h | 5 +++++ 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ static inline bool altp2m_view_is_visible(struct domain *d, unsigned int idx) /* Switch alternate p2m for a single vcpu */ bool altp2m_switch_vcpu_by_id(struct vcpu *v, unsigned int idx); -/* Flush all the alternate p2m's for a domain */ -void altp2m_flush(struct domain *d); /* Find an available alternate p2m and make it valid */ int altp2m_init_next_available(struct domain *d, uint16_t *idx, diff --git a/xen/arch/x86/mm/altp2m.c b/xen/arch/x86/mm/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/altp2m.c +++ b/xen/arch/x86/mm/altp2m.c @@ -XXX,XX +XXX,XX @@ void altp2m_reset_altp2m(struct domain *d, unsigned int idx, p2m_unlock(p2m); } -void altp2m_flush(struct domain *d) -{ - unsigned int i; - - altp2m_lock(d); - - for ( i = 0; i < d->nr_altp2m; i++ ) - { - altp2m_reset_altp2m(d, i, ALTP2M_DEACTIVATE); - d->arch.altp2m_eptp[i] = mfn_x(INVALID_MFN); - d->arch.altp2m_visible_eptp[i] = mfn_x(INVALID_MFN); - } - - altp2m_unlock(d); -} - int altp2m_activate_altp2m(struct domain *d, unsigned int idx, p2m_access_t hvmmem_default_access) { diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ int altp2m_init_by_id(struct domain *d, unsigned int idx) return rc; } +#ifdef CONFIG_X86 +void altp2m_flush(struct domain *d) +{ + unsigned int i; + + altp2m_lock(d); + + for ( i = 0; i < d->nr_altp2m; i++ ) + { + altp2m_reset_altp2m(d, i, ALTP2M_DEACTIVATE); + d->arch.altp2m_eptp[i] = mfn_x(INVALID_MFN); + d->arch.altp2m_visible_eptp[i] = mfn_x(INVALID_MFN); + } + + altp2m_unlock(d); +} +#endif + /* * altp2m operations are envisioned as being used in several different * modes: diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg); /* Make a specific alternate p2m valid */ int altp2m_init_by_id(struct domain *d, unsigned int idx); +#ifdef CONFIG_X86 +/* Flush all the alternate p2m's for a domain */ +void altp2m_flush(struct domain *d); +#endif + #else /* CONFIG_ALTP2M */ static inline bool altp2m_active(const struct domain *d) -- 2.34.1
This commit makes the altp2m_flush compatible with ARM by replacing the x86-specific set view visibility code with the architecture independent altp2m_set_view_visibility locked. This is commit 2/2 of the altp2m_flush phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. There is a small amount of additional overhead introduced on x86 by replacing these direct array sets with calls to altp2m_set_view_visibility_locked. That function also calls altp2m_is_eptp_valid, which performs additional checks, and also bounds the array sets with array_index_nospec, which isn't technically necessary here since we can be certain that the array set will be less than nr_altp2m. This could be resolved by introducing another altp2m_set_view_visibility variant (ex. altp2m_set_view_visibility_unchecked?) which would replace usages of altp2m_set_view_visibility_locked, but I'm not sure if the overhead is enough to matter here. --- xen/common/altp2m.c | 5 +---- xen/include/xen/altp2m.h | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ int altp2m_init_by_id(struct domain *d, unsigned int idx) return rc; } -#ifdef CONFIG_X86 void altp2m_flush(struct domain *d) { unsigned int i; @@ -XXX,XX +XXX,XX @@ void altp2m_flush(struct domain *d) for ( i = 0; i < d->nr_altp2m; i++ ) { altp2m_reset_altp2m(d, i, ALTP2M_DEACTIVATE); - d->arch.altp2m_eptp[i] = mfn_x(INVALID_MFN); - d->arch.altp2m_visible_eptp[i] = mfn_x(INVALID_MFN); + altp2m_set_view_visibility_locked(d, i, 0); } altp2m_unlock(d); } -#endif /* * altp2m operations are envisioned as being used in several different diff --git a/xen/include/xen/altp2m.h b/xen/include/xen/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/altp2m.h +++ b/xen/include/xen/altp2m.h @@ -XXX,XX +XXX,XX @@ int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg); /* Make a specific alternate p2m valid */ int altp2m_init_by_id(struct domain *d, unsigned int idx); -#ifdef CONFIG_X86 /* Flush all the alternate p2m's for a domain */ void altp2m_flush(struct domain *d); -#endif #else /* CONFIG_ALTP2M */ -- 2.34.1
This commit enables the HVMOP_altp2m_set_domain_state command on ARM, since all prerequisite functions have been implemented. This makes it possible to activate altp2m on a domain. This is commit 1/1 of the set_domain_state phase. Signed-off-by: Rose Spangler <Rose.Spangler@elektrobit.com> --- v6: Introduced this patch. This patch replaces the "arm/p2m: Add HVMOP_altp2m_set_domain_state" patch from the v4/v5 patch series. --- xen/common/altp2m.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xen/common/altp2m.c b/xen/common/altp2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/altp2m.c +++ b/xen/common/altp2m.c @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; break; -#ifdef CONFIG_X86 case HVMOP_altp2m_set_domain_state: { struct vcpu *v; bool ostate; +#if defined(CONFIG_X86) && defined(CONFIG_HVM) if ( nestedhvm_enabled(d) ) { rc = -EINVAL; break; } +#endif rc = domain_pause_except_self(d); if ( rc ) @@ -XXX,XX +XXX,XX @@ int do_altp2m_op( break; } +#ifdef CONFIG_X86 case HVMOP_altp2m_vcpu_enable_notify: { struct vcpu *v; -- 2.34.1