x86: add PAGE_KERNEL_EXEC_NOCACHE
[sfrench/cifs-2.6.git] / include / asm-x86 / pgtable.h
index 820db41dbe4c9bd771f2594a8e99e828c94cd4b9..ee40a88882f60f824c68fb35f8b32d8ca782a415 100644 (file)
 #define _PAGE_BIT_UNUSED3      11
 #define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
 
+/*
+ * Note: we use _AC(1, L) instead of _AC(1, UL) so that we get a
+ * sign-extended value on 32-bit with all 1's in the upper word,
+ * which preserves the upper pte values on 64-bit ptes:
+ */
 #define _PAGE_PRESENT  (_AC(1, L)<<_PAGE_BIT_PRESENT)
 #define _PAGE_RW       (_AC(1, L)<<_PAGE_BIT_RW)
 #define _PAGE_USER     (_AC(1, L)<<_PAGE_BIT_USER)
@@ -64,7 +69,7 @@
 #define _PAGE_KERNEL (_PAGE_KERNEL_EXEC | _PAGE_NX)
 
 #ifndef __ASSEMBLY__
-extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
+extern pteval_t __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
 #endif /* __ASSEMBLY__ */
 #else
 #define __PAGE_KERNEL_EXEC                                             \
@@ -74,6 +79,7 @@ extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
 
 #define __PAGE_KERNEL_RO               (__PAGE_KERNEL & ~_PAGE_RW)
 #define __PAGE_KERNEL_RX               (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
+#define __PAGE_KERNEL_EXEC_NOCACHE     (__PAGE_KERNEL_EXEC | _PAGE_PCD | _PAGE_PWT)
 #define __PAGE_KERNEL_NOCACHE          (__PAGE_KERNEL | _PAGE_PCD | _PAGE_PWT)
 #define __PAGE_KERNEL_VSYSCALL         (__PAGE_KERNEL_RX | _PAGE_USER)
 #define __PAGE_KERNEL_VSYSCALL_NOCACHE (__PAGE_KERNEL_VSYSCALL | _PAGE_PCD | _PAGE_PWT)
@@ -91,6 +97,7 @@ extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
 #define PAGE_KERNEL_EXEC               MAKE_GLOBAL(__PAGE_KERNEL_EXEC)
 #define PAGE_KERNEL_RX                 MAKE_GLOBAL(__PAGE_KERNEL_RX)
 #define PAGE_KERNEL_NOCACHE            MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
+#define PAGE_KERNEL_EXEC_NOCACHE       MAKE_GLOBAL(__PAGE_KERNEL_EXEC_NOCACHE)
 #define PAGE_KERNEL_LARGE              MAKE_GLOBAL(__PAGE_KERNEL_LARGE)
 #define PAGE_KERNEL_LARGE_EXEC         MAKE_GLOBAL(__PAGE_KERNEL_LARGE_EXEC)
 #define PAGE_KERNEL_VSYSCALL           MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL)
@@ -117,6 +124,14 @@ extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
 
 #ifndef __ASSEMBLY__
 
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
@@ -126,21 +141,25 @@ static inline int pte_young(pte_t pte)            { return pte_val(pte) & _PAGE_ACCESSED;
 static inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_RW; }
 static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_huge(pte_t pte)          { return pte_val(pte) & _PAGE_PSE; }
+static inline int pte_global(pte_t pte)        { return pte_val(pte) & _PAGE_GLOBAL; }
+static inline int pte_exec(pte_t pte)          { return !(pte_val(pte) & _PAGE_NX); }
 
 static inline int pmd_large(pmd_t pte) {
        return (pmd_val(pte) & (_PAGE_PSE|_PAGE_PRESENT)) ==
                (_PAGE_PSE|_PAGE_PRESENT);
 }
 
-static inline pte_t pte_mkclean(pte_t pte)     { return __pte(pte_val(pte) & ~_PAGE_DIRTY); }
-static inline pte_t pte_mkold(pte_t pte)       { return __pte(pte_val(pte) & ~_PAGE_ACCESSED); }
-static inline pte_t pte_wrprotect(pte_t pte)   { return __pte(pte_val(pte) & ~_PAGE_RW); }
-static inline pte_t pte_mkexec(pte_t pte)      { return __pte(pte_val(pte) & ~_PAGE_NX); }
+static inline pte_t pte_mkclean(pte_t pte)     { return __pte(pte_val(pte) & ~(pteval_t)_PAGE_DIRTY); }
+static inline pte_t pte_mkold(pte_t pte)       { return __pte(pte_val(pte) & ~(pteval_t)_PAGE_ACCESSED); }
+static inline pte_t pte_wrprotect(pte_t pte)   { return __pte(pte_val(pte) & ~(pteval_t)_PAGE_RW); }
+static inline pte_t pte_mkexec(pte_t pte)      { return __pte(pte_val(pte) & ~(pteval_t)_PAGE_NX); }
 static inline pte_t pte_mkdirty(pte_t pte)     { return __pte(pte_val(pte) | _PAGE_DIRTY); }
 static inline pte_t pte_mkyoung(pte_t pte)     { return __pte(pte_val(pte) | _PAGE_ACCESSED); }
 static inline pte_t pte_mkwrite(pte_t pte)     { return __pte(pte_val(pte) | _PAGE_RW); }
 static inline pte_t pte_mkhuge(pte_t pte)      { return __pte(pte_val(pte) | _PAGE_PSE); }
