x86: teach the static_protection function about high mappings
authorArjan van de Ven <arjan@linux.intel.com>
Mon, 4 Feb 2008 15:48:05 +0000 (16:48 +0100)
committerIngo Molnar <mingo@elte.hu>
Mon, 4 Feb 2008 15:48:05 +0000 (16:48 +0100)
Right now, enforcing that the high mapping of the kernel text doesn't
get the NX bit is done deep in the guts of CPA, rather than in the
static_protection() function that enforces all other per-arch sanity
checks.

This patch moves this sanity check into the central static_protection()
function instead, and makes it apply ONLY to the kernel text, not to all
other areas in the high mapping.

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/mm/pageattr.c

index 877b5cca2cb8534b84c3e5c3fa921ebe960b22fa..bf5e33f6a32235c58b71f2073d5781865f5ddf6c 100644 (file)
@@ -106,6 +106,22 @@ static void cpa_flush_range(unsigned long start, int numpages)
        }
 }
 
+#define HIGH_MAP_START __START_KERNEL_map
+#define HIGH_MAP_END   (__START_KERNEL_map + KERNEL_TEXT_SIZE)
+
+
+/*
+ * Converts a virtual address to a X86-64 highmap address
+ */
+static unsigned long virt_to_highmap(void *address)
+{
+#ifdef CONFIG_X86_64
+       return __pa((unsigned long)address) + HIGH_MAP_START - phys_base;
+#else
+       return (unsigned long)address;
+#endif
+}
+
 /*
  * Certain areas of memory on x86 require very specific protection flags,
  * for example the BIOS area or kernel text. Callers don't always get this
@@ -129,12 +145,24 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
         */
        if (within(address, (unsigned long)_text, (unsigned long)_etext))
                pgprot_val(forbidden) |= _PAGE_NX;
+       /*
+        * Do the same for the x86-64 high kernel mapping
+        */
+       if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext)))
+               pgprot_val(forbidden) |= _PAGE_NX;
+
 
 #ifdef CONFIG_DEBUG_RODATA
        /* The .rodata section needs to be read-only */
        if (within(address, (unsigned long)__start_rodata,
                                (unsigned long)__end_rodata))
                pgprot_val(forbidden) |= _PAGE_RW;
+       /*
+        * Do the same for the x86-64 high kernel mapping
+        */
+       if (within(address, virt_to_highmap(__start_rodata),
+                               virt_to_highmap(__end_rodata)))
+               pgprot_val(forbidden) |= _PAGE_RW;
 #endif
 
        prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
@@ -304,8 +332,6 @@ repeat:
  * Modules and drivers should use the set_memory_* APIs instead.
  */
 
-#define HIGH_MAP_START __START_KERNEL_map
-#define HIGH_MAP_END   (__START_KERNEL_map + KERNEL_TEXT_SIZE)
 
 static int
 change_page_attr_addr(unsigned long address, pgprot_t mask_set,
@@ -338,10 +364,11 @@ change_page_attr_addr(unsigned long address, pgprot_t mask_set,
                /*
                 * Calc the high mapping address. See __phys_addr()
                 * for the non obvious details.
+                *
+                * Note that NX and other required permissions are
+                * checked in static_protections().
                 */
                address = phys_addr + HIGH_MAP_START - phys_base;
-               /* Make sure the kernel mappings stay executable */
-               pgprot_val(mask_clr) |= _PAGE_NX;
 
                /*
                 * Our high aliases are imprecise, because we check