Merge branch 'pgt' (early part) into devel
authorRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 6 Jan 2011 22:33:19 +0000 (22:33 +0000)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 6 Jan 2011 22:33:19 +0000 (22:33 +0000)
15 files changed:
arch/arm/include/asm/page.h
arch/arm/include/asm/pgalloc.h
arch/arm/include/asm/pgtable.h
arch/arm/kernel/smp.c
arch/arm/kernel/traps.c
arch/arm/mm/Makefile
arch/arm/mm/fault-armv.c
arch/arm/mm/fault.c
arch/arm/mm/idmap.c [new file with mode: 0644]
arch/arm/mm/mm.h
arch/arm/mm/mmu.c
arch/arm/mm/pgd.c
arch/arm/mm/proc-macros.S
arch/arm/mm/proc-v7.S
arch/arm/mm/proc-xscale.S

index a485ac3c8696d2cdbc2e9a857ba4298de63e1428..f51a69595f6ed53bc2d46d07a146f8b08ac6b83d 100644 (file)
@@ -151,13 +151,15 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
 #define clear_page(page)       memset((void *)(page), 0, PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
 
+typedef unsigned long pteval_t;
+
 #undef STRICT_MM_TYPECHECKS
 
 #ifdef STRICT_MM_TYPECHECKS
 /*
  * These are used to make use of C type-checking..
  */
-typedef struct { unsigned long pte; } pte_t;
+typedef struct { pteval_t pte; } pte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd[2]; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
@@ -175,7 +177,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 /*
  * .. while these make it easier on the compiler
  */
-typedef unsigned long pte_t;
+typedef pteval_t pte_t;
 typedef unsigned long pmd_t;
 typedef unsigned long pgd_t[2];
 typedef unsigned long pgprot_t;
index b12cc98bbe044649e27ea683f73f1dbffd052072..9763be04f77ee9e15b8e759a1b392cb7f66b3b6f 100644 (file)
 #define pmd_free(mm, pmd)              do { } while (0)
 #define pgd_populate(mm,pmd,pte)       BUG()
 
-extern pgd_t *get_pgd_slow(struct mm_struct *mm);
-extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd);
-
-#define pgd_alloc(mm)                  get_pgd_slow(mm)
-#define pgd_free(mm, pgd)              free_pgd_slow(mm, pgd)
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
 #define PGALLOC_GFP    (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
 
+static inline void clean_pte_table(pte_t *pte)
+{
+       clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE);
+}
+
 /*
  * Allocate one PTE table.
  *
@@ -45,14 +47,14 @@ extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd);
  * into one table thus:
  *
  *  +------------+
- *  |  h/w pt 0  |
- *  +------------+
- *  |  h/w pt 1  |
- *  +------------+
  *  | Linux pt 0 |
  *  +------------+
  *  | Linux pt 1 |
  *  +------------+
+ *  |  h/w pt 0  |
+ *  +------------+
+ *  |  h/w pt 1  |
+ *  +------------+
  */
 static inline pte_t *
 pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
@@ -60,10 +62,8 @@ pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
        pte_t *pte;
 
        pte = (pte_t *)__get_free_page(PGALLOC_GFP);
-       if (pte) {
-               clean_dcache_area(pte, sizeof(pte_t) * PTRS_PER_PTE);
-               pte += PTRS_PER_PTE;
-       }
+       if (pte)
+               clean_pte_table(pte);
 
        return pte;
 }
@@ -79,10 +79,8 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr)
        pte = alloc_pages(PGALLOC_GFP, 0);
 #endif
        if (pte) {
-               if (!PageHighMem(pte)) {
-                       void *page = page_address(pte);
-                       clean_dcache_area(page, sizeof(pte_t) * PTRS_PER_PTE);
-               }
+               if (!PageHighMem(pte))
+                       clean_pte_table(page_address(pte));
                pgtable_page_ctor(pte);
        }
 
@@ -94,10 +92,8 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr)
  */
 static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
-       if (pte) {
-               pte -= PTRS_PER_PTE;
+       if (pte)
                free_page((unsigned long)pte);
-       }
 }
 
 static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
@@ -106,8 +102,10 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        __free_page(pte);
 }
 
-static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval)
+static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
+       unsigned long prot)
 {
+       unsigned long pmdval = (pte + PTE_HWTABLE_OFF) | prot;
        pmdp[0] = __pmd(pmdval);
        pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
        flush_pmd_entry(pmdp);
@@ -122,20 +120,16 @@ static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval)
 static inline void
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
 {
-       unsigned long pte_ptr = (unsigned long)ptep;
-
        /*
-        * The pmd must be loaded with the physical
-        * address of the PTE table
+        * The pmd must be loaded with the physical address of the PTE table
         */
-       pte_ptr -= PTRS_PER_PTE * sizeof(void *);
-       __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE);
+       __pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE);
 }
 
 static inline void
 pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
 {
-       __pmd_populate(pmdp, page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE);
+       __pmd_populate(pmdp, page_to_phys(ptep), _PAGE_USER_TABLE);
 }
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
index 53d1d5deb1115b1fe11a52846e62679573534d24..ebcb6432f45f829daaa0c33818b7347fe8df26c1 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef _ASMARM_PGTABLE_H
 #define _ASMARM_PGTABLE_H
 
+#include <linux/const.h>
 #include <asm-generic/4level-fixup.h>
 #include <asm/proc-fns.h>
 
@@ -54,7 +55,7 @@
  * Therefore, we tweak the implementation slightly - we tell Linux that we
  * have 2048 entries in the first level, each of which is 8 bytes (iow, two
  * hardware pointers to the second level.)  The second level contains two
- * hardware PTE tables arranged contiguously, followed by Linux versions
+ * hardware PTE tables arranged contiguously, preceded by Linux versions
  * which contain the state information Linux needs.  We, therefore, end up
  * with 512 entries in the "PTE" level.
  *
  *
  *    pgd             pte
  * |        |
