iommu: Specify access permissions to iommu_map_page().
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 28 May 2010 07:48:50 +0000 (08:48 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 28 May 2010 07:48:50 +0000 (08:48 +0100)
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
15 files changed:
xen/arch/ia64/xen/mm.c
xen/arch/x86/mm.c
xen/arch/x86/mm/hap/p2m-ept.c
xen/arch/x86/mm/p2m.c
xen/arch/x86/x86_64/mm.c
xen/common/grant_table.c
xen/drivers/passthrough/amd/iommu_map.c
xen/drivers/passthrough/amd/pci_amd_iommu.c
xen/drivers/passthrough/iommu.c
xen/drivers/passthrough/vtd/ia64/vtd.c
xen/drivers/passthrough/vtd/iommu.c
xen/drivers/passthrough/vtd/x86/vtd.c
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
xen/include/xen/iommu.h

index bcaadba8e55c4f339a30ffe3285c0cb3b4ec26be..c8ad97673cdf415945def7a3853de85c9033090c 100644 (file)
@@ -2897,7 +2897,8 @@ __guest_physmap_add_page(struct domain *d, unsigned long gpfn,
         int i, j;
         j = 1 << (PAGE_SHIFT-PAGE_SHIFT_4K);
         for(i = 0 ; i < j; i++)
-            iommu_map_page(d, gpfn*j + i, mfn*j + i);
+            iommu_map_page(d, gpfn*j + i, mfn*j + i,
+                           IOMMUF_readable|IOMMUF_writable);
     }
 }
 
index fcb00f737bb31defc0bf691fd4bdd80611d471ec..d042f05d6f4954506a7f1a3dc69200596845374e 100644 (file)
@@ -2402,7 +2402,8 @@ static int __get_page_type(struct page_info *page, unsigned long type,
                 iommu_unmap_page(d, mfn_to_gmfn(d, page_to_mfn(page)));
             else if ( type == PGT_writable_page )
                 iommu_map_page(d, mfn_to_gmfn(d, page_to_mfn(page)),
-                               page_to_mfn(page));
+                               page_to_mfn(page),
+                               IOMMUF_readable|IOMMUF_writable);
         }
     }
 
index 798f4cceddbc42924c50adeb6973700e3a846e2f..7f67a6725a2b78f97b352d33dd6387a15b0a4f06 100644 (file)
@@ -353,10 +353,13 @@ out:
             if ( order == EPT_TABLE_ORDER )
             {
                 for ( i = 0; i < (1 << order); i++ )
-                    iommu_map_page(d, gfn - offset + i, mfn_x(mfn) - offset + i);
+                    iommu_map_page(
+                        d, gfn - offset + i, mfn_x(mfn) - offset + i,
+                        IOMMUF_readable|IOMMUF_writable);
             }
             else if ( !order )
-                iommu_map_page(d, gfn, mfn_x(mfn));
+                iommu_map_page(
+                    d, gfn, mfn_x(mfn), IOMMUF_readable|IOMMUF_writable);
         }
         else
         {
index 46c53c13ead0ac7acd54b8871f16d788c0d17197..29e15741f82e12d7f01b5b4d505221f3b429d977 100644 (file)
@@ -1377,7 +1377,8 @@ p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
     {
         if ( p2mt == p2m_ram_rw )
             for ( i = 0; i < (1UL << page_order); i++ )
-                iommu_map_page(d, gfn+i, mfn_x(mfn)+i );
+                iommu_map_page(d, gfn+i, mfn_x(mfn)+i,
+                               IOMMUF_readable|IOMMUF_writable);
         else
             for ( int i = 0; i < (1UL << page_order); i++ )
                 iommu_unmap_page(d, gfn+i);
@@ -2294,12 +2295,16 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
         if ( need_iommu(d) && t == p2m_ram_rw )
         {
             for ( i = 0; i < (1 << page_order); i++ )
-                if ( (rc = iommu_map_page(d, mfn + i, mfn + i)) != 0 )
+            {
+                rc = iommu_map_page(
+                    d, mfn + i, mfn + i, IOMMUF_readable|IOMMUF_writable);
+                if ( rc != 0 )
                 {
                     while ( i-- > 0 )
                         iommu_unmap_page(d, mfn + i);
                     return rc;
                 }
+            }
         }
         return 0;
     }
index 357a80a5d7ed46b3244d4e9aa77fc9b5193347a7..f4d25e56b99b672db918495237e54ac7a7fab567 100644 (file)
@@ -1463,7 +1463,7 @@ int memory_add(unsigned long spfn, unsigned long epfn, unsigned int pxm)
         goto destroy_m2p;
 
     for ( i = spfn; i < epfn; i++ )
-        if ( iommu_map_page(dom0, i, i) )
+        if ( iommu_map_page(dom0, i, i, IOMMUF_readable|IOMMUF_writable) )
             break;
 
     if ( i != epfn )
index 98a79637d64f5d0742d31474685f52e05e0ea50a..2dbf5c14a0973246cdc8fb40515e94313331a1db 100644 (file)
@@ -605,7 +605,8 @@ __gnttab_map_grant_ref(
         BUG_ON(paging_mode_translate(ld));
         /* We're not translated, so we know that gmfns and mfns are
            the same things, so the IOMMU entry is always 1-to-1. */
-        if ( iommu_map_page(ld, frame, frame) )
+        if ( iommu_map_page(ld, frame, frame,
+                            IOMMUF_readable|IOMMUF_writable) )
         {
             rc = GNTST_general_error;
             goto undo_out;
index 6bd64f9556d000a0d9b0dae25cb16fd3a5a0e329..178e7672c876ed5af39e9e4e97e4d3a9b8243581 100644 (file)
@@ -450,12 +450,11 @@ static u64 iommu_l2e_from_pfn(struct page_info *table, int level,
     return next_table_maddr;
 }
 
-int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn)
+int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn,
+                       unsigned int flags)
 {
     u64 iommu_l2e;
     struct hvm_iommu *hd = domain_hvm_iommu(d);
-    int iw = IOMMU_IO_WRITE_ENABLED;
-    int ir = IOMMU_IO_READ_ENABLED;
 
     BUG_ON( !hd->root_table );
 
@@ -469,7 +468,10 @@ int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn)
         domain_crash(d);
         return -EFAULT;
     }