-static inline pte_t pte_clrhuge(pte_t pte)     { return __pte(pte_val(pte) & ~_PAGE_PSE); }
+static inline pte_t pte_clrhuge(pte_t pte)     { return __pte(pte_val(pte) & ~(pteval_t)_PAGE_PSE); }
+static inline pte_t pte_mkglobal(pte_t pte)    { return __pte(pte_val(pte) | _PAGE_GLOBAL); }
+static inline pte_t pte_clrglobal(pte_t pte)   { return __pte(pte_val(pte) & ~(pteval_t)_PAGE_GLOBAL); }
 
 extern pteval_t __supported_pte_mask;
 
@@ -170,6 +189,43 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
        return __pte(val);
 }
 
+#define pte_pgprot(x) __pgprot(pte_val(x) & (0xfff | _PAGE_NX))
+
+#define canon_pgprot(p) __pgprot(pgprot_val(p) & __supported_pte_mask)
+
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else  /* !CONFIG_PARAVIRT */
+#define set_pte(ptep, pte)             native_set_pte(ptep, pte)
+#define set_pte_at(mm, addr, ptep, pte)        native_set_pte_at(mm, addr, ptep, pte)
+
+#define set_pte_present(mm, addr, ptep, pte)                           \
+       native_set_pte_present(mm, addr, ptep, pte)
+#define set_pte_atomic(ptep, pte)                                      \
+       native_set_pte_atomic(ptep, pte)
+
+#define set_pmd(pmdp, pmd)             native_set_pmd(pmdp, pmd)
+
+#ifndef __PAGETABLE_PUD_FOLDED
+#define set_pgd(pgdp, pgd)             native_set_pgd(pgdp, pgd)
+#define pgd_clear(pgd)                 native_pgd_clear(pgd)
+#endif
+
+#ifndef set_pud
+# define set_pud(pudp, pud)            native_set_pud(pudp, pud)
+#endif
+
+#ifndef __PAGETABLE_PMD_FOLDED
+#define pud_clear(pud)                 native_pud_clear(pud)
+#endif
+
+#define pte_clear(mm, addr, ptep)      native_pte_clear(mm, addr, ptep)
+#define pmd_clear(pmd)                 native_pmd_clear(pmd)
+
+#define pte_update(mm, addr, ptep)              do { } while (0)
+#define pte_update_defer(mm, addr, ptep)        do { } while (0)
+#endif /* CONFIG_PARAVIRT */
+
 #endif /* __ASSEMBLY__ */
 
 #ifdef CONFIG_X86_32
@@ -180,6 +236,36 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 #ifndef __ASSEMBLY__
 
+enum {
+       PG_LEVEL_NONE,
+       PG_LEVEL_4K,
+       PG_LEVEL_2M,
+};
+
+/*
+ * Helper function that returns the kernel pagetable entry controlling
+ * the virtual address 'address'. NULL means no pagetable entry present.
+ * NOTE: the return type is pte_t but if the pmd is PSE then we return it
+ * as a pte too.
+ */
+extern pte_t *lookup_address(unsigned long address, int *level);
+
+/* local pte updates need not use xchg for locking */
+static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
+{
+       pte_t res = *ptep;
+
+       /* Pure native function needs no input for mm, addr */
+       native_pte_clear(NULL, 0, ptep);
+       return res;
+}
+
+static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
+                                    pte_t *ptep , pte_t pte)
+{
+       native_set_pte(ptep, pte);
+}
+
 #ifndef CONFIG_PARAVIRT
 /*
  * Rules for using pte_update - it must be called after any PTE update which
@@ -198,16 +284,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pte_update_defer(mm, addr, ptep)       do { } while (0)
 #endif
 
-/* local pte updates need not use xchg for locking */
-static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
-{
-       pte_t res = *ptep;
-
-       /* Pure native function needs no input for mm, addr */
-       native_pte_clear(NULL, 0, ptep);
-       return res;
-}
-
 /*
  * We only update the dirty/accessed state if we set
  * the dirty bit by hand in the kernel, since the hardware
@@ -279,10 +355,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
        pte_update(mm, addr, ptep);
 }
 
-#ifndef CONFIG_PARAVIRT
-#define pte_clear(mm, addr, ptep)              native_pte_clear(mm, addr, ptep)
-#endif /* !CONFIG_PARAVIRT */
-
 #include <asm-generic/pgtable.h>
 #endif /* __ASSEMBLY__ */