- * +--------+ +0
- * |        |-----> +------------+ +0
+ * +--------+
+ * |        |       +------------+ +0
+ * +- - - - +       | Linux pt 0 |
+ * |        |       +------------+ +1024
+ * +--------+ +0    | Linux pt 1 |
+ * |        |-----> +------------+ +2048
  * +- - - - + +4    |  h/w pt 0  |
- * |        |-----> +------------+ +1024
+ * |        |-----> +------------+ +3072
  * +--------+ +8    |  h/w pt 1  |
- * |        |       +------------+ +2048
- * +- - - - +       | Linux pt 0 |
- * |        |       +------------+ +3072
- * +--------+       | Linux pt 1 |
  * |        |       +------------+ +4096
  *
  * See L_PTE_xxx below for definitions of bits in the "Linux pt", and
 #define PTRS_PER_PMD           1
 #define PTRS_PER_PGD           2048
 
+#define PTE_HWTABLE_PTRS       (PTRS_PER_PTE)
+#define PTE_HWTABLE_OFF                (PTE_HWTABLE_PTRS * sizeof(pte_t))
+#define PTE_HWTABLE_SIZE       (PTRS_PER_PTE * sizeof(u32))
+
 /*
  * PMD_SHIFT determines the size of the area a second-level page table can map
  * PGDIR_SHIFT determines what a third-level page table entry can map
 #define LIBRARY_TEXT_START     0x0c000000
 
 #ifndef __ASSEMBLY__
-extern void __pte_error(const char *file, int line, unsigned long val);
-extern void __pmd_error(const char *file, int line, unsigned long val);
-extern void __pgd_error(const char *file, int line, unsigned long val);
+extern void __pte_error(const char *file, int line, pte_t);
+extern void __pmd_error(const char *file, int line, pmd_t);
+extern void __pgd_error(const char *file, int line, pgd_t);
 
-#define pte_ERROR(pte)         __pte_error(__FILE__, __LINE__, pte_val(pte))
-#define pmd_ERROR(pmd)         __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
-#define pgd_ERROR(pgd)         __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
+#define pte_ERROR(pte)         __pte_error(__FILE__, __LINE__, pte)
+#define pmd_ERROR(pmd)         __pmd_error(__FILE__, __LINE__, pmd)
+#define pgd_ERROR(pgd)         __pgd_error(__FILE__, __LINE__, pgd)
 #endif /* !__ASSEMBLY__ */
 
 #define PMD_SIZE               (1UL << PMD_SHIFT)
@@ -133,8 +138,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
  */
 #define FIRST_USER_ADDRESS     PAGE_SIZE
 
-#define FIRST_USER_PGD_NR      1
-#define USER_PTRS_PER_PGD      ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)
+#define USER_PTRS_PER_PGD      (TASK_SIZE / PGDIR_SIZE)
 
 /*
  * section address mask and size definitions.
@@ -161,30 +165,30 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
  * The PTE table pointer refers to the hardware entries; the "Linux"
  * entries are stored 1024 bytes below.
  */
-#define L_PTE_PRESENT          (1 << 0)
-#define L_PTE_YOUNG            (1 << 1)
-#define L_PTE_FILE             (1 << 2)        /* only when !PRESENT */
-#define L_PTE_DIRTY            (1 << 6)
-#define L_PTE_WRITE            (1 << 7)
-#define L_PTE_USER             (1 << 8)
-#define L_PTE_EXEC             (1 << 9)
-#define L_PTE_SHARED           (1 << 10)       /* shared(v6), coherent(xsc3) */
+#define L_PTE_PRESENT          (_AT(pteval_t, 1) << 0)
+#define L_PTE_YOUNG            (_AT(pteval_t, 1) << 1)
+#define L_PTE_FILE             (_AT(pteval_t, 1) << 2) /* only when !PRESENT */
+#define L_PTE_DIRTY            (_AT(pteval_t, 1) << 6)
+#define L_PTE_RDONLY           (_AT(pteval_t, 1) << 7)
+#define L_PTE_USER             (_AT(pteval_t, 1) << 8)
+#define L_PTE_XN               (_AT(pteval_t, 1) << 9)
+#define L_PTE_SHARED           (_AT(pteval_t, 1) << 10)        /* shared(v6), coherent(xsc3) */
 
 /*
  * These are the memory types, defined to be compatible with
  * pre-ARMv6 CPUs cacheable and bufferable bits:   XXCB
  */
-#define L_PTE_MT_UNCACHED      (0x00 << 2)     /* 0000 */
-#define L_PTE_MT_BUFFERABLE    (0x01 << 2)     /* 0001 */
-#define L_PTE_MT_WRITETHROUGH  (0x02 << 2)     /* 0010 */
-#define L_PTE_MT_WRITEBACK     (0x03 << 2)     /* 0011 */
-#define L_PTE_MT_MINICACHE     (0x06 << 2)     /* 0110 (sa1100, xscale) */
-#define L_PTE_MT_WRITEALLOC    (0x07 << 2)     /* 0111 */
-#define L_PTE_MT_DEV_SHARED    (0x04 << 2)     /* 0100 */
-#define L_PTE_MT_DEV_NONSHARED (0x0c << 2)     /* 1100 */
-#define L_PTE_MT_DEV_WC                (0x09 << 2)     /* 1001 */
-#define L_PTE_MT_DEV_CACHED    (0x0b << 2)     /* 1011 */
-#define L_PTE_MT_MASK          (0x0f << 2)
+#define L_PTE_MT_UNCACHED      (_AT(pteval_t, 0x00) << 2)      /* 0000 */
+#define L_PTE_MT_BUFFERABLE    (_AT(pteval_t, 0x01) << 2)      /* 0001 */
+#define L_PTE_MT_WRITETHROUGH  (_AT(pteval_t, 0x02) << 2)      /* 0010 */
+#define L_PTE_MT_WRITEBACK     (_AT(pteval_t, 0x03) << 2)      /* 0011 */
+#define L_PTE_MT_MINICACHE     (_AT(pteval_t, 0x06) << 2)      /* 0110 (sa1100, xscale) */
+#define L_PTE_MT_WRITEALLOC    (_AT(pteval_t, 0x07) << 2)      /* 0111 */
+#define L_PTE_MT_DEV_SHARED    (_AT(pteval_t, 0x04) << 2)      /* 0100 */
+#define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 0x0c) << 2)      /* 1100 */
+#define L_PTE_MT_DEV_WC                (_AT(pteval_t, 0x09) << 2)      /* 1001 */
+#define L_PTE_MT_DEV_CACHED    (_AT(pteval_t, 0x0b) << 2)      /* 1011 */
+#define L_PTE_MT_MASK          (_AT(pteval_t, 0x0f) << 2)
 
 #ifndef __ASSEMBLY__
 
