]> xenbits.xensource.com Git - xen.git/commitdiff
xen/arm: grant: Add another entry to map MFN 1:1 in dom0 p2m
authorJulien Grall <julien.grall@linaro.org>
Tue, 27 May 2014 11:11:41 +0000 (12:11 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Mon, 2 Jun 2014 15:46:41 +0000 (16:46 +0100)
Grant mappings can be used for DMA requests. Currently the dev_bus_addr returned
by the hypercall is the MFN (not the IPA). Guest expects to be able the returned
address for DMA. When the device is protected by IOMMU the request will fail.
Therefore, we have to add 1:1 mapping in the domain p2m to allow DMA request
to work.

This is valid because DOM0 has its memory mapped 1:1 and therefore we know
that RAM and devices cannot clash.

If the guest only owns protected device, the return dev_bus_addr should be an
IPA. This will allow us to remove safely the 1:1 mapping and make grant mapping
works correctly in the guest. For now, this is not addressed by this patch.

The grant mapping code does the reference counting on every MFN and will
call iommu_{map,unmap}_page when necessary. This was already handle for x86
PV guests, so we can reuse the same code path for ARM guest.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
[ ijc s/ld/d/ in both arch's gnttab_need_iommu_mapping() ]

xen/arch/arm/p2m.c
xen/common/grant_table.c
xen/drivers/passthrough/arm/smmu.c
xen/include/asm-arm/grant_table.h
xen/include/asm-arm/p2m.h
xen/include/asm-x86/grant_table.h

index 96bc0efaeb1bf2712864053a43aa6c242da919c9..810459a7329ae056d250cf6c129297901fa2f712 100644 (file)
@@ -227,6 +227,7 @@ static lpae_t mfn_to_p2m_entry(unsigned long mfn, unsigned int mattr,
         e.p2m.write = 0;
         break;
 
+    case p2m_iommu_map_rw:
     case p2m_map_foreign:
     case p2m_grant_map_rw:
     case p2m_mmio_direct:
@@ -234,6 +235,7 @@ static lpae_t mfn_to_p2m_entry(unsigned long mfn, unsigned int mattr,
         e.p2m.write = 1;
         break;
 
+    case p2m_iommu_map_ro:
     case p2m_grant_map_ro:
     case p2m_invalid:
         e.p2m.xn = 1;
index 2c93d9cc38a1d2da5217ffbb8fe156471307225f..c08e9573ba2ebd508efd94c620c4fbd189674131 100644 (file)
@@ -727,7 +727,7 @@ __gnttab_map_grant_ref(
 
     double_gt_lock(lgt, rgt);
 
-    if ( !paging_mode_translate(ld) && need_iommu(ld) )
+    if ( gnttab_need_iommu_mapping(ld) )
     {
         unsigned int wrc, rdc;
         int err = 0;
@@ -935,7 +935,7 @@ __gnttab_unmap_common(
             act->pin -= GNTPIN_hstw_inc;
     }
 
-    if ( !paging_mode_translate(ld) && need_iommu(ld) )
+    if ( gnttab_need_iommu_mapping(ld) )
     {
         unsigned int wrc, rdc;
         int err = 0;
index 21b4572c73142900abf7c96f5f9f2afa4683ea0c..f4eb2a2d59f5eee3b5256d414752b73afbe56c69 100644 (file)
@@ -1536,6 +1536,46 @@ static void arm_smmu_iommu_domain_teardown(struct domain *d)
     xfree(smmu_domain);
 }
 
+static int arm_smmu_map_page(struct domain *d, unsigned long gfn,
+                             unsigned long mfn, unsigned int flags)
+{
+    p2m_type_t t;
+
+    /* Grant mappings can be used for DMA requests. The dev_bus_addr returned by
+     * the hypercall is the MFN (not the IPA). For device protected by
+     * an IOMMU, Xen needs to add a 1:1 mapping in the domain p2m to
+     * allow DMA request to work.
+     * This is only valid when the domain is directed mapped. Hence this
+     * function should only be used by gnttab code with gfn == mfn.
+     */
+    BUG_ON(!is_domain_direct_mapped(d));
+    BUG_ON(mfn != gfn);
+
+    /* We only support readable and writable flags */
+    if ( !(flags & (IOMMUF_readable | IOMMUF_writable)) )
+        return -EINVAL;
+
+    t = (flags & IOMMUF_writable) ? p2m_iommu_map_rw : p2m_iommu_map_ro;
+
+    /* The function guest_physmap_add_entry replaces the current mapping
+     * if there is already one...
+     */
+    return guest_physmap_add_entry(d, gfn, mfn, 0, t);
+}
+
+static int arm_smmu_unmap_page(struct domain *d, unsigned long gfn)
+{
+    /* This function should only be used by gnttab code when the domain
+     * is direct mapped
+     */
+    if ( !is_domain_direct_mapped(d) )
+        return -EINVAL;
+
+    guest_physmap_remove_page(d, gfn, gfn, 0);
+
+    return 0;
+}
+
 static const struct iommu_ops arm_smmu_iommu_ops = {
     .init = arm_smmu_iommu_domain_init,
     .hwdom_init = arm_smmu_iommu_hwdom_init,
@@ -1544,6 +1584,8 @@ static const struct iommu_ops arm_smmu_iommu_ops = {
     .iotlb_flush_all = arm_smmu_iotlb_flush_all,
     .assign_dt_device = arm_smmu_attach_dev,
     .reassign_dt_device = arm_smmu_reassign_dt_dev,
+    .map_page = arm_smmu_map_page,
+    .unmap_page = arm_smmu_unmap_page,
 };
 
 static int __init smmu_init(struct dt_device_node *dev,
index 6e0cc59fb2f72e90fa91679a85dd138b185ad12f..eac8a7004324dbd9f5628dc578056527bcbc75b0 100644 (file)
@@ -33,6 +33,9 @@ static inline int replace_grant_supported(void)
     ( ((i >= nr_grant_frames(d->grant_table)) &&                         \
      (i < max_nr_grant_frames)) ? 0 : (d->arch.grant_table_gpfn[i]))
 
+#define gnttab_need_iommu_mapping(d)                    \
+    (is_domain_direct_mapped(d) && need_iommu(d))
+
 #endif /* __ASM_GRANT_TABLE_H__ */
 /*
  * Local variables:
index bd71abe9f75654011e7b9fb9883ba33c1978f6a9..911d32df1cbd6056e776bbb5ba7987e1f5692bfb 100644 (file)
@@ -45,6 +45,9 @@ typedef enum {
     p2m_map_foreign,    /* 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 */
+    p2m_iommu_map_rw,   /* Read/write iommu mapping */
+    p2m_iommu_map_ro,   /* Read-only iommu mapping */
     p2m_max_real_type,  /* Types after this won't be store in the p2m */
 } p2m_type_t;
 
index 3013869384171bf1a2c6afa55da56e5cd49b4cf8..8c9bbcf753cb813784cb1c85377883f705cb0828 100644 (file)
@@ -65,6 +65,9 @@ static inline void gnttab_clear_flag(unsigned int nr, uint16_t *st)
 /* Done implicitly when page tables are destroyed. */
 #define gnttab_release_host_mappings(domain) ( paging_mode_external(domain) )
 
+#define gnttab_need_iommu_mapping(d)                \
+    (!paging_mode_translate(d) && need_iommu(d))
+
 static inline int replace_grant_supported(void)
 {
     return 1;