WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

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

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [Patch] Read-only iomem page mapping
From: Kieran Mansley <kmansley@xxxxxxxxxxxxxx>
Date: Wed, 16 Aug 2006 11:06:56 +0100
Delivery-date: Wed, 16 Aug 2006 03:07:32 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [Patch] Read-only iomem page mapping, Kieran Mansley <=