@@ -201,23 +205,44 @@ extern pgprot_t           pgprot_kernel;
 
 #define _MOD_PROT(p, b)        __pgprot(pgprot_val(p) | (b))
 
-#define PAGE_NONE              pgprot_user
-#define PAGE_SHARED            _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE)
-#define PAGE_SHARED_EXEC       _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE | L_PTE_EXEC)
-#define PAGE_COPY              _MOD_PROT(pgprot_user, L_PTE_USER)
-#define PAGE_COPY_EXEC         _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_EXEC)
-#define PAGE_READONLY          _MOD_PROT(pgprot_user, L_PTE_USER)
-#define PAGE_READONLY_EXEC     _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_EXEC)
-#define PAGE_KERNEL            pgprot_kernel
-#define PAGE_KERNEL_EXEC       _MOD_PROT(pgprot_kernel, L_PTE_EXEC)
-
-#define __PAGE_NONE            __pgprot(_L_PTE_DEFAULT)
-#define __PAGE_SHARED          __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE)
-#define __PAGE_SHARED_EXEC     __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE | L_PTE_EXEC)
-#define __PAGE_COPY            __pgprot(_L_PTE_DEFAULT | L_PTE_USER)
-#define __PAGE_COPY_EXEC       __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_EXEC)
-#define __PAGE_READONLY                __pgprot(_L_PTE_DEFAULT | L_PTE_USER)
-#define __PAGE_READONLY_EXEC   __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_EXEC)
+#define PAGE_NONE              _MOD_PROT(pgprot_user, L_PTE_XN | L_PTE_RDONLY)
+#define PAGE_SHARED            _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_XN)
+#define PAGE_SHARED_EXEC       _MOD_PROT(pgprot_user, L_PTE_USER)
+#define PAGE_COPY              _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY | L_PTE_XN)
+#define PAGE_COPY_EXEC         _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY)
+#define PAGE_READONLY          _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY | L_PTE_XN)
+#define PAGE_READONLY_EXEC     _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY)
+#define PAGE_KERNEL            _MOD_PROT(pgprot_kernel, L_PTE_XN)
+#define PAGE_KERNEL_EXEC       pgprot_kernel
+
+#define __PAGE_NONE            __pgprot(_L_PTE_DEFAULT | L_PTE_RDONLY | L_PTE_XN)
+#define __PAGE_SHARED          __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN)
+#define __PAGE_SHARED_EXEC     __pgprot(_L_PTE_DEFAULT | L_PTE_USER)
+#define __PAGE_COPY            __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_RDONLY | L_PTE_XN)
+#define __PAGE_COPY_EXEC       __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_RDONLY)
+#define __PAGE_READONLY                __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_RDONLY | L_PTE_XN)
+#define __PAGE_READONLY_EXEC   __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_RDONLY)
+
+#define __pgprot_modify(prot,mask,bits)                \
+       __pgprot((pgprot_val(prot) & ~(mask)) | (bits))
+
+#define pgprot_noncached(prot) \
+       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
+
+#define pgprot_writecombine(prot) \
+       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
+
+#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+#define pgprot_dmacoherent(prot) \
+       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN)
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+                                    unsigned long size, pgprot_t vma_prot);
+#else
+#define pgprot_dmacoherent(prot) \
+       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED | L_PTE_XN)
+#endif
 
 #endif /* __ASSEMBLY__ */
 
@@ -255,26 +280,84 @@ extern pgprot_t           pgprot_kernel;
 extern struct page *empty_zero_page;
 #define ZERO_PAGE(vaddr)       (empty_zero_page)
 
-#define pte_pfn(pte)           (pte_val(pte) >> PAGE_SHIFT)
-#define pfn_pte(pfn,prot)      (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)))
 
-#define pte_none(pte)          (!pte_val(pte))
-#define pte_clear(mm,addr,ptep)        set_pte_ext(ptep, __pte(0), 0)
-#define pte_page(pte)          (pfn_to_page(pte_pfn(pte)))
-#define pte_offset_kernel(dir,addr)    (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(addr)                ((addr) >> PGDIR_SHIFT)
+
+#define pgd_offset(mm, addr)   ((mm)->pgd + pgd_index(addr))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(addr)     pgd_offset(&init_mm, addr)
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+#define pgd_none(pgd)          (0)
+#define pgd_bad(pgd)           (0)
+#define pgd_present(pgd)       (1)
+#define pgd_clear(pgdp)                do { } while (0)
+#define set_pgd(pgd,pgdp)      do { } while (0)
+
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir, addr)  ((pmd_t *)(dir))
+
+#define pmd_none(pmd)          (!pmd_val(pmd))
+#define pmd_present(pmd)       (pmd_val(pmd))
+#define pmd_bad(pmd)           (pmd_val(pmd) & 2)
+
+#define copy_pmd(pmdpd,pmdps)          \
+       do {                            \
+               pmdpd[0] = pmdps[0];    \
+               pmdpd[1] = pmdps[1];    \
+               flush_pmd_entry(pmdpd); \
+       } while (0)
+
+#define pmd_clear(pmdp)                        \
+       do {                            \
+               pmdp[0] = __pmd(0);     \
+               pmdp[1] = __pmd(0);     \
+               clean_pmd_entry(pmdp);  \
+       } while (0)
+
+static inline pte_t *pmd_page_vaddr(pmd_t pmd)
+{
+       return __va(pmd_val(pmd) & PAGE_MASK);
+}
+
+#define pmd_page(pmd)          pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
+
+/* we don't need complex calculations here as the pmd is folded into the pgd */
+#define pmd_addr_end(addr,end) (end)
 
-#define pte_offset_map(dir,addr)       (__pte_map(dir) + __pte_index(addr))
-#define pte_unmap(pte)                 __pte_unmap(pte)
 
 #ifndef CONFIG_HIGHPTE
-#define __pte_map(dir)         pmd_page_vaddr(*(dir))
+#define __pte_map(pmd)         pmd_page_vaddr(*(pmd))
 #define __pte_unmap(pte)       do { } while (0)
 #else
-#define __pte_map(dir)         ((pte_t *)kmap_atomic(pmd_page(*(dir))) + PTRS_PER_PTE)
-#define __pte_unmap(pte)       kunmap_atomic((pte - PTRS_PER_PTE))
+#define __pte_map(pmd)         (pte_t *)kmap_atomic(pmd_page(*(pmd)))
+#define __pte_unmap(pte)       kunmap_atomic(pte)
 #endif
 
+#define pte_index(addr)                (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+
+#define pte_offset_kernel(pmd,addr)    (pmd_page_vaddr(*(pmd)) + pte_index(addr))
+
+#define pte_offset_map(pmd,addr)       (__pte_map(pmd) + pte_index(addr))
+#define pte_unmap(pte)                 __pte_unmap(pte)
+
+#define pte_pfn(pte)           (pte_val(pte) >> PAGE_SHIFT)
+#define pfn_pte(pfn,prot)      __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+
+#define pte_page(pte)          pfn_to_page(pte_pfn(pte))
+#define mk_pte(page,prot)      pfn_pte(page_to_pfn(page), prot)
+
 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
+#define pte_clear(mm,addr,ptep)        set_pte_ext(ptep, __pte(0), 0)
 
 #if __LINUX_ARM_ARCH__ < 6
 static inline void __sync_icache_dcache(pte_t pteval)
@@ -295,15 +378,12 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
        }
 }
 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
+#define pte_none(pte)          (!pte_val(pte))
 #define pte_present(pte)       (pte_val(pte) & L_PTE_PRESENT)
-#define pte_write(pte)         (pte_val(pte) & L_PTE_WRITE)
+#define pte_write(pte)         (!(pte_val(pte) & L_PTE_RDONLY))
 #define pte_dirty(pte)         (pte_val(pte) & L_PTE_DIRTY)
 #define pte_young(pte)         (pte_val(pte) & L_PTE_YOUNG)
-#define pte_exec(pte)          (pte_val(pte) & L_PTE_EXEC)
+#define pte_exec(pte)          (!(pte_val(pte) & L_PTE_XN))
 #define pte_special(pte)       (0)
 
 #define pte_present_user(pte) \
@@ -313,8 +393,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
 
-PTE_BIT_FUNC(wrprotect, &= ~L_PTE_WRITE);
-PTE_BIT_FUNC(mkwrite,   |= L_PTE_WRITE);
+PTE_BIT_FUNC(wrprotect, |= L_PTE_RDONLY);
+PTE_BIT_FUNC(mkwrite,   &= ~L_PTE_RDONLY);
 PTE_BIT_FUNC(mkclean,   &= ~L_PTE_DIRTY);
 PTE_BIT_FUNC(mkdirty,   |= L_PTE_DIRTY);
 PTE_BIT_FUNC(mkold,     &= ~L_PTE_YOUNG);
@@ -322,101 +402,13 @@ PTE_BIT_FUNC(mkyoung,   |= L_PTE_YOUNG);
 
 static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
 
