@@ -384,15 +384,50 @@ static int dm_op(domid_t domid,
case XEN_DMOP_map_mem_type_to_ioreq_server:
{
- const struct xen_dm_op_map_mem_type_to_ioreq_server *data =
+ struct xen_dm_op_map_mem_type_to_ioreq_server *data =
&op.u.map_mem_type_to_ioreq_server;
+ unsigned long first_gfn = data->opaque;
+
+ const_op = false;
rc = -EOPNOTSUPP;
if ( !hap_enabled(d) )
break;
- rc = hvm_map_mem_type_to_ioreq_server(d, data->id,
- data->type, data->flags);
+ if ( first_gfn == 0 )
+ rc = hvm_map_mem_type_to_ioreq_server(d, data->id,
+ data->type, data->flags);
+ else
+ rc = 0;
+
+ /*
+ * Iterate p2m table when an ioreq server unmaps from p2m_ioreq_server,
+ * and reset the remaining p2m_ioreq_server entries back to p2m_ram_rw.
+ */
+ if ( rc == 0 && data->flags == 0 )
+ {
+ struct p2m_domain *p2m = p2m_get_hostp2m(d);
+
+ while ( read_atomic(&p2m->ioreq.entry_count) &&
+ first_gfn <= p2m->max_mapped_pfn )
+ {
+ /* Iterate p2m table for 256 gfns each time. */
+ p2m_finish_type_change(d, _gfn(first_gfn), 256,
+ p2m_ioreq_server, p2m_ram_rw);
+
+ first_gfn += 256;
+
+ /* Check for continuation if it's not the last iteration. */
+ if ( first_gfn <= p2m->max_mapped_pfn &&
+ hypercall_preempt_check() )
+ {
+ rc = -ERESTART;
+ data->opaque = first_gfn;
+ break;
+ }
+ }
+ }
+
break;
}
@@ -1011,6 +1011,35 @@ void p2m_change_type_range(struct domain *d,
p2m_unlock(p2m);
}
+/* Synchronously modify the p2m type for a range of gfns from ot to nt. */
+void p2m_finish_type_change(struct domain *d,
+ gfn_t first_gfn, unsigned long max_nr,
+ p2m_type_t ot, p2m_type_t nt)
+{
+ struct p2m_domain *p2m = p2m_get_hostp2m(d);
+ p2m_type_t t;
+ unsigned long gfn = gfn_x(first_gfn);
+ unsigned long last_gfn = gfn + max_nr - 1;
+
+ ASSERT(ot != nt);
+ ASSERT(p2m_is_changeable(ot) && p2m_is_changeable(nt));
+
+ p2m_lock(p2m);
+
+ last_gfn = min(last_gfn, p2m->max_mapped_pfn);
+ while ( gfn <= last_gfn )
+ {
+ get_gfn_query_unlocked(d, gfn, &t);
+
+ if ( t == ot )
+ p2m_change_type_one(d, gfn, t, nt);
+
+ gfn++;
+ }
+
+ p2m_unlock(p2m);
+}
+
/*
* Returns:
* 0 for success
@@ -611,6 +611,12 @@ void p2m_change_type_range(struct domain *d,
int p2m_change_type_one(struct domain *d, unsigned long gfn,
p2m_type_t ot, p2m_type_t nt);
+/* Synchronously change the p2m type for a range of gfns */
+void p2m_finish_type_change(struct domain *d,
+ gfn_t first_gfn,
+ unsigned long max_nr,
+ p2m_type_t ot, p2m_type_t nt);
+
/* Report a change affecting memory types. */
void p2m_memory_type_changed(struct domain *d);