powerpc32: adds handling of _PAGE_RO
authorLEROY Christophe <christophe.leroy@c-s.fr>
Mon, 19 Jan 2015 16:04:38 +0000 (17:04 +0100)
committerScott Wood <scottwood@freescale.com>
Fri, 30 Jan 2015 02:11:51 +0000 (20:11 -0600)
Some powerpc like the 8xx don't have a RW bit in PTE bits but a RO
(Read Only) bit.  This patch implements the handling of a _PAGE_RO flag
to be used in place of _PAGE_RW

Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
[scottwood@freescale.com: fix whitespace]
Signed-off-by: Scott Wood <scottwood@freescale.com>
arch/powerpc/include/asm/pgtable-ppc32.h
arch/powerpc/include/asm/pgtable.h
arch/powerpc/include/asm/pte-common.h
arch/powerpc/mm/pgtable_32.c

index 234e07c478032728861bb918664e48592cf0f712..62a3e49a9a149c77ce2701ba2d91d7a020085b10 100644 (file)
@@ -275,7 +275,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
                                      pte_t *ptep)
 {
-       pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0);
+       pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), _PAGE_RO);
 }
 static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
                                           unsigned long addr, pte_t *ptep)
@@ -286,9 +286,11 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 
 static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
 {
-       unsigned long bits = pte_val(entry) &
+       unsigned long set = pte_val(entry) &
                (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
-       pte_update(ptep, 0, bits);
+       unsigned long clr = ~pte_val(entry) & _PAGE_RO;
+
+       pte_update(ptep, clr, set);
 }
 
 #define __HAVE_ARCH_PTE_SAME
index a8805fee0df91bffdcdc4560e0b259985df2f930..7e77f2ca51325a7c36782b8507ceb6fcbb5a7b2e 100644 (file)
@@ -30,7 +30,8 @@ struct mm_struct;
 #include <asm/tlbflush.h>
 
 /* Generic accessors to PTE bits */
-static inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_write(pte_t pte)
+{      return (pte_val(pte) & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO; }
 static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
@@ -115,12 +116,14 @@ static inline unsigned long pte_pfn(pte_t pte)    {
 
 /* Generic modifiers for PTE bits */
 static inline pte_t pte_wrprotect(pte_t pte) {
-       pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+       pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE);
+       pte_val(pte) |= _PAGE_RO; return pte; }
 static inline pte_t pte_mkclean(pte_t pte) {
        pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
 static inline pte_t pte_mkold(pte_t pte) {
        pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte) {
+       pte_val(pte) &= ~_PAGE_RO;
        pte_val(pte) |= _PAGE_RW; return pte; }
 static inline pte_t pte_mkdirty(pte_t pte) {
        pte_val(pte) |= _PAGE_DIRTY; return pte; }
index e040c3595129e41f502ba873502a1571b0076b9e..2aef9b7a0eb2afc8635c4d658ae0bd32ae8c463a 100644 (file)
 #ifndef _PAGE_PSIZE
 #define _PAGE_PSIZE            0
 #endif
+/* _PAGE_RO and _PAGE_RW shall not be defined at the same time */
+#ifndef _PAGE_RO
+#define _PAGE_RO 0
+#else
+#define _PAGE_RW 0
+#endif
 #ifndef _PMD_PRESENT_MASK
 #define _PMD_PRESENT_MASK      _PMD_PRESENT
 #endif
 #define PMD_PAGE_SIZE(pmd)     bad_call_to_PMD_PAGE_SIZE()
 #endif
 #ifndef _PAGE_KERNEL_RO
-#define _PAGE_KERNEL_RO                0
+#define _PAGE_KERNEL_RO                (_PAGE_RO)
 #endif
 #ifndef _PAGE_KERNEL_ROX
-#define _PAGE_KERNEL_ROX       (_PAGE_EXEC)
+#define _PAGE_KERNEL_ROX       (_PAGE_EXEC | _PAGE_RO)
 #endif
 #ifndef _PAGE_KERNEL_RW
 #define _PAGE_KERNEL_RW                (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE)
@@ -95,7 +101,7 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
 /* Mask of bits returned by pte_pgprot() */
 #define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
                         _PAGE_WRITETHRU | _PAGE_ENDIAN | _PAGE_4K_PFN | \
-                        _PAGE_USER | _PAGE_ACCESSED | \
+                        _PAGE_USER | _PAGE_ACCESSED | _PAGE_RO | \
                         _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_EXEC)
 
 #ifdef CONFIG_NUMA_BALANCING
@@ -128,11 +134,14 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
  */
 #define PAGE_NONE      __pgprot(_PAGE_BASE)
 #define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
-#define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
-#define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_READONLY  __pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X        __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | \
+                                _PAGE_EXEC)
+#define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO)
+#define PAGE_COPY_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \
+                                _PAGE_EXEC)
+#define PAGE_READONLY  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO)
+#define PAGE_READONLY_X        __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \
+                                _PAGE_EXEC)
 
 #define __P000 PAGE_NONE
 #define __P001 PAGE_READONLY
index 6eec88685a71b5c5f805f3eebfb031f399957288..833139620431282abb7fd3e1fba3e84922c67cc6 100644 (file)
@@ -146,7 +146,7 @@ void __iomem *
 ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags)
 {
        /* writeable implies dirty for kernel addresses */
-       if (flags & _PAGE_RW)
+       if ((flags & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO)
                flags |= _PAGE_DIRTY | _PAGE_HWWRITE;
 
        /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */