|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 1/3] introduce GFN notification for translated domains
> -----Original Message-----
> From: Xen-devel <xen-devel-bounces@xxxxxxxxxxxxxxxxxxxx> On Behalf Of Jan
> Beulich
> Sent: 25 November 2019 09:58
> To: xen-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Juergen Gross <jgross@xxxxxxxx>; Stefano Stabellini
> <sstabellini@xxxxxxxxxx>; Julien Grall <julien@xxxxxxx>; Wei Liu
> <wl@xxxxxxx>; Konrad Wilk <konrad.wilk@xxxxxxxxxx>; George Dunlap
> <George.Dunlap@xxxxxxxxxxxxx>; Andrew Cooper <andrew.cooper3@xxxxxxxxxx>;
> Sander Eikelenboom <linux@xxxxxxxxxxxxxx>; Ian Jackson
> <ian.jackson@xxxxxxxxxx>; Roger Pau Monné <roger.pau@xxxxxxxxxx>
> Subject: [Xen-devel] [PATCH v3 1/3] introduce GFN notification for
> translated domains
>
> In order for individual IOMMU drivers (and from an abstract pov also
> architectures) to be able to adjust, ahead of actual mapping requests,
> their data structures when they might cover only a sub-range of all
> possible GFNs, introduce a notification call used by various code paths
> potentially installing a fresh mapping of a never used GFN (for a
> particular domain).
>
> Note that before this patch, in gnttab_transfer(), once past
> assign_pages(), further errors modifying the physmap are ignored
> (presumably because it would be too complicated to try to roll back at
> that point). This patch follows suit by ignoring failed notify_gfn()s or
> races due to the need to intermediately drop locks, simply printing out
> a warning that the gfn may not be accessible due to the failure.
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> ---
> v3: Conditionalize upon CONFIG_IOMMU_FORCE_PT_SHARE, also covering the
> share_p2m_table() functionality as appropriate. Un-comment the
> GNTMAP_host_map check.
> v2: Introduce arch_notify_gfn(), to invoke gfn_valid() on x86 (this
> unfortunately means it and notify_gfn() now need to be macros, or
> else include file dependencies get in the way, as gfn_valid() lives
> in paging.h, which we shouldn't include from xen/sched.h). Improve
> description.
>
> TBD: Does Arm actually have anything to check against in its
> arch_notify_gfn()?
>
> --- a/xen/arch/x86/hvm/dom0_build.c
> +++ b/xen/arch/x86/hvm/dom0_build.c
> @@ -173,7 +173,8 @@ static int __init pvh_populate_memory_ra
> continue;
> }
>
> - rc = guest_physmap_add_page(d, _gfn(start), page_to_mfn(page),
> + rc = notify_gfn(d, _gfn(start + (1UL << order) - 1)) ?:
> + guest_physmap_add_page(d, _gfn(start), page_to_mfn(page),
> order);
> if ( rc != 0 )
> {
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -4304,9 +4304,17 @@ static int hvmop_set_param(
> if ( a.value > SHUTDOWN_MAX )
> rc = -EINVAL;
> break;
> +
> case HVM_PARAM_IOREQ_SERVER_PFN:
> - d->arch.hvm.ioreq_gfn.base = a.value;
> + if ( d->arch.hvm.params[HVM_PARAM_NR_IOREQ_SERVER_PAGES] )
> + rc = notify_gfn(
> + d,
> + _gfn(a.value + d->arch.hvm.params
> + [HVM_PARAM_NR_IOREQ_SERVER_PAGES] -
> 1));
IIRC the PFN is typically set by the toolstack before the number of pages, so
the notify will be for a.value - 1, i.e. the previous gfn. Is that a problem?
Paul
> + if ( !rc )
> + d->arch.hvm.ioreq_gfn.base = a.value;
> break;
> +
> case HVM_PARAM_NR_IOREQ_SERVER_PAGES:
> {
> unsigned int i;
> @@ -4317,6 +4325,9 @@ static int hvmop_set_param(
> rc = -EINVAL;
> break;
> }
> + rc = notify_gfn(d, _gfn(d->arch.hvm.ioreq_gfn.base + a.value -
> 1));
> + if ( rc )
> + break;
> for ( i = 0; i < a.value; i++ )
> set_bit(i, &d->arch.hvm.ioreq_gfn.mask);
>
> @@ -4330,7 +4341,11 @@ static int hvmop_set_param(
> BUILD_BUG_ON(HVM_PARAM_BUFIOREQ_PFN >
> sizeof(d->arch.hvm.ioreq_gfn.legacy_mask) * 8);
> if ( a.value )
> - set_bit(a.index, &d->arch.hvm.ioreq_gfn.legacy_mask);
> + {
> + rc = notify_gfn(d, _gfn(a.value));
> + if ( !rc )
> + set_bit(a.index, &d->arch.hvm.ioreq_gfn.legacy_mask);
> + }
> break;
>
> case HVM_PARAM_X87_FIP_WIDTH:
> --- a/xen/common/grant_table.c
> +++ b/xen/common/grant_table.c
> @@ -946,6 +946,16 @@ map_grant_ref(
> return;
> }
>
> + if ( paging_mode_translate(ld) && (op->flags & GNTMAP_host_map) &&
> + (rc = notify_gfn(ld, gaddr_to_gfn(op->host_addr))) )
> + {
> + gdprintk(XENLOG_INFO, "notify(%"PRI_gfn") -> %d\n",
> + gfn_x(gaddr_to_gfn(op->host_addr)), rc);
> + op->status = GNTST_general_error;
> + return;
> + BUILD_BUG_ON(GNTST_okay);
> + }
> +
> if ( unlikely((rd = rcu_lock_domain_by_id(op->dom)) == NULL) )
> {
> gdprintk(XENLOG_INFO, "Could not find domain %d\n", op->dom);
> @@ -2123,6 +2133,7 @@ gnttab_transfer(
> {
> bool_t okay;
> int rc;
> + gfn_t gfn;
>
> if ( i && hypercall_preempt_check() )
> return i;
> @@ -2300,21 +2311,52 @@ gnttab_transfer(
> act = active_entry_acquire(e->grant_table, gop.ref);
>
> if ( evaluate_nospec(e->grant_table->gt_version == 1) )
> + gfn = _gfn(shared_entry_v1(e->grant_table, gop.ref).frame);
> + else
> + gfn = _gfn(shared_entry_v2(e->grant_table,
> gop.ref).full_page.frame);
> +
> + if ( paging_mode_translate(e) )
> {
> - grant_entry_v1_t *sha = &shared_entry_v1(e->grant_table,
> gop.ref);
> + gfn_t gfn2;
> +
> + active_entry_release(act);
> + grant_read_unlock(e->grant_table);
> +
> + rc = notify_gfn(e, gfn);
> + if ( rc )
> + printk(XENLOG_G_WARNING
> + "%pd: gref %u: xfer GFN %"PRI_gfn" may be
> inaccessible (%d)\n",
> + e, gop.ref, gfn_x(gfn), rc);
> +
> + grant_read_lock(e->grant_table);
> + act = active_entry_acquire(e->grant_table, gop.ref);
>
> - guest_physmap_add_page(e, _gfn(sha->frame), mfn, 0);
> - if ( !paging_mode_translate(e) )
> - sha->frame = mfn_x(mfn);
> + if ( evaluate_nospec(e->grant_table->gt_version == 1) )
> + gfn2 = _gfn(shared_entry_v1(e->grant_table,
> gop.ref).frame);
> + else
> + gfn2 = _gfn(shared_entry_v2(e->grant_table, gop.ref).
> + full_page.frame);
> +
> + if ( !gfn_eq(gfn, gfn2) )
> + {
> + printk(XENLOG_G_WARNING
> + "%pd: gref %u: xfer GFN went %"PRI_gfn" ->
> %"PRI_gfn"\n",
> + e, gop.ref, gfn_x(gfn), gfn_x(gfn2));
> + gfn = gfn2;
> + }
> }
> - else
> - {
> - grant_entry_v2_t *sha = &shared_entry_v2(e->grant_table,
> gop.ref);
>
> - guest_physmap_add_page(e, _gfn(sha->full_page.frame), mfn,
> 0);
> - if ( !paging_mode_translate(e) )
> - sha->full_page.frame = mfn_x(mfn);
> + guest_physmap_add_page(e, gfn, mfn, 0);
> +
> + if ( !paging_mode_translate(e) )
> + {
> + if ( evaluate_nospec(e->grant_table->gt_version == 1) )
> + shared_entry_v1(e->grant_table, gop.ref).frame =
> mfn_x(mfn);
> + else
> + shared_entry_v2(e->grant_table, gop.ref).full_page.frame
> =
> + mfn_x(mfn);
> }
> +
> smp_wmb();
> shared_entry_header(e->grant_table, gop.ref)->flags |=
> GTF_transfer_completed;
> --- a/xen/common/memory.c
> +++ b/xen/common/memory.c
> @@ -203,6 +203,10 @@ static void populate_physmap(struct memo
> if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i,
> 1)) )
> goto out;
>
> + if ( paging_mode_translate(d) &&
> + notify_gfn(d, _gfn(gpfn + (1U << a->extent_order) - 1)) )
> + goto out;
> +
> if ( a->memflags & MEMF_populate_on_demand )
> {
> /* Disallow populating PoD pages on oneself. */
> @@ -745,6 +749,10 @@ static long memory_exchange(XEN_GUEST_HA
> continue;
> }
>
> + if ( paging_mode_translate(d) )
> + rc = notify_gfn(d,
> + _gfn(gpfn + (1U << exch.out.extent_order)
> - 1));
> +
> mfn = page_to_mfn(page);
> guest_physmap_add_page(d, _gfn(gpfn), mfn,
> exch.out.extent_order);
> @@ -813,12 +821,20 @@ int xenmem_add_to_physmap(struct domain
> extra.foreign_domid = DOMID_INVALID;
>
> if ( xatp->space != XENMAPSPACE_gmfn_range )
> - return xenmem_add_to_physmap_one(d, xatp->space, extra,
> + return notify_gfn(d, _gfn(xatp->gpfn)) ?:
> + xenmem_add_to_physmap_one(d, xatp->space, extra,
> xatp->idx, _gfn(xatp->gpfn));
>
> if ( xatp->size < start )
> return -EILSEQ;
>
> + if ( !start && xatp->size )
> + {
> + rc = notify_gfn(d, _gfn(xatp->gpfn + xatp->size - 1));
> + if ( rc )
> + return rc;
> + }
> +
> xatp->idx += start;
> xatp->gpfn += start;
> xatp->size -= start;
> @@ -891,7 +907,8 @@ static int xenmem_add_to_physmap_batch(s
> extent, 1)) )
> return -EFAULT;
>
> - rc = xenmem_add_to_physmap_one(d, xatpb->space,
> + rc = notify_gfn(d, _gfn(gpfn)) ?:
> + xenmem_add_to_physmap_one(d, xatpb->space,
> xatpb->u,
> idx, _gfn(gpfn));
>
> --- a/xen/drivers/passthrough/iommu.c
> +++ b/xen/drivers/passthrough/iommu.c
> @@ -522,6 +522,7 @@ int iommu_do_domctl(
> return ret;
> }
>
> +#ifndef CONFIG_IOMMU_FORCE_PT_SHARE
> void iommu_share_p2m_table(struct domain* d)
> {
> ASSERT(hap_enabled(d));
> @@ -530,6 +531,15 @@ void iommu_share_p2m_table(struct domain
> iommu_get_ops()->share_p2m(d);
> }
>
> +int iommu_notify_gfn(struct domain *d, gfn_t gfn)
> +{
> + const struct iommu_ops *ops = dom_iommu(d)->platform_ops;
> +
> + return need_iommu_pt_sync(d) && ops->notify_dfn
> + ? iommu_call(ops, notify_dfn, d, _dfn(gfn_x(gfn))) : 0;
> +}
> +#endif
> +
> void iommu_crash_shutdown(void)
> {
> if ( !iommu_crash_disable )
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -272,6 +272,8 @@ static inline void free_vcpu_guest_conte
>
> static inline void arch_vcpu_block(struct vcpu *v) {}
>
> +#define arch_notify_gfn(d, gfn) ((void)(d), (void)(gfn), 0)
> +
> #endif /* __ASM_DOMAIN_H__ */
>
> /*
> --- a/xen/include/asm-x86/domain.h
> +++ b/xen/include/asm-x86/domain.h
> @@ -647,6 +647,8 @@ static inline void free_vcpu_guest_conte
>
> void arch_vcpu_regs_init(struct vcpu *v);
>
> +#define arch_notify_gfn(d, gfn) (gfn_valid(d, gfn) ? 0 : -EADDRNOTAVAIL)
> +
> struct vcpu_hvm_context;
> int arch_set_info_hvm_guest(struct vcpu *v, const struct vcpu_hvm_context
> *ctx);
>
> --- a/xen/include/xen/iommu.h
> +++ b/xen/include/xen/iommu.h
> @@ -237,6 +237,11 @@ struct iommu_ops {
> int __must_check (*lookup_page)(struct domain *d, dfn_t dfn, mfn_t
> *mfn,
> unsigned int *flags);
>
> +#ifndef CONFIG_IOMMU_FORCE_PT_SHARE
> + void (*share_p2m)(struct domain *d);
> + int __must_check (*notify_dfn)(struct domain *d, dfn_t dfn);
> +#endif
> +
> void (*free_page_table)(struct page_info *);
>
> #ifdef CONFIG_X86
> @@ -253,7 +258,6 @@ struct iommu_ops {
>
> int __must_check (*suspend)(void);
> void (*resume)(void);
> - void (*share_p2m)(struct domain *d);
> void (*crash_shutdown)(void);
> int __must_check (*iotlb_flush)(struct domain *d, dfn_t dfn,
> unsigned int page_count,
> @@ -330,7 +334,15 @@ void iommu_resume(void);
> void iommu_crash_shutdown(void);
> int iommu_get_reserved_device_memory(iommu_grdm_t *, void *);
>
> +#ifndef CONFIG_IOMMU_FORCE_PT_SHARE
> void iommu_share_p2m_table(struct domain *d);
> +int __must_check iommu_notify_gfn(struct domain *d, gfn_t gfn);
> +#else
> +static inline int __must_check iommu_notify_gfn(struct domain *d, gfn_t
> gfn)
> +{
> + return 0;
> +}
> +#endif
>
> #ifdef CONFIG_HAS_PCI
> int iommu_do_pci_domctl(struct xen_domctl *, struct domain *d,
> --- a/xen/include/xen/sched.h
> +++ b/xen/include/xen/sched.h
> @@ -1039,6 +1039,8 @@ static always_inline bool is_iommu_enabl
> return evaluate_nospec(d->options & XEN_DOMCTL_CDF_iommu);
> }
>
> +#define notify_gfn(d, gfn) (arch_notify_gfn(d, gfn) ?:
> iommu_notify_gfn(d, gfn))
> +
> extern bool sched_smt_power_savings;
> extern bool sched_disable_smt_switching;
>
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxxx
> https://lists.xenproject.org/mailman/listinfo/xen-devel
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |