[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH V4 16/24] xen/mm: Handle properly reference in set_foreign_p2m_entry() on Arm
On Tue, 12 Jan 2021, Oleksandr Tyshchenko wrote: > From: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx> > > This patch implements reference counting of foreign entries in > in set_foreign_p2m_entry() on Arm. This is a mandatory action if > we want to run emulator (IOREQ server) in other than dom0 domain, > as we can't trust it to do the right thing if it is not running > in dom0. So we need to grab a reference on the page to avoid it > disappearing. > > It is valid to always pass "p2m_map_foreign_rw" type to > guest_physmap_add_entry() since the current and foreign domains > would be always different. A case when they are equal would be > rejected by rcu_lock_remote_domain_by_id(). Besides the similar > comment in the code put a respective ASSERT() to catch incorrect > usage in future. > > It was tested with IOREQ feature to confirm that all the pages given > to this function belong to a domain, so we can use the same approach > as for XENMAPSPACE_gmfn_foreign handling in xenmem_add_to_physmap_one(). > > This involves adding an extra parameter for the foreign domain to > set_foreign_p2m_entry() and a helper to indicate whether the arch > supports the reference counting of foreign entries and the restriction > for the hardware domain in the common code can be skipped for it. > > Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx> > CC: Julien Grall <julien.grall@xxxxxxx> > [On Arm only] > Tested-by: Wei Chen <Wei.Chen@xxxxxxx> Acked-by: Stefano Stabellini <sstabellini@xxxxxxxxxx> > --- > Please note, this is a split/cleanup/hardening of Julien's PoC: > "Add support for Guest IO forwarding to a device emulator" > > Changes RFC -> V1: > - new patch, was split from: > "[RFC PATCH V1 04/12] xen/arm: Introduce arch specific bits for IOREQ/DM > features" > - rewrite a logic to handle properly reference in set_foreign_p2m_entry() > instead of treating foreign entries as p2m_ram_rw > > Changes V1 -> V2: > - rebase according to the recent changes to acquire_resource() > - update patch description > - introduce arch_refcounts_p2m() > - add an explanation why p2m_map_foreign_rw is valid > - move set_foreign_p2m_entry() to p2m-common.h > - add const to new parameter > > Changes V2 -> V3: > - update patch description > - rename arch_refcounts_p2m() to arch_acquire_resource_check() > - move comment to x86’s arch_acquire_resource_check() > - return rc in Arm's set_foreign_p2m_entry() > - put a respective ASSERT() into Arm's set_foreign_p2m_entry() > > Changes V3 -> V4: > - update arch_acquire_resource_check() implementation on x86 > and common code which uses it, pass struct domain to the function > - put ASSERT() to x86/Arm set_foreign_p2m_entry() > - use arch_acquire_resource_check() in p2m_add_foreign() > instead of open-coding it > --- > xen/arch/arm/p2m.c | 26 ++++++++++++++++++++++++++ > xen/arch/x86/mm/p2m.c | 9 ++++++--- > xen/common/memory.c | 9 ++------- > xen/include/asm-arm/p2m.h | 19 +++++++++---------- > xen/include/asm-x86/p2m.h | 19 ++++++++++++++++--- > xen/include/xen/p2m-common.h | 4 ++++ > 6 files changed, 63 insertions(+), 23 deletions(-) > > diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c > index 4eeb867..d41c4fa 100644 > --- a/xen/arch/arm/p2m.c > +++ b/xen/arch/arm/p2m.c > @@ -1380,6 +1380,32 @@ int guest_physmap_remove_page(struct domain *d, gfn_t > gfn, mfn_t mfn, > return p2m_remove_mapping(d, gfn, (1 << page_order), mfn); > } > > +int set_foreign_p2m_entry(struct domain *d, const struct domain *fd, > + unsigned long gfn, mfn_t mfn) > +{ > + struct page_info *page = mfn_to_page(mfn); > + int rc; > + > + ASSERT(arch_acquire_resource_check(d)); > + > + if ( !get_page(page, fd) ) > + return -EINVAL; > + > + /* > + * It is valid to always use p2m_map_foreign_rw here as if this gets > + * called then d != fd. A case when d == fd would be rejected by > + * rcu_lock_remote_domain_by_id() earlier. Put a respective ASSERT() > + * to catch incorrect usage in future. > + */ > + ASSERT(d != fd); > + > + rc = guest_physmap_add_entry(d, _gfn(gfn), mfn, 0, p2m_map_foreign_rw); > + if ( rc ) > + put_page(page); > + > + return rc; > +} > + > static struct page_info *p2m_allocate_root(void) > { > struct page_info *page; > diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c > index 71fda06..cbeea85 100644 > --- a/xen/arch/x86/mm/p2m.c > +++ b/xen/arch/x86/mm/p2m.c > @@ -1323,8 +1323,11 @@ static int set_typed_p2m_entry(struct domain *d, > unsigned long gfn_l, > } > > /* Set foreign mfn in the given guest's p2m table. */ > -int set_foreign_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn) > +int set_foreign_p2m_entry(struct domain *d, const struct domain *fd, > + unsigned long gfn, mfn_t mfn) > { > + ASSERT(arch_acquire_resource_check(d)); > + > return set_typed_p2m_entry(d, gfn, mfn, PAGE_ORDER_4K, p2m_map_foreign, > p2m_get_hostp2m(d)->default_access); > } > @@ -2579,7 +2582,7 @@ static int p2m_add_foreign(struct domain *tdom, > unsigned long fgfn, > * hvm fixme: until support is added to p2m teardown code to cleanup any > * foreign entries, limit this to hardware domain only. > */ > - if ( !is_hardware_domain(tdom) ) > + if ( !arch_acquire_resource_check(tdom) ) > return -EPERM; > > if ( foreigndom == DOMID_XEN ) > @@ -2635,7 +2638,7 @@ static int p2m_add_foreign(struct domain *tdom, > unsigned long fgfn, > * will update the m2p table which will result in mfn -> gpfn of dom0 > * and not fgfn of domU. > */ > - rc = set_foreign_p2m_entry(tdom, gpfn, mfn); > + rc = set_foreign_p2m_entry(tdom, fdom, gpfn, mfn); > if ( rc ) > gdprintk(XENLOG_WARNING, "set_foreign_p2m_entry failed. " > "gpfn:%lx mfn:%lx fgfn:%lx td:%d fd:%d\n", > diff --git a/xen/common/memory.c b/xen/common/memory.c > index 66828d9..d625a9b 100644 > --- a/xen/common/memory.c > +++ b/xen/common/memory.c > @@ -1138,12 +1138,7 @@ static int acquire_resource( > xen_pfn_t mfn_list[32]; > int rc; > > - /* > - * FIXME: Until foreign pages inserted into the P2M are properly > - * reference counted, it is unsafe to allow mapping of > - * resource pages unless the caller is the hardware domain. > - */ > - if ( paging_mode_translate(currd) && !is_hardware_domain(currd) ) > + if ( !arch_acquire_resource_check(currd) ) > return -EACCES; > > if ( copy_from_guest(&xmar, arg, 1) ) > @@ -1211,7 +1206,7 @@ static int acquire_resource( > > for ( i = 0; !rc && i < xmar.nr_frames; i++ ) > { > - rc = set_foreign_p2m_entry(currd, gfn_list[i], > + rc = set_foreign_p2m_entry(currd, d, gfn_list[i], > _mfn(mfn_list[i])); > /* rc should be -EIO for any iteration other than the first */ > if ( rc && i ) > diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h > index 28ca9a8..4f8b3b0 100644 > --- a/xen/include/asm-arm/p2m.h > +++ b/xen/include/asm-arm/p2m.h > @@ -161,6 +161,15 @@ typedef enum { > #endif > #include <xen/p2m-common.h> > > +static inline bool arch_acquire_resource_check(struct domain *d) > +{ > + /* > + * The reference counting of foreign entries in set_foreign_p2m_entry() > + * is supported on Arm. > + */ > + return true; > +} > + > static inline > void p2m_altp2m_check(struct vcpu *v, uint16_t idx) > { > @@ -392,16 +401,6 @@ static inline gfn_t gfn_next_boundary(gfn_t gfn, > unsigned int order) > return gfn_add(gfn, 1UL << order); > } > > -static inline int set_foreign_p2m_entry(struct domain *d, unsigned long gfn, > - mfn_t mfn) > -{ > - /* > - * NOTE: If this is implemented then proper reference counting of > - * foreign entries will need to be implemented. > - */ > - return -EOPNOTSUPP; > -} > - > /* > * A vCPU has cache enabled only when the MMU is enabled and data cache > * is enabled. > diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h > index 7df2878..1d64c12 100644 > --- a/xen/include/asm-x86/p2m.h > +++ b/xen/include/asm-x86/p2m.h > @@ -382,6 +382,22 @@ struct p2m_domain { > #endif > #include <xen/p2m-common.h> > > +static inline bool arch_acquire_resource_check(struct domain *d) > +{ > + /* > + * The reference counting of foreign entries in set_foreign_p2m_entry() > + * is not supported for translated domains on x86. > + * > + * FIXME: Until foreign pages inserted into the P2M are properly > + * reference counted, it is unsafe to allow mapping of > + * resource pages unless the caller is the hardware domain. > + */ > + if ( paging_mode_translate(d) && !is_hardware_domain(d) ) > + return false; > + > + return true; > +} > + > /* > * Updates vCPU's n2pm to match its np2m_base in VMCx12 and returns that > np2m. > */ > @@ -647,9 +663,6 @@ int p2m_finish_type_change(struct domain *d, > int p2m_is_logdirty_range(struct p2m_domain *, unsigned long start, > unsigned long end); > > -/* Set foreign entry in the p2m table (for priv-mapping) */ > -int set_foreign_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn); > - > /* Set mmio addresses in the p2m table (for pass-through) */ > int set_mmio_p2m_entry(struct domain *d, gfn_t gfn, mfn_t mfn, > unsigned int order); > diff --git a/xen/include/xen/p2m-common.h b/xen/include/xen/p2m-common.h > index 58031a6..b4bc709 100644 > --- a/xen/include/xen/p2m-common.h > +++ b/xen/include/xen/p2m-common.h > @@ -3,6 +3,10 @@ > > #include <xen/mm.h> > > +/* Set foreign entry in the p2m table */ > +int set_foreign_p2m_entry(struct domain *d, const struct domain *fd, > + unsigned long gfn, mfn_t mfn); > + > /* Remove a page from a domain's p2m table */ > int __must_check > guest_physmap_remove_page(struct domain *d, gfn_t gfn, mfn_t mfn, > -- > 2.7.4 >
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |