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@level5networks.com # HG changeset patch # User kjm@moonstone.uk.level5networks.com # 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@lists.xensource.com http://lists.xensource.com/xen-devel