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;
!!(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++ )
/* 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);
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;