-    set_iommu_l1e_present(iommu_l2e, gfn, (u64)mfn << PAGE_SHIFT, iw, ir);
+
+    set_iommu_l1e_present(iommu_l2e, gfn, (u64)mfn << PAGE_SHIFT,
+                          !!(flags & IOMMUF_writable),
+                          !!(flags & IOMMUF_readable));
 
     spin_unlock(&hd->mapping_lock);
     return 0;
index fc9bb29d624dc6b1415740da9ba5ef270dd5b986..d1c97e3ae3b544843f9e1d6b99e8d4f32c29b426 100644 (file)
@@ -235,7 +235,8 @@ static int amd_iommu_domain_init(struct domain *domain)
         {
             /* setup 1:1 page table for dom0 */
             for ( i = 0; i < max_page; i++ )
-                amd_iommu_map_page(domain, i, i);
+                amd_iommu_map_page(domain, i, i,
+                                   IOMMUF_readable|IOMMUF_writable);
         }
 
         amd_iommu_setup_dom0_devices(domain);
index 2989ced86f19872298335aeffab32aabae977fe7..732618cc83fffe48771784a4475623228776483f 100644 (file)
@@ -172,7 +172,8 @@ static int iommu_populate_page_table(struct domain *d)
         {
             BUG_ON(SHARED_M2P(mfn_to_gmfn(d, page_to_mfn(page))));
             rc = hd->platform_ops->map_page(
-                d, mfn_to_gmfn(d, page_to_mfn(page)), page_to_mfn(page));
+                d, mfn_to_gmfn(d, page_to_mfn(page)), page_to_mfn(page),
+                IOMMUF_readable|IOMMUF_writable);
             if (rc)
             {
                 spin_unlock(&d->page_alloc_lock);
@@ -217,14 +218,15 @@ void iommu_domain_destroy(struct domain *d)
     }
 }
 
-int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn)
+int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn,
+                   unsigned int flags)
 {
     struct hvm_iommu *hd = domain_hvm_iommu(d);
 
     if ( !iommu_enabled || !hd->platform_ops )
         return 0;
 
-    return hd->platform_ops->map_page(d, gfn, mfn);
+    return hd->platform_ops->map_page(d, gfn, mfn, flags);
 }
 
 int iommu_unmap_page(struct domain *d, unsigned long gfn)