-#define __pgprot_modify(prot,mask,bits)                \
-       __pgprot((pgprot_val(prot) & ~(mask)) | (bits))
-
-/*
- * Mark the prot value as uncacheable and unbufferable.
- */
-#define pgprot_noncached(prot) \
-       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
-#define pgprot_writecombine(prot) \
-       __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
-#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
-#define pgprot_dmacoherent(prot) \
-       __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_BUFFERABLE)
-#define __HAVE_PHYS_MEM_ACCESS_PROT
-struct file;
-extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
-                                    unsigned long size, pgprot_t vma_prot);
-#else
-#define pgprot_dmacoherent(prot) \
-       __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_UNCACHED)
-#endif
-
-#define pmd_none(pmd)          (!pmd_val(pmd))
-#define pmd_present(pmd)       (pmd_val(pmd))
-#define pmd_bad(pmd)           (pmd_val(pmd) & 2)
-
-#define copy_pmd(pmdpd,pmdps)          \
-       do {                            \
-               pmdpd[0] = pmdps[0];    \
-               pmdpd[1] = pmdps[1];    \
-               flush_pmd_entry(pmdpd); \
-       } while (0)
-
-#define pmd_clear(pmdp)                        \
-       do {                            \
-               pmdp[0] = __pmd(0);     \
-               pmdp[1] = __pmd(0);     \
-               clean_pmd_entry(pmdp);  \
-       } while (0)
-
-static inline pte_t *pmd_page_vaddr(pmd_t pmd)
-{
-       unsigned long ptr;
-
-       ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * sizeof(void *) - 1);
-       ptr += PTRS_PER_PTE * sizeof(void *);
-
-       return __va(ptr);
-}
-
-#define pmd_page(pmd)          pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
-
-/* we don't need complex calculations here as the pmd is folded into the pgd */
-#define pmd_addr_end(addr,end) (end)
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-#define mk_pte(page,prot)      pfn_pte(page_to_pfn(page),prot)
-
-/*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-#define pgd_none(pgd)          (0)
-#define pgd_bad(pgd)           (0)
-#define pgd_present(pgd)       (1)
-#define pgd_clear(pgdp)                do { } while (0)
-#define set_pgd(pgd,pgdp)      do { } while (0)
-
-/* to find an entry in a page-table-directory */
-#define pgd_index(addr)                ((addr) >> PGDIR_SHIFT)
-
-#define pgd_offset(mm, addr)   ((mm)->pgd+pgd_index(addr))
-
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(addr)     pgd_offset(&init_mm, addr)
-
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir, addr)  ((pmd_t *)(dir))
-
-/* Find an entry in the third-level page table.. */
-#define __pte_index(addr)      (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
-
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-       const unsigned long mask = L_PTE_EXEC | L_PTE_WRITE | L_PTE_USER;
+       const pteval_t mask = L_PTE_XN | L_PTE_RDONLY | L_PTE_USER;
        pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
        return pte;
 }
 
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
 /*
  * Encode and decode a swap entry.  Swap entries are stored in the Linux
  * page tables as follows:
@@ -481,6 +473,9 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 #define pgtable_cache_init() do { } while (0)
 
+void identity_mapping_add(pgd_t *, unsigned long, unsigned long);
+void identity_mapping_del(pgd_t *, unsigned long, unsigned long);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* CONFIG_MMU */
index 5ec79b4ff950eefb22308919daa40b74eb04c75c..4539ebcb089fad0c9471310aed633da450cf963f 100644 (file)
@@ -55,42 +55,6 @@ enum ipi_msg_type {
        IPI_CPU_STOP,
 };
 
-static inline void identity_mapping_add(pgd_t *pgd, unsigned long start,
-       unsigned long end)
-{
-       unsigned long addr, prot;
-       pmd_t *pmd;
-
-       prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
-       if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
-               prot |= PMD_BIT4;
-
-       for (addr = start & PGDIR_MASK; addr < end;) {
-               pmd = pmd_offset(pgd + pgd_index(addr), addr);
-               pmd[0] = __pmd(addr | prot);
-               addr += SECTION_SIZE;
-               pmd[1] = __pmd(addr | prot);
-               addr += SECTION_SIZE;
-               flush_pmd_entry(pmd);
-               outer_clean_range(__pa(pmd), __pa(pmd + 1));
-       }
-}
-
-static inline void identity_mapping_del(pgd_t *pgd, unsigned long start,
-       unsigned long end)
-{
-       unsigned long addr;
-       pmd_t *pmd;
-
-       for (addr = start & PGDIR_MASK; addr < end; addr += PGDIR_SIZE) {
-               pmd = pmd_offset(pgd + pgd_index(addr), addr);
-               pmd[0] = __pmd(0);
-               pmd[1] = __pmd(0);
-               clean_pmd_entry(pmd);
-               outer_clean_range(__pa(pmd), __pa(pmd + 1));
-       }
-}
-
 int __cpuinit __cpu_up(unsigned int cpu)
 {
        struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
index e02f4f7537c51342fb0a9a6e0f794bd49a4bbe80..ee57640ba2bb50ddff8400cccfb6c01603a0da87 100644 (file)
@@ -710,19 +710,19 @@ void __readwrite_bug(const char *fn)
 }
 EXPORT_SYMBOL(__readwrite_bug);
 
-void __pte_error(const char *file, int line, unsigned long val)
+void __pte_error(const char *file, int line, pte_t pte)
 {
-       printk("%s:%d: bad pte %08lx.\n", file, line, val);
+       printk("%s:%d: bad pte %08lx.\n", file, line, pte_val(pte));
 }
 
-void __pmd_error(const char *file, int line, unsigned long val)
+void __pmd_error(const char *file, int line, pmd_t pmd)
 {
-       printk("%s:%d: bad pmd %08lx.\n", file, line, val);
+       printk("%s:%d: bad pmd %08lx.\n", file, line, pmd_val(pmd));
 }
 
-void __pgd_error(const char *file, int line, unsigned long val)
+void __pgd_error(const char *file, int line, pgd_t pgd)
 {
-       printk("%s:%d: bad pgd %08lx.\n", file, line, val);
+       printk("%s:%d: bad pgd %08lx.\n", file, line, pgd_val(pgd));
 }
 
 asmlinkage void __div0(void)
index d63b6c413758a23389cbb09ea1ab8686c61e56db..00d74a04af3afd91858d4512feb4191913efedd7 100644 (file)
@@ -5,8 +5,8 @@
 obj-y                          := dma-mapping.o extable.o fault.o init.o \
                                   iomap.o
 
-obj-$(CONFIG_MMU)              += fault-armv.o flush.o ioremap.o mmap.o \
-                                  pgd.o mmu.o vmregion.o
+obj-$(CONFIG_MMU)              += fault-armv.o flush.o idmap.o ioremap.o \
+                                  mmap.o pgd.o mmu.o vmregion.o
 
 ifneq ($(CONFIG_MMU),y)
 obj-y                          += nommu.o
index 83e59f8704261bfa1c12bd2cd21ac0c21ad17e08..01210dba02217302a3757ecc93810d46d089d43a 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "mm.h"
 
