kaiser: add "nokaiser" boot option, using ALTERNATIVE
[pandora-kernel.git] / arch / x86 / include / asm / pgtable.h
index 18601c8..a467c19 100644 (file)
 #ifndef __ASSEMBLY__
 
 #include <asm/x86_init.h>
+#ifdef CONFIG_KAISER
+extern int kaiser_enabled;
+#else
+#define kaiser_enabled 0
+#endif
 
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
@@ -142,12 +147,16 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
        return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT;
 }
 
+static inline unsigned long pud_pfn(pud_t pud)
+{
+       return (pud_val(pud) & PTE_PFN_MASK) >> PAGE_SHIFT;
+}
+
 #define pte_page(pte)  pfn_to_page(pte_pfn(pte))
 
 static inline int pmd_large(pmd_t pte)
 {
-       return (pmd_flags(pte) & (_PAGE_PSE | _PAGE_PRESENT)) ==
-               (_PAGE_PSE | _PAGE_PRESENT);
+       return pmd_flags(pte) & _PAGE_PSE;
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -415,7 +424,13 @@ static inline int pte_hidden(pte_t pte)
 
 static inline int pmd_present(pmd_t pmd)
 {
-       return pmd_flags(pmd) & _PAGE_PRESENT;
+       /*
+        * Checking for _PAGE_PSE is needed too because
+        * split_huge_page will temporarily clear the present bit (but
+        * the _PAGE_PSE flag will remain set at all times while the
+        * _PAGE_PRESENT bit is clear).
+        */
+       return pmd_flags(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_PSE);
 }
 
 static inline int pmd_none(pmd_t pmd)
@@ -560,7 +575,17 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
 
 static inline int pgd_bad(pgd_t pgd)
 {
-       return (pgd_flags(pgd) & ~_PAGE_USER) != _KERNPG_TABLE;
+       pgdval_t ignore_flags = _PAGE_USER;
+       /*
+        * We set NX on KAISER pgds that map userspace memory so
+        * that userspace can not meaningfully use the kernel
+        * page table by accident; it will fault on the first
+        * instruction it tries to run.  See native_set_pgd().
+        */
+       if (kaiser_enabled)
+               ignore_flags |= _PAGE_NX;
+
+       return (pgd_flags(pgd) & ~ignore_flags) != _KERNPG_TABLE;
 }
 
 static inline int pgd_none(pgd_t pgd)
@@ -760,7 +785,15 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
  */
 static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
 {
-       memcpy(dst, src, count * sizeof(pgd_t));
+       memcpy(dst, src, count * sizeof(pgd_t));
+#ifdef CONFIG_KAISER
+       if (kaiser_enabled) {
+               /* Clone the shadow pgd part as well */
+               memcpy(native_get_shadow_pgd(dst),
+                       native_get_shadow_pgd(src),
+                       count * sizeof(pgd_t));
+       }
+#endif
 }