[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [Patch] Read-only iomem page mapping



Attached is a patch to add ability to make read-only grants and ioremaps
of iomem pages.  Apologies if I've done something wrong - this is my
first attempt at Xen devel and driving mercurial!

Signed-off-by: kmansley@xxxxxxxxxxxxxxxxxx

# HG changeset patch
# User kjm@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Date 1155721361 -3600
# Node ID 0b37070e2efb0911d5bcfda5884089a64669e21e
# Parent  0e32095a7b4611d18a82052a9d5b23e474f91af9
Add ability to grant/map iomem pages read only as well as read write

diff -r 0e32095a7b46 -r 0b37070e2efb linux-2.6-xen-
sparse/arch/i386/mm/ioremap-xen.c
--- a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c   Wed Aug 09
21:34:27 2006 +0100
+++ b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c   Wed Aug 16
10:42:41 2006 +0100
@@ -281,7 +281,7 @@ void __iomem * __ioremap(unsigned long p
                return NULL;
        area->phys_addr = phys_addr;
        addr = (void __iomem *) area->addr;
-       flags |= _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED;
+       flags |= _PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED;
 #ifdef __x86_64__
        flags |= _PAGE_USER;
 #endif
@@ -320,7 +320,7 @@ void __iomem *ioremap_nocache (unsigned 
 void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long
size)
 {
        unsigned long last_addr;
-       void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);
+       void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD | _PAGE_RW);
        if (!p) 
                return p; 
 
diff -r 0e32095a7b46 -r 0b37070e2efb linux-2.6-xen-sparse/include/asm-
i386/mach-xen/asm/io.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/io.h   Wed Aug 09
21:34:27 2006 +0100
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/io.h   Wed Aug 16
10:42:41 2006 +0100
@@ -49,6 +49,11 @@
 
 #include <linux/vmalloc.h>
 #include <asm/fixmap.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
@@ -129,6 +134,12 @@ extern void __iomem * __ioremap(unsigned
  */
 
 static inline void __iomem * ioremap(unsigned long offset, unsigned
long size)
+{
+       return __ioremap(offset, size, _PAGE_RW);
+}
+
+static inline void __iomem * ioremap_readonly(unsigned long offset, 
+                                              unsigned long size)
 {
        return __ioremap(offset, size, 0);
 }
diff -r 0e32095a7b46 -r 0b37070e2efb linux-2.6-xen-sparse/include/asm-
x86_64/mach-xen/asm/io.h
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/io.h Wed Aug
09 21:34:27 2006 +0100
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/io.h Wed Aug
16 10:42:41 2006 +0100
@@ -105,6 +105,7 @@ __OUTS(l)
 #if defined(__KERNEL__) && __x86_64__
 
 #include <linux/vmalloc.h>
+#include <linux/init.h>
 
 #ifndef __i386__
 /*
@@ -143,10 +144,15 @@ static inline void * phys_to_virt(unsign
          bvec_to_pseudophys((vec2))))
 
 #include <asm-generic/iomap.h>
+#include <asm/pgtable.h>
 
 extern void __iomem *__ioremap(unsigned long offset, unsigned long
size, unsigned long flags);
 
 static inline void __iomem * ioremap (unsigned long offset, unsigned
long size)
+{
+       return __ioremap(offset, size, _PAGE_RW);
+}
+static inline void __iomem * ioremap_readonly (unsigned long offset,
unsigned long size)
 {
        return __ioremap(offset, size, 0);
 }
diff -r 0e32095a7b46 -r 0b37070e2efb xen/arch/ia64/xen/dom0_ops.c
--- a/xen/arch/ia64/xen/dom0_ops.c      Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/arch/ia64/xen/dom0_ops.c      Wed Aug 16 10:42:41 2006 +0100
@@ -210,11 +210,18 @@ dom0vp_ioremap(struct domain *d, unsigne
 
     end = PAGE_ALIGN(mpaddr + size);
 
-    if (!iomem_access_permitted(d, mpaddr >> PAGE_SHIFT,
-                                (end >> PAGE_SHIFT) - 1))
+    switch(iomem_access_permitted(d, mpaddr >> PAGE_SHIFT, 
+                                  (end >> PAGE_SHIFT) - 1)){
+    case IOMEM_ACCESS_READWRITE:
+        return assign_domain_mmio_page(d, mpaddr, size,
ASSIGN_writable);
+        break;
+    case IOMEM_ACCESS_READONLY:
+        return assign_domain_mmio_page(d, mpaddr, size,
ASSIGN_readonly);
+        break;
+    case IOMEM_ACCESS_NOACCESS:
         return -EPERM;
-
-    return assign_domain_mmio_page(d, mpaddr, size);
+        break;
+    }
 }
 
 unsigned long
diff -r 0e32095a7b46 -r 0b37070e2efb xen/arch/ia64/xen/dom_fw.c
--- a/xen/arch/ia64/xen/dom_fw.c        Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/arch/ia64/xen/dom_fw.c        Wed Aug 16 10:42:41 2006 +0100
@@ -496,7 +496,7 @@ dom_fw_dom0_passthrough(efi_memory_desc_
         if (md->type == EFI_MEMORY_MAPPED_IO && (size > 0x100000000UL))
             return 0;
 
-        paddr = assign_domain_mmio_page(d, start, size);
+        paddr = assign_domain_mmio_page(d, start, size,
ASSIGN_writable);
     } else
         paddr = assign_domain_mach_page(d, start, size, arg->flags);
 
@@ -913,7 +913,8 @@ dom_fw_init (struct domain *d, struct ia
                                continue;
                                        
                        if (efi_mmio(addr, PAGE_SIZE))
-                               assign_domain_mmio_page(d, addr, PAGE_SIZE);
+                                assign_domain_mmio_page(d, addr,
PAGE_SIZE,
+
ASSIGN_writable);
                }
        }
        for (i = 0 ; i < bp->efi_memmap_size/sizeof(efi_memory_desc_t) ; i++)
{
diff -r 0e32095a7b46 -r 0b37070e2efb xen/arch/ia64/xen/domain.c
--- a/xen/arch/ia64/xen/domain.c        Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/arch/ia64/xen/domain.c        Wed Aug 16 10:42:41 2006 +0100
@@ -364,7 +364,7 @@ int arch_domain_create(struct domain *d)
            goto fail_nomem;
 
        d->arch.ioport_caps = rangeset_new(d, "I/O Ports",
-                                          RANGESETF_prettyprint_hex);
+                                          RANGESETF_prettyprint_hex);
 
        printf ("arch_domain_create: domain=%p\n", d);
        return 0;
@@ -850,7 +850,7 @@ void alloc_dom0(void)
  */
 static void physdev_init_dom0(struct domain *d)
 {
-       if (iomem_permit_access(d, 0UL, ~0UL))
+        if (iomem_permit_access(d, 0UL, ~0UL, IOMEM_ACCESS_READWRITE))
                BUG();
        if (irqs_permit_access(d, 0, NR_IRQS-1))
                BUG();
diff -r 0e32095a7b46 -r 0b37070e2efb xen/arch/ia64/xen/mm.c
--- a/xen/arch/ia64/xen/mm.c    Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/arch/ia64/xen/mm.c    Wed Aug 16 10:42:41 2006 +0100
@@ -963,7 +963,8 @@ efi_mmio(unsigned long physaddr, unsigne
 
 unsigned long
 assign_domain_mmio_page(struct domain *d,
-                        unsigned long mpaddr, unsigned long size)
+                        unsigned long mpaddr, unsigned long size,
+                        unsigned long flags)
 {
     if (size == 0) {
         DPRINTK("%s: domain %p mpaddr 0x%lx size = 0x%lx\n",
@@ -974,7 +975,7 @@ assign_domain_mmio_page(struct domain *d
                 __func__, __LINE__, d, mpaddr, size);
         return -EINVAL;
     }
-    assign_domain_same_page(d, mpaddr, size, ASSIGN_writable |
ASSIGN_nocache);
+    assign_domain_same_page(d, mpaddr, size, flags | ASSIGN_nocache);
     return mpaddr;
 }
 
diff -r 0e32095a7b46 -r 0b37070e2efb xen/arch/powerpc/domain_build.c
--- a/xen/arch/powerpc/domain_build.c   Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/arch/powerpc/domain_build.c   Wed Aug 16 10:42:41 2006 +0100
@@ -276,7 +276,7 @@ int construct_dom0(struct domain *d,
     rc = 0;
 
     /* DOM0 is permitted full I/O capabilities. */
-    rc |= iomem_permit_access(dom0, 0UL, ~0UL);
+    rc |= iomem_permit_access(dom0, 0UL, ~0UL, IOMEM_ACCESS_READWRITE);
     rc |= irqs_permit_access(dom0, 0, NR_IRQS-1);
 
     BUG_ON(rc != 0);
diff -r 0e32095a7b46 -r 0b37070e2efb xen/arch/x86/domain_build.c
--- a/xen/arch/x86/domain_build.c       Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/arch/x86/domain_build.c       Wed Aug 16 10:42:41 2006 +0100
@@ -815,7 +815,7 @@ int construct_dom0(struct domain *d,
 
     /* DOM0 is permitted full I/O capabilities. */
     rc |= ioports_permit_access(dom0, 0, 0xFFFF);
-    rc |= iomem_permit_access(dom0, 0UL, ~0UL);
+    rc |= iomem_permit_access(dom0, 0UL, ~0UL, IOMEM_ACCESS_READWRITE);
     rc |= irqs_permit_access(dom0, 0, NR_IRQS-1);
 
     /*
diff -r 0e32095a7b46 -r 0b37070e2efb xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/arch/x86/mm.c Wed Aug 16 10:42:41 2006 +0100
@@ -555,7 +555,7 @@ get_page_from_l1e(
 {
     unsigned long mfn = l1e_get_pfn(l1e);
     struct page_info *page = mfn_to_page(mfn);
-    int okay;
+    int okay, access;
 
     if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) )
         return 1;
@@ -573,9 +573,17 @@ get_page_from_l1e(
         if ( d == dom_io )
             d = current->domain;
 
-        if ( !iomem_access_permitted(d, mfn, mfn) )
+        if ( (access = iomem_access_permitted(d, mfn, mfn))
+             == IOMEM_ACCESS_NOACCESS)
         {
             MEM_LOG("Non-privileged attempt to map I/O space %08lx",
mfn);
+            return 0;
+        }
+
+        /* If access is IOMEM_ACCESS_READONLY, the l1e_get_flags below
+           should not have _PAGE_RW set */
+        if(access == IOMEM_ACCESS_READONLY && l1e_get_flags(l1e) &
_PAGE_RW){
+            MEM_LOG("Non-privileged attempt to map readonly I/O space %
08lx", mfn);
             return 0;
         }
 
diff -r 0e32095a7b46 -r 0b37070e2efb xen/common/dom0_ops.c
--- a/xen/common/dom0_ops.c     Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/common/dom0_ops.c     Wed Aug 16 10:42:41 2006 +0100
@@ -678,7 +678,8 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op
             break;
 
         if ( op->u.iomem_permission.allow_access )
-            ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
+            ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1, 
+                                      op->u.iomem_permission.rw);
         else
             ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
 
diff -r 0e32095a7b46 -r 0b37070e2efb xen/common/domain.c
--- a/xen/common/domain.c       Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/common/domain.c       Wed Aug 16 10:42:41 2006 +0100
@@ -147,9 +147,14 @@ struct domain *domain_create(domid_t dom
     if ( arch_domain_create(d) != 0 )
         goto fail3;
 
-    d->iomem_caps = rangeset_new(d, "I/O Memory",
RANGESETF_prettyprint_hex);
+    d->iomem_caps_readwrite = rangeset_new(d, "I/O Memory RW", 
+                                           RANGESETF_prettyprint_hex);
+    d->iomem_caps_readonly  = rangeset_new(d, "I/O Memory RO", 
+                                           RANGESETF_prettyprint_hex);
     d->irq_caps   = rangeset_new(d, "Interrupts", 0);
-    if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
+    if ( (d->iomem_caps_readwrite == NULL) || 
+         (d->iomem_caps_readonly == NULL) ||
+         (d->irq_caps == NULL) )
         goto fail4;
 
     if ( !is_idle_domain(d) )
diff -r 0e32095a7b46 -r 0b37070e2efb xen/include/asm-ia64/mm.h
--- a/xen/include/asm-ia64/mm.h Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/include/asm-ia64/mm.h Wed Aug 16 10:42:41 2006 +0100
@@ -435,7 +435,7 @@ extern unsigned long lookup_domain_mpa(s
 extern unsigned long lookup_domain_mpa(struct domain *d, unsigned long
mpaddr, struct p2m_entry* entry);
 extern void *domain_mpa_to_imva(struct domain *d, unsigned long
mpaddr);
 extern volatile pte_t *lookup_noalloc_domain_pte(struct domain* d,
unsigned long mpaddr);
-extern unsigned long assign_domain_mmio_page(struct domain *d, unsigned
long mpaddr, unsigned long size);
+extern unsigned long assign_domain_mmio_page(struct domain *d, unsigned
long mpaddr, unsigned long size, unsigned long flags);
 extern unsigned long assign_domain_mach_page(struct domain *d, unsigned
long mpaddr, unsigned long size, unsigned long flags);
 int domain_page_mapped(struct domain *d, unsigned long mpaddr);
 int efi_mmio(unsigned long physaddr, unsigned long size);
diff -r 0e32095a7b46 -r 0b37070e2efb xen/include/asm-x86/iocap.h
--- a/xen/include/asm-x86/iocap.h       Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/include/asm-x86/iocap.h       Wed Aug 16 10:42:41 2006 +0100
@@ -14,7 +14,8 @@
 #define ioports_access_permitted(d, s, e)               \
     rangeset_contains_range((d)->arch.ioport_caps, s, e)
 
-#define cache_flush_permitted(d)                       \
-    (!rangeset_is_empty((d)->iomem_caps))
+#define cache_flush_permitted(d)                        \
+  (!(rangeset_is_empty((d)->iomem_caps_readwrite) &&    \
+     rangeset_is_empty((d)->iomem_caps_readonly)))
 
 #endif /* __X86_IOCAP_H__ */
diff -r 0e32095a7b46 -r 0b37070e2efb xen/include/public/dom0_ops.h
--- a/xen/include/public/dom0_ops.h     Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/include/public/dom0_ops.h     Wed Aug 16 10:42:41 2006 +0100
@@ -19,7 +19,7 @@
  * This makes sure that old versions of dom0 tools will stop working in
a
  * well-defined way (rather than crashing the machine, for instance).
  */
-#define DOM0_INTERFACE_VERSION   0x03000001
+#define DOM0_INTERFACE_VERSION   0x03000002
 
 /************************************************************************/
 
@@ -506,6 +506,11 @@ struct dom0_iomem_permission {
     xen_pfn_t first_mfn;      /* first page (physical page number) in
range */
     uint64_t nr_mfns;         /* number of pages in range (>0) */
     uint8_t allow_access;     /* allow (!0) or deny (0) access to
range? */
+#define IOMEM_ACCESS_NOACCESS  0
+#define IOMEM_ACCESS_READWRITE 1
+#define IOMEM_ACCESS_READONLY  2
+    uint8_t rw;               /* read/write permissions to allow.
+                                 Only relevant if allow_access != 0 */
 };
 typedef struct dom0_iomem_permission dom0_iomem_permission_t;
 DEFINE_XEN_GUEST_HANDLE(dom0_iomem_permission_t);
diff -r 0e32095a7b46 -r 0b37070e2efb xen/include/xen/iocap.h
--- a/xen/include/xen/iocap.h   Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/include/xen/iocap.h   Wed Aug 16 10:42:41 2006 +0100
@@ -10,12 +10,24 @@
 #include <xen/rangeset.h>
 #include <asm/iocap.h>
 
-#define iomem_permit_access(d, s, e)                    \
-    rangeset_add_range((d)->iomem_caps, s, e)
-#define iomem_deny_access(d, s, e)                      \
-    rangeset_remove_range((d)->iomem_caps, s, e)
-#define iomem_access_permitted(d, s, e)                 \
-    rangeset_contains_range((d)->iomem_caps, s, e)
+#define IOMEM_ACCESS_NOACCESS  0
+#define IOMEM_ACCESS_READWRITE 1
+#define IOMEM_ACCESS_READONLY  2
+
+#define iomem_permit_access(d, s, e, r)                         \
+    ((r) == IOMEM_ACCESS_READWRITE ?                            \
+      rangeset_add_range((d)->iomem_caps_readwrite, s, e) :     \
+      rangeset_add_range((d)->iomem_caps_readonly, s, e))
+
+#define iomem_deny_access(d, s, e)                              \
+    (rangeset_remove_range((d)->iomem_caps_readwrite, s, e) ||  \
+     rangeset_remove_range((d)->iomem_caps_readonly, s, e))
+
+#define iomem_access_permitted(d, s, e)
\
+    (rangeset_contains_range((d)->iomem_caps_readwrite, s, e) ?
\
+     IOMEM_ACCESS_READWRITE :
\
+     (rangeset_contains_range((d)->iomem_caps_readonly, s, e) ?
\
+      IOMEM_ACCESS_READONLY : IOMEM_ACCESS_NOACCESS))
 
 #define irq_permit_access(d, i)                         \
     rangeset_add_singleton((d)->irq_caps, i)
@@ -29,6 +41,7 @@
     rangeset_contains_singleton((d)->irq_caps, i)
 
 #define multipage_allocation_permitted(d)               \
-    (!rangeset_is_empty((d)->iomem_caps))
+  (!(rangeset_is_empty((d)->iomem_caps_readwrite) &&    \
+     rangeset_is_empty((d)->iomem_caps_readonly)))
 
 #endif /* __XEN_IOCAP_H__ */
diff -r 0e32095a7b46 -r 0b37070e2efb xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Wed Aug 09 21:34:27 2006 +0100
+++ b/xen/include/xen/sched.h   Wed Aug 16 10:42:41 2006 +0100
@@ -139,7 +139,8 @@ struct domain
     DECLARE_BITMAP(pirq_mask, NR_IRQS);
 
     /* I/O capabilities (access to IRQs and memory-mapped I/O). */
-    struct rangeset *iomem_caps;
+    struct rangeset *iomem_caps_readwrite;
+    struct rangeset *iomem_caps_readonly;
     struct rangeset *irq_caps;
 
     unsigned long    domain_flags;



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.