index 660bcd35128bb63a50ef4dd1486cc4abc5637c44..4364c55648afa78d38fff79d104bd67ca8f7aa52 100644 (file)
@@ -108,7 +108,8 @@ static int do_dom0_iommu_mapping(unsigned long start, unsigned long end,
         pfn = page_addr >> PAGE_SHIFT;
         tmp = 1 << (PAGE_SHIFT - PAGE_SHIFT_4K);
         for ( j = 0; j < tmp; j++ )
-            iommu_map_page(d, (pfn*tmp+j), (pfn*tmp+j));
+            iommu_map_page(d, (pfn*tmp+j), (pfn*tmp+j),
+                           IOMMUF_readable|IOMMUF_writable);
 
        page_addr += PAGE_SIZE;
 
index e41c854798fed8eff772b2d159b369394ddcd50a..f1c2dd56d409661950b2ae02b9eca93b69b8f49c 100644 (file)
@@ -1578,7 +1578,8 @@ void iommu_domain_teardown(struct domain *d)
 }
 
 static int intel_iommu_map_page(
-    struct domain *d, unsigned long gfn, unsigned long mfn)
+    struct domain *d, unsigned long gfn, unsigned long mfn,
+    unsigned int flags)
 {
     struct hvm_iommu *hd = domain_hvm_iommu(d);
     struct acpi_drhd_unit *drhd;
@@ -1605,7 +1606,9 @@ static int intel_iommu_map_page(
     pte = page + (gfn & LEVEL_MASK);
     pte_present = dma_pte_present(*pte);
     dma_set_pte_addr(*pte, (paddr_t)mfn << PAGE_SHIFT_4K);
-    dma_set_pte_prot(*pte, DMA_PTE_READ | DMA_PTE_WRITE);
+    dma_set_pte_prot(*pte,
+                     ((flags & IOMMUF_readable) ? DMA_PTE_READ  : 0) |
+                     ((flags & IOMMUF_writable) ? DMA_PTE_WRITE : 0));
 
     /* Set the SNP on leaf page table if Snoop Control available */
     if ( iommu_snoop )
@@ -1687,7 +1690,8 @@ static int rmrr_identity_mapping(struct domain *d,
 
     while ( base_pfn < end_pfn )
     {
-        if ( intel_iommu_map_page(d, base_pfn, base_pfn) )
+        if ( intel_iommu_map_page(d, base_pfn, base_pfn,
+                                  IOMMUF_readable|IOMMUF_writable) )
             return -1;
         base_pfn++;
     }
index 580fc03eda14ae5758ff69e91a8fd3d63593eb64..bdd980c26472485b07bd17c5b2e737b2fdf53857 100644 (file)
@@ -153,7 +153,8 @@ void iommu_set_dom0_mapping(struct domain *d)
 
         tmp = 1 << (PAGE_SHIFT - PAGE_SHIFT_4K);
         for ( j = 0; j < tmp; j++ )
-            iommu_map_page(d, (i*tmp+j), (i*tmp+j));
+            iommu_map_page(d, (i*tmp+j), (i*tmp+j),
+                           IOMMUF_readable|IOMMUF_writable);
 
         if (!(i & (0xfffff >> (PAGE_SHIFT - PAGE_SHIFT_4K))))
             process_pending_softirqs();
index 463121bf77488f457a41b4a5949ab2cc9e173956..56aeb8a912b6649bf1a69dc47c980cc24f5b6a6f 100644 (file)
 #define MAX_AMD_IOMMUS                  32
 #define IOMMU_PAGE_TABLE_LEVEL_3        3
 #define IOMMU_PAGE_TABLE_LEVEL_4        4
-#define IOMMU_IO_WRITE_ENABLED          1
-#define IOMMU_IO_READ_ENABLED           1
-#define HACK_BIOS_SETTINGS                  0
 
 /* interrupt remapping table */
 #define INT_REMAP_INDEX_DM_MASK         0x1C00
index 26d859659e4c779e21d6740b03ecb5cb93f06e4e..594bb21e22589e3b8a89a953add01da5aa81c820 100644 (file)
@@ -52,7 +52,8 @@ int __init amd_iommu_init(void);
 int __init amd_iommu_update_ivrs_mapping_acpi(void);
 
 /* mapping functions */
-int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);
+int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn,
+                       unsigned int flags);
 int amd_iommu_unmap_page(struct domain *d, unsigned long gfn);
 u64 amd_iommu_get_next_table_from_pte(u32 *entry);
 int amd_iommu_reserve_domain_unity_map(struct domain *domain,
index 3a418bc5ba8b7304a1f1b0061ca6e8c109755525..5181ffc5be69c08223e0425086d0e64fe60063e1 100644 (file)
@@ -68,8 +68,16 @@ int assign_device(struct domain *d, u8 bus, u8 devfn);
 int deassign_device(struct domain *d, u8 bus, u8 devfn);
 int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn,
     XEN_GUEST_HANDLE_64(uint32) buf, int max_sdevs);
-int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);
+
+/* iommu_map_page() takes flags to direct the mapping operation. */
+#define _IOMMUF_readable 0
+#define IOMMUF_readable  (1u<<_IOMMUF_readable)
+#define _IOMMUF_writable 1
+#define IOMMUF_writable  (1u<<_IOMMUF_writable)
+int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn,
+                   unsigned int flags);
 int iommu_unmap_page(struct domain *d, unsigned long gfn);
+
 void iommu_domain_teardown(struct domain *d);
 int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq);
 int dpci_ioport_intercept(ioreq_t *p);
@@ -102,7 +110,8 @@ struct iommu_ops {
     int (*remove_device)(struct pci_dev *pdev);
     int (*assign_device)(struct domain *d, u8 bus, u8 devfn);
     void (*teardown)(struct domain *d);
-    int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn);
+    int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn,
+                    unsigned int flags);
     int (*unmap_page)(struct domain *d, unsigned long gfn);
     int (*reassign_device)(struct domain *s, struct domain *t,
                           u8 bus, u8 devfn);