diff --git a/xen/common/domain.c b/xen/common/domain.c index 047a489647..479e48ab98 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -1023,6 +1023,20 @@ int domain_unpause_by_systemcontroller(struct domain *d) prev = cmpxchg(&d->controller_pause_count, old, new); } while ( prev != old ); + /* + * d->controller_pause_count is initialised to 1, and the toolstack is + * responsible for making one unpause hypercall when it wishes the guest + * to start running. + * + * All other toolstack operations should make a pair of pause/unpause + * calls and rely on the reference counting here. + * + * Creation is considered finished when the controller reference count + * first drops to 0. + */ + if ( new == 0 ) + d->creation_finished = 1; + domain_unpause(d); return 0; diff --git a/xen/drivers/passthrough/amd/iommu_map.c b/xen/drivers/passthrough/amd/iommu_map.c index 1c04ed65f5..87b93c2074 100644 --- a/xen/drivers/passthrough/amd/iommu_map.c +++ b/xen/drivers/passthrough/amd/iommu_map.c @@ -695,11 +695,24 @@ int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn, !!(flags & IOMMUF_writable), !!(flags & IOMMUF_readable)); - /* Do not increase pde count if io mapping has not been changed */ - if ( !need_flush ) - goto out; + if ( need_flush ) + { + amd_iommu_flush_pages(d, gfn, 0); + /* No further merging, as the logic doesn't cope. */ + hd->arch.no_merge = 1; + } - amd_iommu_flush_pages(d, gfn, 0); + /* + * Suppress merging of non-R/W mappings or after initial table creation, + * as the merge logic does not cope with this. + */ + if ( hd->arch.no_merge || flags != (IOMMUF_writable | IOMMUF_readable) ) + goto out; + if ( d->creation_finished ) + { + hd->arch.no_merge = 1; + goto out; + } for ( merge_level = IOMMU_PAGING_MODE_LEVEL_2; merge_level <= hd->arch.paging_mode; merge_level++ ) @@ -769,6 +782,10 @@ int amd_iommu_unmap_page(struct domain *d, unsigned long gfn) /* mark PTE as 'page not present' */ clear_iommu_pte_present(pt_mfn[1], gfn); + + /* No further merging in amd_iommu_map_page(), as the logic doesn't cope. */ + hd->arch.no_merge = 1; + spin_unlock(&hd->arch.mapping_lock); amd_iommu_flush_pages(d, gfn, 0); diff --git a/xen/include/asm-x86/hvm/iommu.h b/xen/include/asm-x86/hvm/iommu.h index 6962cf6fe2..95a7802a3a 100644 --- a/xen/include/asm-x86/hvm/iommu.h +++ b/xen/include/asm-x86/hvm/iommu.h @@ -59,6 +59,7 @@ struct arch_iommu /* amd iommu support */ int paging_mode; + bool_t no_merge; struct page_info *root_table; struct guest_iommu *g_iommu; }; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 4d8be547dd..0d45ba4d2c 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -387,6 +387,12 @@ struct domain bool_t disable_migrate; /* Is this guest being debugged by dom0? */ bool_t debugger_attached; + /* + * Set to true at the very end of domain creation, when the domain is + * unpaused for the first time by the systemcontroller. + */ + bool_t creation_finished; + /* Which guest this guest has privileges on */ struct domain *target;