Current, foreign mappings can only be read-write. A follow-up patch will
extend foreign mapping for Xen backend memory (via XEN_DOMID), some of
that memory should only be read accessible for the mapping domain.
Introduce a new p2m_type to cater read-only foreign mappings. For now,
the decision between the two foreign mapping type is based on the type
of the guest page mapped.
Signed-off-by: Julien Grall <julien.grall@xxxxxxx>
Reviewed-by: Andrii Anisov <andrii_anisov@xxxxxxxx>
---
Changes in v2:
- Add Andrii's reviewed-by
---
xen/arch/arm/mm.c | 2 +-
xen/arch/arm/p2m.c | 1 +
xen/include/asm-arm/p2m.h | 42 +++++++++++++++++++++++++++++++++++++++---
3 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 7193d83b44..58f7e54640 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1267,7 +1267,7 @@ int xenmem_add_to_physmap_one(
}
mfn = page_to_mfn(page);
- t = p2m_map_foreign_rw;
+ t = (p2mt == p2m_ram_rw) ? p2m_map_foreign_rw : p2m_map_foreign_ro;
rcu_unlock_domain(od);
break;
diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index e0b84a9db5..dea04ef66f 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -477,6 +477,7 @@ static void p2m_set_permission(lpae_t *e, p2m_type_t t,
p2m_access_t a)
break;
case p2m_iommu_map_ro:
+ case p2m_map_foreign_ro:
case p2m_grant_map_ro:
case p2m_invalid:
e->p2m.xn = 1;
diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
index a1aef7b793..6f2728e2bb 100644
--- a/xen/include/asm-arm/p2m.h
+++ b/xen/include/asm-arm/p2m.h
@@ -116,6 +116,7 @@ typedef enum {
p2m_mmio_direct_nc, /* Read/write mapping of genuine MMIO area
non-cacheable */
p2m_mmio_direct_c, /* Read/write mapping of genuine MMIO area cacheable
*/
p2m_map_foreign_rw, /* Read/write RAM pages from foreign domain */
+ p2m_map_foreign_ro, /* Read-only RAM pages from foreign domain */
p2m_grant_map_rw, /* Read/write grant mapping */
p2m_grant_map_ro, /* Read-only grant mapping */
/* The types below are only used to decide the page attribute in the P2M
*/
@@ -135,12 +136,16 @@ typedef enum {
#define P2M_GRANT_TYPES (p2m_to_mask(p2m_grant_map_rw) | \
p2m_to_mask(p2m_grant_map_ro))
+/* Foreign mappings types */
+#define P2M_FOREIGN_TYPES (p2m_to_mask(p2m_map_foreign_rw) | \
+ p2m_to_mask(p2m_map_foreign_ro))
+
/* Useful predicates */
#define p2m_is_ram(_t) (p2m_to_mask(_t) & P2M_RAM_TYPES)
-#define p2m_is_foreign(_t) (p2m_to_mask(_t) & p2m_to_mask(p2m_map_foreign_rw))
+#define p2m_is_foreign(_t) (p2m_to_mask(_t) & P2M_FOREIGN_TYPES)
#define p2m_is_any_ram(_t) (p2m_to_mask(_t) & \
(P2M_RAM_TYPES | P2M_GRANT_TYPES | \
- p2m_to_mask(p2m_map_foreign_rw)))
+ P2M_FOREIGN_TYPES))
/* All common type definitions should live ahead of this inclusion. */
#ifdef _XEN_P2M_COMMON_H
@@ -295,7 +300,38 @@ struct page_info *p2m_get_page_from_gfn(struct domain *d,
gfn_t gfn,
static inline struct page_info *get_page_from_gfn(
struct domain *d, unsigned long gfn, p2m_type_t *t, p2m_query_t q)
{
- return p2m_get_page_from_gfn(d, _gfn(gfn), t);
+ mfn_t mfn;
+ p2m_type_t _t;
+ struct page_info *page;
+
+ /*
+ * Special case for DOMID_XEN as it is the only domain so far that is
+ * not auto-translated.
+ */
+ if ( unlikely(d != dom_xen) )
+ return p2m_get_page_from_gfn(d, _gfn(gfn), t);
+
+ if ( !t )
+ t = &_t;
+
+ *t = p2m_invalid;
+
+ /*
+ * DOMID_XEN see 1-1 RAM. The p2m_type is based on the type of the
+ * page.
+ */
+ mfn = _mfn(gfn);
+ page = mfn_to_page(mfn);
+
+ if ( !mfn_valid(mfn) || !get_page(page, d) )
+ return NULL;
+
+ if ( page->u.inuse.type_info & PGT_writable_page )
+ *t = p2m_ram_rw;
+ else
+ *t = p2m_ram_ro;
+
+ return page;
}
int get_page_type(struct page_info *page, unsigned long type);