-static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE;
+static pteval_t shared_pte_mask = L_PTE_MT_BUFFERABLE;
 
 #if __LINUX_ARM_ARCH__ < 6
 /*
index 1e21e125fe3a833fadcc932c8fcf01177d7ba8f2..f10f9bac220695d02037731e6715ad510bbfb33d 100644 (file)
@@ -108,7 +108,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
 
                pte = pte_offset_map(pmd, addr);
                printk(", *pte=%08lx", pte_val(*pte));
-               printk(", *ppte=%08lx", pte_val(pte[-PTRS_PER_PTE]));
+               printk(", *ppte=%08lx", pte_val(pte[PTE_HWTABLE_PTRS]));
                pte_unmap(pte);
        } while(0);
 
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
new file mode 100644 (file)
index 0000000..5729944
--- /dev/null
@@ -0,0 +1,67 @@
+#include <linux/kernel.h>
+
+#include <asm/cputype.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+static void idmap_add_pmd(pgd_t *pgd, unsigned long addr, unsigned long end,
+       unsigned long prot)
+{
+       pmd_t *pmd = pmd_offset(pgd, addr);
+
+       addr = (addr & PMD_MASK) | prot;
+       pmd[0] = __pmd(addr);
+       addr += SECTION_SIZE;
+       pmd[1] = __pmd(addr);
+       flush_pmd_entry(pmd);
+}
+
+void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+       unsigned long prot, next;
+
+       prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
+       if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
+               prot |= PMD_BIT4;
+
+       pgd += pgd_index(addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               idmap_add_pmd(pgd, addr, next, prot);
+       } while (pgd++, addr = next, addr != end);
+}
+
+#ifdef CONFIG_SMP
+static void idmap_del_pmd(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+       pmd_t *pmd = pmd_offset(pgd, addr);
+       pmd_clear(pmd);
+}
+
+void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+       unsigned long next;
+
+       pgd += pgd_index(addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               idmap_del_pmd(pgd, addr, next);
+       } while (pgd++, addr = next, addr != end);
+}
+#endif
+
+/*
+ * In order to soft-boot, we need to insert a 1:1 mapping in place of
+ * the user-mode pages.  This will then ensure that we have predictable
+ * results when turning the mmu off
+ */
+void setup_mm_for_reboot(char mode)
+{
+       /*
+        * We need to access to user-mode page tables here. For kernel threads
+        * we don't have any user-mode mappings so we use the context that we
+        * "borrowed".
+        */
+       identity_mapping_add(current->active_mm->pgd, 0, TASK_SIZE);
+       local_flush_tlb_all();
+}
index 6630620380a4aa0f538aed006a2de6f04c71d3dd..36960df5fb762a990be65bba9d92efba3657d8ed 100644 (file)
@@ -16,7 +16,7 @@ static inline pmd_t *pmd_off_k(unsigned long virt)
 }
 
 struct mem_type {
-       unsigned int prot_pte;
+       pteval_t prot_pte;
        unsigned int prot_l1;
        unsigned int prot_sect;
        unsigned int domain;
index 79c01f540cbe31dccda7d795026ae4c6ec349763..3c67e92f7d5921183e69d21e507d854aac8cde94 100644 (file)
@@ -63,7 +63,7 @@ struct cachepolicy {
        const char      policy[16];
        unsigned int    cr_mask;
        unsigned int    pmd;
-       unsigned int    pte;
+       pteval_t        pte;
 };
 
 static struct cachepolicy cache_policies[] __initdata = {
@@ -191,7 +191,7 @@ void adjust_cr(unsigned long mask, unsigned long set)
 }
 #endif
 
-#define PROT_PTE_DEVICE                L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_WRITE
+#define PROT_PTE_DEVICE                L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN
 #define PROT_SECT_DEVICE       PMD_TYPE_SECT|PMD_SECT_AP_WRITE
 
 static struct mem_type mem_types[] = {
@@ -236,19 +236,18 @@ static struct mem_type mem_types[] = {
        },
        [MT_LOW_VECTORS] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-                               L_PTE_EXEC,
+                               L_PTE_RDONLY,
                .prot_l1   = PMD_TYPE_TABLE,
                .domain    = DOMAIN_USER,
        },
        [MT_HIGH_VECTORS] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-                               L_PTE_USER | L_PTE_EXEC,
+                               L_PTE_USER | L_PTE_RDONLY,
                .prot_l1   = PMD_TYPE_TABLE,
                .domain    = DOMAIN_USER,
        },
        [MT_MEMORY] = {
-               .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-                               L_PTE_WRITE | L_PTE_EXEC,
+               .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
                .prot_l1   = PMD_TYPE_TABLE,
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
                .domain    = DOMAIN_KERNEL,
@@ -259,21 +258,20 @@ static struct mem_type mem_types[] = {
        },
        [MT_MEMORY_NONCACHED] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-                               L_PTE_WRITE | L_PTE_EXEC | L_PTE_MT_BUFFERABLE,
+                               L_PTE_MT_BUFFERABLE,
                .prot_l1   = PMD_TYPE_TABLE,
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
                .domain    = DOMAIN_KERNEL,
        },
        [MT_MEMORY_DTCM] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-                               L_PTE_WRITE,
+                               L_PTE_XN,
                .prot_l1   = PMD_TYPE_TABLE,
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
                .domain    = DOMAIN_KERNEL,
        },
        [MT_MEMORY_ITCM] = {
-               .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-                               L_PTE_WRITE | L_PTE_EXEC,
+               .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
                .prot_l1   = PMD_TYPE_TABLE,
                .domain    = DOMAIN_KERNEL,
        },
@@ -480,7 +478,7 @@ static void __init build_mem_type_table(void)
 
        pgprot_user   = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot);
        pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
-                                L_PTE_DIRTY | L_PTE_WRITE | kern_pgprot);
+                                L_PTE_DIRTY | kern_pgprot);
 
        mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
        mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
@@ -536,7 +534,7 @@ static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned l
 {
        if (pmd_none(*pmd)) {
                pte_t *pte = early_alloc(2 * PTRS_PER_PTE * sizeof(pte_t));
-               __pmd_populate(pmd, __pa(pte) | prot);
+               __pmd_populate(pmd, __pa(pte), prot);
        }
        BUG_ON(pmd_bad(*pmd));
        return pte_offset_kernel(pmd, addr);
@@ -554,7 +552,7 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
 }
 
 static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
