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

Re: [Xen-devel] CONFIG_XEN_COMPAT_030002 broken?



Jan Beulich wrote:
> not nice for use in (early) feature detection. Maybe it'd be better to try 
> and write
> a page table entry without PAGE_USER, and check whether that bit got turned
> on implicitly...

Patch attached, seems to work ok, survived quick test with ttylinux on
both 3.0.3 and 3.0.2 without crashing and detected both versions correctly.

cheers,
  Gerd

-- 
Gerd Hoffmann <kraxel@xxxxxxx>
http://www.suse.de/~kraxel/julika-dora.jpeg
---
 linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c                |    4 
 linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c                 |   52 
+++++++++-
 linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h |   26 +++--
 3 files changed, 73 insertions(+), 9 deletions(-)

Index: build-64-testing-11774/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c
===================================================================
--- build-64-testing-11774.orig/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c
+++ build-64-testing-11774/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c
@@ -250,6 +250,10 @@ void __iomem * __ioremap(unsigned long p
        area->phys_addr = phys_addr;
        addr = (void __iomem *) area->addr;
        flags |= _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED;
+#if defined(__x86_64__) && defined(CONFIG_XEN_COMPAT_030002)
+       if (kernel_pages_need_user_flag)
+               flags |= _PAGE_USER;
+#endif
        if (__direct_remap_pfn_range(&init_mm, (unsigned long)addr,
                                     phys_addr>>PAGE_SHIFT,
                                     size, __pgprot(flags), domid)) {
Index: build-64-testing-11774/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c
===================================================================
--- build-64-testing-11774.orig/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c
+++ build-64-testing-11774/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c
@@ -56,6 +56,12 @@
 struct dma_mapping_ops* dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
+#ifdef CONFIG_XEN_COMPAT_030002
+int kernel_pages_need_user_flag = 1;
+unsigned long kernel_page_user = _PAGE_USER;
+EXPORT_SYMBOL(kernel_page_user);
+#endif
+
 extern unsigned long *contiguous_bitmap;
 
 static unsigned long dma_reserve __initdata;
@@ -507,7 +513,49 @@ static void __meminit phys_pud_init(pud_
                spin_unlock(&init_mm.page_table_lock);
        }
        __flush_tlb();
-} 
+}
+
+#ifdef CONFIG_XEN_COMPAT_030002
+/*
+ * should we set _PAGE_USER for kernel pages?
+ *   - must be set when running on xen 3.0.2
+ *   - should not be set on xen 3.0.3 (kills tlb flush optimization).
+ */
+static void __init check_page_user_flag(unsigned long *pmd)
+{
+       unsigned long addr, *pte;
+        mmu_update_t u;
+
+       addr = pmd[pmd_index(__START_KERNEL_map)];
+       addr_to_page(addr, pte);
+
+       /* try to clear _PAGE_USER */
+        u.ptr = virt_to_machine(pte);
+        u.val = pte[0] & ~_PAGE_USER;
+       if (HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0) {
+               printk("%s: clear _PAGE_USER: mmu_update failed\n", 
__FUNCTION__);
+               return;
+       }
+
+       if (pte[0] & _PAGE_USER) {
+               /* xen 3.0.3 automagically sets _PAGE_USER */
+               printk("%s: xen 3.0.3+ detected\n", __FUNCTION__);
+               kernel_pages_need_user_flag = 0;
+               kernel_page_user = 0;
+               return;
+       }
+       printk("%s: xen 3.0.2 detected\n", __FUNCTION__);
+
+       /* restore previous state */
+       u.ptr = virt_to_machine(pte);
+       u.val = pte[0] | _PAGE_USER;
+       if (HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0) {
+               printk("%s: set _PAGE_USER: mmu_update failed\n", __FUNCTION__);
+       }
+}
+#else
+static void __init check_page_user_flag(unsigned long *pmd) {}
+#endif
 
 void __init xen_init_pt(void)
 {
@@ -524,6 +572,8 @@ void __init xen_init_pt(void)
        addr = page[pud_index(__START_KERNEL_map)];
        addr_to_page(addr, page);
 
+       check_page_user_flag(page);
+
        /* Construct mapping of initial pte page in our own directories. */
        init_level4_pgt[pgd_index(__START_KERNEL_map)] = 
                mk_kernel_pgd(__pa_symbol(level3_kernel_pgt));
Index: 
build-64-testing-11774/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h
===================================================================
--- 
build-64-testing-11774.orig/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h
+++ 
build-64-testing-11774/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h
@@ -205,8 +205,16 @@ static inline pte_t ptep_get_and_clear_f
 #define _PAGE_PROTNONE 0x080   /* If not present */
 #define _PAGE_NX        (1UL<<_PAGE_BIT_NX)
 
+#ifdef CONFIG_XEN_COMPAT_030002
+extern int kernel_pages_need_user_flag;
+extern unsigned long kernel_page_user;
+#else
+#define kernel_pages_need_user_flag 0
+#define kernel_page_user 0
+#endif
+
 #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED 
| _PAGE_DIRTY)
-#define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | 
_PAGE_DIRTY)
+#define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | 
_PAGE_DIRTY | kernel_page_user)
 
 #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
@@ -218,22 +226,24 @@ static inline pte_t ptep_get_and_clear_f
 #define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | 
_PAGE_NX)
 #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | 
_PAGE_ACCESSED)
+
 #define __PAGE_KERNEL \
-       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | 
kernel_page_user )
 #define __PAGE_KERNEL_EXEC \
-       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | 
kernel_page_user )
 #define __PAGE_KERNEL_NOCACHE \
-       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | 
_PAGE_NX)
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | 
_PAGE_NX | kernel_page_user )
 #define __PAGE_KERNEL_RO \
-       (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+       (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | 
kernel_page_user )
 #define __PAGE_KERNEL_VSYSCALL \
        (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define __PAGE_KERNEL_VSYSCALL_NOCACHE \
        (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PCD)
 #define __PAGE_KERNEL_LARGE \
-       (__PAGE_KERNEL | _PAGE_PSE)
+       (__PAGE_KERNEL | _PAGE_PSE | kernel_page_user )
 #define __PAGE_KERNEL_LARGE_EXEC \
-       (__PAGE_KERNEL_EXEC | _PAGE_PSE)
+       (__PAGE_KERNEL_EXEC | _PAGE_PSE | kernel_page_user )
+
 
 /*
  * We don't support GLOBAL page in xenolinux64
@@ -422,7 +432,7 @@ static inline pud_t *pud_offset_k(pgd_t 
    can temporarily clear it. */
 #define pmd_present(x) (pmd_val(x))
 #define pmd_clear(xp)  do { set_pmd(xp, __pmd(0)); } while (0)
-#define        pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER & 
~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_PRESENT))
+#define        pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER & 
~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_USER & ~_PAGE_PRESENT))
 #define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot)))
 #define pmd_pfn(x)  ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT)
 
_______________________________________________
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®.