@@ -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;
@@ -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);
}
@@ -2587,7 +2590,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 )
@@ -2643,7 +2646,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",
@@ -1139,12 +1139,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) )
@@ -1212,7 +1207,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 )
@@ -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.
@@ -382,6 +382,17 @@ struct p2m_domain {
#endif
#include <xen/p2m-common.h>
+static inline bool arch_acquire_resource_check(struct domain *d)
+{
+ /*
+ * 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
+ * (see set_foreign_p2m_entry()).
+ */
+ return !paging_mode_translate(d) || is_hardware_domain(d);
+}
+
/*
* Updates vCPU's n2pm to match its np2m_base in VMCx12 and returns that np2m.
*/
@@ -647,9 +658,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);
@@ -3,6 +3,10 @@
#include <xen/mm-frame.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,