-                                     unsigned long end, unsigned long phys,
+                                     unsigned long end, phys_addr_t phys,
                                      const struct mem_type *type)
 {
        pmd_t *pmd = pmd_offset(pgd, addr);
@@ -589,7 +587,8 @@ static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
 static void __init create_36bit_mapping(struct map_desc *md,
                                        const struct mem_type *type)
 {
-       unsigned long phys, addr, length, end;
+       unsigned long addr, length, end;
+       phys_addr_t phys;
        pgd_t *pgd;
 
        addr = md->virtual;
@@ -1044,38 +1043,3 @@ void __init paging_init(struct machine_desc *mdesc)
        empty_zero_page = virt_to_page(zero_page);
        __flush_dcache_page(NULL, empty_zero_page);
 }
-
-/*
- * In order to soft-boot, we need to insert a 1:1 mapping in place of
- * the user-mode pages.  This will then ensure that we have predictable
- * results when turning the mmu off
- */
-void setup_mm_for_reboot(char mode)
-{
-       unsigned long base_pmdval;
-       pgd_t *pgd;
-       int i;
-
-       /*
-        * We need to access to user-mode page tables here. For kernel threads
-        * we don't have any user-mode mappings so we use the context that we
-        * "borrowed".
-        */
-       pgd = current->active_mm->pgd;
-
-       base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
-       if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
-               base_pmdval |= PMD_BIT4;
-
-       for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
-               unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
-               pmd_t *pmd;
-
-               pmd = pmd_off(pgd, i << PGDIR_SHIFT);
-               pmd[0] = __pmd(pmdval);
-               pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
-               flush_pmd_entry(pmd);
-       }
-
-       local_flush_tlb_all();
-}
index 69bbfc6645a673853ed6f8171e08e3a4f9f22585..93292a18cf77f35bd9369ad84f3f6f56e948ddc8 100644 (file)
 
 #include "mm.h"
 
-#define FIRST_KERNEL_PGD_NR    (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
-
 /*
  * need to get a 16k page for level 1
  */
-pgd_t *get_pgd_slow(struct mm_struct *mm)
+pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        pgd_t *new_pgd, *init_pgd;
        pmd_t *new_pmd, *init_pmd;
@@ -32,14 +30,14 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
        if (!new_pgd)
                goto no_pgd;
 
-       memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
+       memset(new_pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
 
        /*
         * Copy over the kernel and IO PGD entries
         */
        init_pgd = pgd_offset_k(0);
-       memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
-                      (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
+       memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD,
+                      (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 
        clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
 
@@ -73,28 +71,29 @@ no_pgd:
        return NULL;
 }
 
-void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
 {
+       pgd_t *pgd;
        pmd_t *pmd;
        pgtable_t pte;
 
-       if (!pgd)
+       if (!pgd_base)
                return;
 
-       /* pgd is always present and good */
-       pmd = pmd_off(pgd, 0);
-       if (pmd_none(*pmd))
-               goto free;
-       if (pmd_bad(*pmd)) {
-               pmd_ERROR(*pmd);
-               pmd_clear(pmd);
-               goto free;
-       }
+       pgd = pgd_base + pgd_index(0);
+       if (pgd_none_or_clear_bad(pgd))
+               goto no_pgd;
+
+       pmd = pmd_offset(pgd, 0);
+       if (pmd_none_or_clear_bad(pmd))
+               goto no_pmd;
 
        pte = pmd_pgtable(*pmd);
        pmd_clear(pmd);
        pte_free(mm, pte);
+no_pmd:
+       pgd_clear(pgd);
        pmd_free(mm, pmd);
-free:
-       free_pages((unsigned long) pgd, 2);
+no_pgd:
+       free_pages((unsigned long) pgd_base, 2);
 }
index f8f777df8d72780c6b105481f28dd1767180649e..e32fa499194ca717b27a3391bf0c71879ad4a352 100644 (file)
@@ -91,7 +91,7 @@
 #if L_PTE_SHARED != PTE_EXT_SHARED
 #error PTE shared bit mismatch
 #endif
-#if (L_PTE_EXEC+L_PTE_USER+L_PTE_WRITE+L_PTE_DIRTY+L_PTE_YOUNG+\
+#if (L_PTE_XN+L_PTE_USER+L_PTE_RDONLY+L_PTE_DIRTY+L_PTE_YOUNG+\
      L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED
 #error Invalid Linux PTE bit settings
 #endif
        .endm
 
        .macro  armv6_set_pte_ext pfx
-       str     r1, [r0], #-2048                @ linux version
+       str     r1, [r0], #2048                 @ linux version
 
        bic     r3, r1, #0x000003fc
        bic     r3, r3, #PTE_TYPE_MASK
        and     r2, r1, #L_PTE_MT_MASK
        ldr     r2, [ip, r2]
 
-       tst     r1, #L_PTE_WRITE
-       tstne   r1, #L_PTE_DIRTY
-       orreq   r3, r3, #PTE_EXT_APX
+       eor     r1, r1, #L_PTE_DIRTY
+       tst     r1, #L_PTE_DIRTY|L_PTE_RDONLY
+       orrne   r3, r3, #PTE_EXT_APX
 
        tst     r1, #L_PTE_USER
        orrne   r3, r3, #PTE_EXT_AP1
        bicne   r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
 #endif
 
-       tst     r1, #L_PTE_EXEC
-       orreq   r3, r3, #PTE_EXT_XN
+       tst     r1, #L_PTE_XN
+       orrne   r3, r3, #PTE_EXT_XN
 
        orr     r3, r3, r2
 
  *  1111  0xff r/w     r/w
  */
        .macro  armv3_set_pte_ext wc_disable=1
-       str     r1, [r0], #-2048                @ linux version
+       str     r1, [r0], #2048                 @ linux version
 
-       eor     r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
+       eor     r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY
 
        bic     r2, r1, #PTE_SMALL_AP_MASK      @ keep C, B bits
        bic     r2, r2, #PTE_TYPE_MASK
        tst     r3, #L_PTE_USER                 @ user?
        orrne   r2, r2, #PTE_SMALL_AP_URO_SRW
 
-       tst     r3, #L_PTE_WRITE | L_PTE_DIRTY  @ write and dirty?
+       tst     r3, #L_PTE_RDONLY | L_PTE_DIRTY @ write and dirty?
        orreq   r2, r2, #PTE_SMALL_AP_UNO_SRW
 
        tst     r3, #L_PTE_PRESENT | L_PTE_YOUNG        @ present and young?
        bicne   r2, r2, #PTE_BUFFERABLE
 #endif
        .endif
-       str     r2, [r0]                        @ hardware version
+       str     r2, [r0]                @ hardware version
        .endm
 
 
  *  1111  11   r/w     r/w
  */
        .macro  xscale_set_pte_ext_prologue
-       str     r1, [r0], #-2048                @ linux version
+       str     r1, [r0]                        @ linux version
 
-       eor     r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
+       eor     r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY
 
        bic     r2, r1, #PTE_SMALL_AP_MASK      @ keep C, B bits
        orr     r2, r2, #PTE_TYPE_EXT           @ extended page
        tst     r3, #L_PTE_USER                 @ user?
        orrne   r2, r2, #PTE_EXT_AP_URO_SRW     @ yes -> user r/o, system r/w
 
-       tst     r3, #L_PTE_WRITE | L_PTE_DIRTY  @ write and dirty?
+       tst     r3, #L_PTE_RDONLY | L_PTE_DIRTY @ write and dirty?
        orreq   r2, r2, #PTE_EXT_AP_UNO_SRW     @ yes -> user n/a, system r/w
                                                @ combined with user -> user r/w
        .endm
        tst     r3, #L_PTE_PRESENT | L_PTE_YOUNG        @ present and young?
        movne   r2, #0                          @ no -> fault
 
-       str     r2, [r0]                        @ hardware version
+       str     r2, [r0, #2048]!                @ hardware version
        mov     ip, #0
        mcr     p15, 0, r0, c7, c10, 1          @ clean L1 D line
        mcr     p15, 0, ip, c7, c10, 4          @ data write barrier
index 7401f4d7e6763a9fb02c54a98dc63cba404e3d47..b49fab21517c04b1f0d7476571a05b7133ca4826 100644 (file)
@@ -124,15 +124,13 @@ ENDPROC(cpu_v7_switch_mm)
  *     Set a level 2 translation table entry.
  *
  *     - ptep  - pointer to level 2 translation table entry
- *               (hardware version is stored at -1024 bytes)
+ *               (hardware version is stored at +2048 bytes)
  *     - pte   - PTE value to store
  *     - ext   - value for extended PTE bits
  */
 ENTRY(cpu_v7_set_pte_ext)
 #ifdef CONFIG_MMU
- ARM(  str     r1, [r0], #-2048        )       @ linux version
- THUMB(        str     r1, [r0]                )       @ linux version
- THUMB(        sub     r0, r0, #2048           )
+       str     r1, [r0]                        @ linux version
 
        bic     r3, r1, #0x000003f0
        bic     r3, r3, #PTE_TYPE_MASK
@@ -142,9 +140,9 @@ ENTRY(cpu_v7_set_pte_ext)
        tst     r1, #1 << 4
        orrne   r3, r3, #PTE_EXT_TEX(1)
 
-       tst     r1, #L_PTE_WRITE
-       tstne   r1, #L_PTE_DIRTY
-       orreq   r3, r3, #PTE_EXT_APX
+       eor     r1, r1, #L_PTE_DIRTY
+       tst     r1, #L_PTE_RDONLY | L_PTE_DIRTY
+       orrne   r3, r3, #PTE_EXT_APX
 
        tst     r1, #L_PTE_USER
        orrne   r3, r3, #PTE_EXT_AP1
@@ -154,14 +152,14 @@ ENTRY(cpu_v7_set_pte_ext)
        bicne   r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
 #endif
 
-       tst     r1, #L_PTE_EXEC
-       orreq   r3, r3, #PTE_EXT_XN
+       tst     r1, #L_PTE_XN
+       orrne   r3, r3, #PTE_EXT_XN
 
        tst     r1, #L_PTE_YOUNG
        tstne   r1, #L_PTE_PRESENT
        moveq   r3, #0
 
-       str     r3, [r0]
+       str     r3, [r0, #2048]!
        mcr     p15, 0, r0, c7, c10, 1          @ flush_pte
 #endif
        mov     pc, lr
index 523408c0bb38aafb69903dbd85f8584d5eef1a3a..5a37c5e45c411a8d377dec497207777338ed68db 100644 (file)
@@ -500,8 +500,8 @@ ENTRY(cpu_xscale_set_pte_ext)
        @
        @ Erratum 40: must set memory to write-through for user read-only pages
        @
-       and     ip, r1, #(L_PTE_MT_MASK | L_PTE_USER | L_PTE_WRITE) & ~(4 << 2)
-       teq     ip, #L_PTE_MT_WRITEBACK | L_PTE_USER
+       and     ip, r1, #(L_PTE_MT_MASK | L_PTE_USER | L_PTE_RDONLY) & ~(4 << 2)
+       teq     ip, #L_PTE_MT_WRITEBACK | L_PTE_USER | L_PTE_RDONLY
 
        moveq   r1, #L_PTE_MT_WRITETHROUGH
        and     r1, r1, #L_PTE_MT_MASK