Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

unicore32 core architecture: mm related: fault handling

This patch implements fault handling of memory management.

Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>

+2247
+17
arch/unicore32/include/asm/mmu.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/mmu.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #ifndef __UNICORE_MMU_H__ 13 + #define __UNICORE_MMU_H__ 14 + 15 + typedef unsigned long mm_context_t; 16 + 17 + #endif
+87
arch/unicore32/include/asm/mmu_context.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/mmu_context.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #ifndef __UNICORE_MMU_CONTEXT_H__ 13 + #define __UNICORE_MMU_CONTEXT_H__ 14 + 15 + #include <linux/compiler.h> 16 + #include <linux/sched.h> 17 + #include <linux/io.h> 18 + 19 + #include <asm/cacheflush.h> 20 + #include <asm/cpu-single.h> 21 + 22 + #define init_new_context(tsk, mm) 0 23 + 24 + #define destroy_context(mm) do { } while (0) 25 + 26 + /* 27 + * This is called when "tsk" is about to enter lazy TLB mode. 28 + * 29 + * mm: describes the currently active mm context 30 + * tsk: task which is entering lazy tlb 31 + * cpu: cpu number which is entering lazy tlb 32 + * 33 + * tsk->mm will be NULL 34 + */ 35 + static inline void 36 + enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) 37 + { 38 + } 39 + 40 + /* 41 + * This is the actual mm switch as far as the scheduler 42 + * is concerned. No registers are touched. We avoid 43 + * calling the CPU specific function when the mm hasn't 44 + * actually changed. 45 + */ 46 + static inline void 47 + switch_mm(struct mm_struct *prev, struct mm_struct *next, 48 + struct task_struct *tsk) 49 + { 50 + unsigned int cpu = smp_processor_id(); 51 + 52 + if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) 53 + cpu_switch_mm(next->pgd, next); 54 + } 55 + 56 + #define deactivate_mm(tsk, mm) do { } while (0) 57 + #define activate_mm(prev, next) switch_mm(prev, next, NULL) 58 + 59 + /* 60 + * We are inserting a "fake" vma for the user-accessible vector page so 61 + * gdb and friends can get to it through ptrace and /proc/<pid>/mem. 62 + * But we also want to remove it before the generic code gets to see it 63 + * during process exit or the unmapping of it would cause total havoc. 64 + * (the macro is used as remove_vma() is static to mm/mmap.c) 65 + */ 66 + #define arch_exit_mmap(mm) \ 67 + do { \ 68 + struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \ 69 + if (high_vma) { \ 70 + BUG_ON(high_vma->vm_next); /* it should be last */ \ 71 + if (high_vma->vm_prev) \ 72 + high_vma->vm_prev->vm_next = NULL; \ 73 + else \ 74 + mm->mmap = NULL; \ 75 + rb_erase(&high_vma->vm_rb, &mm->mm_rb); \ 76 + mm->mmap_cache = NULL; \ 77 + mm->map_count--; \ 78 + remove_vma(high_vma); \ 79 + } \ 80 + } while (0) 81 + 82 + static inline void arch_dup_mmap(struct mm_struct *oldmm, 83 + struct mm_struct *mm) 84 + { 85 + } 86 + 87 + #endif
+110
arch/unicore32/include/asm/pgalloc.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/pgalloc.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #ifndef __UNICORE_PGALLOC_H__ 13 + #define __UNICORE_PGALLOC_H__ 14 + 15 + #include <asm/pgtable-hwdef.h> 16 + #include <asm/processor.h> 17 + #include <asm/cacheflush.h> 18 + #include <asm/tlbflush.h> 19 + 20 + #define check_pgt_cache() do { } while (0) 21 + 22 + #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_PRESENT) 23 + #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_PRESENT) 24 + 25 + extern pgd_t *get_pgd_slow(struct mm_struct *mm); 26 + extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd); 27 + 28 + #define pgd_alloc(mm) get_pgd_slow(mm) 29 + #define pgd_free(mm, pgd) free_pgd_slow(mm, pgd) 30 + 31 + #define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) 32 + 33 + /* 34 + * Allocate one PTE table. 35 + */ 36 + static inline pte_t * 37 + pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) 38 + { 39 + pte_t *pte; 40 + 41 + pte = (pte_t *)__get_free_page(PGALLOC_GFP); 42 + if (pte) 43 + clean_dcache_area(pte, PTRS_PER_PTE * sizeof(pte_t)); 44 + 45 + return pte; 46 + } 47 + 48 + static inline pgtable_t 49 + pte_alloc_one(struct mm_struct *mm, unsigned long addr) 50 + { 51 + struct page *pte; 52 + 53 + pte = alloc_pages(PGALLOC_GFP, 0); 54 + if (pte) { 55 + if (!PageHighMem(pte)) { 56 + void *page = page_address(pte); 57 + clean_dcache_area(page, PTRS_PER_PTE * sizeof(pte_t)); 58 + } 59 + pgtable_page_ctor(pte); 60 + } 61 + 62 + return pte; 63 + } 64 + 65 + /* 66 + * Free one PTE table. 67 + */ 68 + static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) 69 + { 70 + if (pte) 71 + free_page((unsigned long)pte); 72 + } 73 + 74 + static inline void pte_free(struct mm_struct *mm, pgtable_t pte) 75 + { 76 + pgtable_page_dtor(pte); 77 + __free_page(pte); 78 + } 79 + 80 + static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval) 81 + { 82 + set_pmd(pmdp, __pmd(pmdval)); 83 + flush_pmd_entry(pmdp); 84 + } 85 + 86 + /* 87 + * Populate the pmdp entry with a pointer to the pte. This pmd is part 88 + * of the mm address space. 89 + */ 90 + static inline void 91 + pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) 92 + { 93 + unsigned long pte_ptr = (unsigned long)ptep; 94 + 95 + /* 96 + * The pmd must be loaded with the physical 97 + * address of the PTE table 98 + */ 99 + __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE); 100 + } 101 + 102 + static inline void 103 + pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep) 104 + { 105 + __pmd_populate(pmdp, 106 + page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE); 107 + } 108 + #define pmd_pgtable(pmd) pmd_page(pmd) 109 + 110 + #endif
+55
arch/unicore32/include/asm/pgtable-hwdef.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/pgtable-hwdef.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #ifndef __UNICORE_PGTABLE_HWDEF_H__ 13 + #define __UNICORE_PGTABLE_HWDEF_H__ 14 + 15 + /* 16 + * Hardware page table definitions. 17 + * 18 + * + Level 1 descriptor (PMD) 19 + * - common 20 + */ 21 + #define PMD_TYPE_MASK (3 << 0) 22 + #define PMD_TYPE_TABLE (0 << 0) 23 + /*#define PMD_TYPE_LARGE (1 << 0) */ 24 + #define PMD_TYPE_INVALID (2 << 0) 25 + #define PMD_TYPE_SECT (3 << 0) 26 + 27 + #define PMD_PRESENT (1 << 2) 28 + #define PMD_YOUNG (1 << 3) 29 + 30 + /*#define PMD_SECT_DIRTY (1 << 4) */ 31 + #define PMD_SECT_CACHEABLE (1 << 5) 32 + #define PMD_SECT_EXEC (1 << 6) 33 + #define PMD_SECT_WRITE (1 << 7) 34 + #define PMD_SECT_READ (1 << 8) 35 + 36 + /* 37 + * + Level 2 descriptor (PTE) 38 + * - common 39 + */ 40 + #define PTE_TYPE_MASK (3 << 0) 41 + #define PTE_TYPE_SMALL (0 << 0) 42 + #define PTE_TYPE_MIDDLE (1 << 0) 43 + #define PTE_TYPE_LARGE (2 << 0) 44 + #define PTE_TYPE_INVALID (3 << 0) 45 + 46 + #define PTE_PRESENT (1 << 2) 47 + #define PTE_FILE (1 << 3) /* only when !PRESENT */ 48 + #define PTE_YOUNG (1 << 3) 49 + #define PTE_DIRTY (1 << 4) 50 + #define PTE_CACHEABLE (1 << 5) 51 + #define PTE_EXEC (1 << 6) 52 + #define PTE_WRITE (1 << 7) 53 + #define PTE_READ (1 << 8) 54 + 55 + #endif
+317
arch/unicore32/include/asm/pgtable.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/pgtable.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #ifndef __UNICORE_PGTABLE_H__ 13 + #define __UNICORE_PGTABLE_H__ 14 + 15 + #include <asm-generic/pgtable-nopmd.h> 16 + #include <asm/cpu-single.h> 17 + 18 + #include <asm/memory.h> 19 + #include <asm/pgtable-hwdef.h> 20 + 21 + /* 22 + * Just any arbitrary offset to the start of the vmalloc VM area: the 23 + * current 8MB value just means that there will be a 8MB "hole" after the 24 + * physical memory until the kernel virtual memory starts. That means that 25 + * any out-of-bounds memory accesses will hopefully be caught. 26 + * The vmalloc() routines leaves a hole of 4kB between each vmalloced 27 + * area for the same reason. ;) 28 + * 29 + * Note that platforms may override VMALLOC_START, but they must provide 30 + * VMALLOC_END. VMALLOC_END defines the (exclusive) limit of this space, 31 + * which may not overlap IO space. 32 + */ 33 + #ifndef VMALLOC_START 34 + #define VMALLOC_OFFSET SZ_8M 35 + #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) \ 36 + & ~(VMALLOC_OFFSET-1)) 37 + #define VMALLOC_END (0xff000000UL) 38 + #endif 39 + 40 + #define PTRS_PER_PTE 1024 41 + #define PTRS_PER_PGD 1024 42 + 43 + /* 44 + * PGDIR_SHIFT determines what a third-level page table entry can map 45 + */ 46 + #define PGDIR_SHIFT 22 47 + 48 + #ifndef __ASSEMBLY__ 49 + extern void __pte_error(const char *file, int line, unsigned long val); 50 + extern void __pgd_error(const char *file, int line, unsigned long val); 51 + 52 + #define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) 53 + #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) 54 + #endif /* !__ASSEMBLY__ */ 55 + 56 + #define PGDIR_SIZE (1UL << PGDIR_SHIFT) 57 + #define PGDIR_MASK (~(PGDIR_SIZE-1)) 58 + 59 + /* 60 + * This is the lowest virtual address we can permit any user space 61 + * mapping to be mapped at. This is particularly important for 62 + * non-high vector CPUs. 63 + */ 64 + #define FIRST_USER_ADDRESS PAGE_SIZE 65 + 66 + #define FIRST_USER_PGD_NR 1 67 + #define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR) 68 + 69 + /* 70 + * section address mask and size definitions. 71 + */ 72 + #define SECTION_SHIFT 22 73 + #define SECTION_SIZE (1UL << SECTION_SHIFT) 74 + #define SECTION_MASK (~(SECTION_SIZE-1)) 75 + 76 + #ifndef __ASSEMBLY__ 77 + 78 + /* 79 + * The pgprot_* and protection_map entries will be fixed up in runtime 80 + * to include the cachable bits based on memory policy, as well as any 81 + * architecture dependent bits. 82 + */ 83 + #define _PTE_DEFAULT (PTE_PRESENT | PTE_YOUNG | PTE_CACHEABLE) 84 + 85 + extern pgprot_t pgprot_user; 86 + extern pgprot_t pgprot_kernel; 87 + 88 + #define PAGE_NONE pgprot_user 89 + #define PAGE_SHARED __pgprot(pgprot_val(pgprot_user | PTE_READ \ 90 + | PTE_WRITE) 91 + #define PAGE_SHARED_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ 92 + | PTE_WRITE \ 93 + | PTE_EXEC) 94 + #define PAGE_COPY __pgprot(pgprot_val(pgprot_user | PTE_READ) 95 + #define PAGE_COPY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ 96 + | PTE_EXEC) 97 + #define PAGE_READONLY __pgprot(pgprot_val(pgprot_user | PTE_READ) 98 + #define PAGE_READONLY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ 99 + | PTE_EXEC) 100 + #define PAGE_KERNEL pgprot_kernel 101 + #define PAGE_KERNEL_EXEC __pgprot(pgprot_val(pgprot_kernel | PTE_EXEC)) 102 + 103 + #define __PAGE_NONE __pgprot(_PTE_DEFAULT) 104 + #define __PAGE_SHARED __pgprot(_PTE_DEFAULT | PTE_READ \ 105 + | PTE_WRITE) 106 + #define __PAGE_SHARED_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \ 107 + | PTE_WRITE \ 108 + | PTE_EXEC) 109 + #define __PAGE_COPY __pgprot(_PTE_DEFAULT | PTE_READ) 110 + #define __PAGE_COPY_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \ 111 + | PTE_EXEC) 112 + #define __PAGE_READONLY __pgprot(_PTE_DEFAULT | PTE_READ) 113 + #define __PAGE_READONLY_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \ 114 + | PTE_EXEC) 115 + 116 + #endif /* __ASSEMBLY__ */ 117 + 118 + /* 119 + * The table below defines the page protection levels that we insert into our 120 + * Linux page table version. These get translated into the best that the 121 + * architecture can perform. Note that on UniCore hardware: 122 + * 1) We cannot do execute protection 123 + * 2) If we could do execute protection, then read is implied 124 + * 3) write implies read permissions 125 + */ 126 + #define __P000 __PAGE_NONE 127 + #define __P001 __PAGE_READONLY 128 + #define __P010 __PAGE_COPY 129 + #define __P011 __PAGE_COPY 130 + #define __P100 __PAGE_READONLY_EXEC 131 + #define __P101 __PAGE_READONLY_EXEC 132 + #define __P110 __PAGE_COPY_EXEC 133 + #define __P111 __PAGE_COPY_EXEC 134 + 135 + #define __S000 __PAGE_NONE 136 + #define __S001 __PAGE_READONLY 137 + #define __S010 __PAGE_SHARED 138 + #define __S011 __PAGE_SHARED 139 + #define __S100 __PAGE_READONLY_EXEC 140 + #define __S101 __PAGE_READONLY_EXEC 141 + #define __S110 __PAGE_SHARED_EXEC 142 + #define __S111 __PAGE_SHARED_EXEC 143 + 144 + #ifndef __ASSEMBLY__ 145 + /* 146 + * ZERO_PAGE is a global shared page that is always zero: used 147 + * for zero-mapped memory areas etc.. 148 + */ 149 + extern struct page *empty_zero_page; 150 + #define ZERO_PAGE(vaddr) (empty_zero_page) 151 + 152 + #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) 153 + #define pfn_pte(pfn, prot) (__pte(((pfn) << PAGE_SHIFT) \ 154 + | pgprot_val(prot))) 155 + 156 + #define pte_none(pte) (!pte_val(pte)) 157 + #define pte_clear(mm, addr, ptep) set_pte(ptep, __pte(0)) 158 + #define pte_page(pte) (pfn_to_page(pte_pfn(pte))) 159 + #define pte_offset_kernel(dir, addr) (pmd_page_vaddr(*(dir)) \ 160 + + __pte_index(addr)) 161 + 162 + #define pte_offset_map(dir, addr) (pmd_page_vaddr(*(dir)) \ 163 + + __pte_index(addr)) 164 + #define pte_unmap(pte) do { } while (0) 165 + 166 + #define set_pte(ptep, pte) cpu_set_pte(ptep, pte) 167 + 168 + #define set_pte_at(mm, addr, ptep, pteval) \ 169 + do { \ 170 + set_pte(ptep, pteval); \ 171 + } while (0) 172 + 173 + /* 174 + * The following only work if pte_present() is true. 175 + * Undefined behaviour if not.. 176 + */ 177 + #define pte_present(pte) (pte_val(pte) & PTE_PRESENT) 178 + #define pte_write(pte) (pte_val(pte) & PTE_WRITE) 179 + #define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) 180 + #define pte_young(pte) (pte_val(pte) & PTE_YOUNG) 181 + #define pte_exec(pte) (pte_val(pte) & PTE_EXEC) 182 + #define pte_special(pte) (0) 183 + 184 + #define PTE_BIT_FUNC(fn, op) \ 185 + static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } 186 + 187 + PTE_BIT_FUNC(wrprotect, &= ~PTE_WRITE); 188 + PTE_BIT_FUNC(mkwrite, |= PTE_WRITE); 189 + PTE_BIT_FUNC(mkclean, &= ~PTE_DIRTY); 190 + PTE_BIT_FUNC(mkdirty, |= PTE_DIRTY); 191 + PTE_BIT_FUNC(mkold, &= ~PTE_YOUNG); 192 + PTE_BIT_FUNC(mkyoung, |= PTE_YOUNG); 193 + 194 + static inline pte_t pte_mkspecial(pte_t pte) { return pte; } 195 + 196 + /* 197 + * Mark the prot value as uncacheable. 198 + */ 199 + #define pgprot_noncached(prot) \ 200 + __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE) 201 + #define pgprot_writecombine(prot) \ 202 + __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE) 203 + #define pgprot_dmacoherent(prot) \ 204 + __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE) 205 + 206 + #define pmd_none(pmd) (!pmd_val(pmd)) 207 + #define pmd_present(pmd) (pmd_val(pmd) & PMD_PRESENT) 208 + #define pmd_bad(pmd) (((pmd_val(pmd) & \ 209 + (PMD_PRESENT | PMD_TYPE_MASK)) \ 210 + != (PMD_PRESENT | PMD_TYPE_TABLE))) 211 + 212 + #define set_pmd(pmdpd, pmdval) \ 213 + do { \ 214 + *(pmdpd) = pmdval; \ 215 + } while (0) 216 + 217 + #define pmd_clear(pmdp) \ 218 + do { \ 219 + set_pmd(pmdp, __pmd(0));\ 220 + clean_pmd_entry(pmdp); \ 221 + } while (0) 222 + 223 + #define pmd_page_vaddr(pmd) ((pte_t *)__va(pmd_val(pmd) & PAGE_MASK)) 224 + #define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd))) 225 + 226 + /* 227 + * Conversion functions: convert a page and protection to a page entry, 228 + * and a page entry and page directory to the page they refer to. 229 + */ 230 + #define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot) 231 + 232 + /* to find an entry in a page-table-directory */ 233 + #define pgd_index(addr) ((addr) >> PGDIR_SHIFT) 234 + 235 + #define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr)) 236 + 237 + /* to find an entry in a kernel page-table-directory */ 238 + #define pgd_offset_k(addr) pgd_offset(&init_mm, addr) 239 + 240 + /* Find an entry in the third-level page table.. */ 241 + #define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 242 + 243 + static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) 244 + { 245 + const unsigned long mask = PTE_EXEC | PTE_WRITE | PTE_READ; 246 + pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); 247 + return pte; 248 + } 249 + 250 + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; 251 + 252 + /* 253 + * Encode and decode a swap entry. Swap entries are stored in the Linux 254 + * page tables as follows: 255 + * 256 + * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 257 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 258 + * <--------------- offset --------------> <--- type --> 0 0 0 0 0 259 + * 260 + * This gives us up to 127 swap files and 32GB per swap file. Note that 261 + * the offset field is always non-zero. 262 + */ 263 + #define __SWP_TYPE_SHIFT 5 264 + #define __SWP_TYPE_BITS 7 265 + #define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) 266 + #define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) 267 + 268 + #define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) \ 269 + & __SWP_TYPE_MASK) 270 + #define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT) 271 + #define __swp_entry(type, offset) ((swp_entry_t) { \ 272 + ((type) << __SWP_TYPE_SHIFT) | \ 273 + ((offset) << __SWP_OFFSET_SHIFT) }) 274 + 275 + #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) 276 + #define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) 277 + 278 + /* 279 + * It is an error for the kernel to have more swap files than we can 280 + * encode in the PTEs. This ensures that we know when MAX_SWAPFILES 281 + * is increased beyond what we presently support. 282 + */ 283 + #define MAX_SWAPFILES_CHECK() \ 284 + BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) 285 + 286 + /* 287 + * Encode and decode a file entry. File entries are stored in the Linux 288 + * page tables as follows: 289 + * 290 + * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 291 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 292 + * <----------------------- offset ----------------------> 1 0 0 0 293 + */ 294 + #define pte_file(pte) (pte_val(pte) & PTE_FILE) 295 + #define pte_to_pgoff(x) (pte_val(x) >> 4) 296 + #define pgoff_to_pte(x) __pte(((x) << 4) | PTE_FILE) 297 + 298 + #define PTE_FILE_MAX_BITS 28 299 + 300 + /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ 301 + /* FIXME: this is not correct */ 302 + #define kern_addr_valid(addr) (1) 303 + 304 + #include <asm-generic/pgtable.h> 305 + 306 + /* 307 + * remap a physical page `pfn' of size `size' with page protection `prot' 308 + * into virtual address `from' 309 + */ 310 + #define io_remap_pfn_range(vma, from, pfn, size, prot) \ 311 + remap_pfn_range(vma, from, pfn, size, prot) 312 + 313 + #define pgtable_cache_init() do { } while (0) 314 + 315 + #endif /* !__ASSEMBLY__ */ 316 + 317 + #endif /* __UNICORE_PGTABLE_H__ */
+523
arch/unicore32/mm/alignment.c
··· 1 + /* 2 + * linux/arch/unicore32/mm/alignment.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + /* 13 + * TODO: 14 + * FPU ldm/stm not handling 15 + */ 16 + #include <linux/compiler.h> 17 + #include <linux/kernel.h> 18 + #include <linux/errno.h> 19 + #include <linux/string.h> 20 + #include <linux/init.h> 21 + #include <linux/sched.h> 22 + #include <linux/uaccess.h> 23 + 24 + #include <asm/tlbflush.h> 25 + #include <asm/unaligned.h> 26 + 27 + #define CODING_BITS(i) (i & 0xe0000120) 28 + 29 + #define LDST_P_BIT(i) (i & (1 << 28)) /* Preindex */ 30 + #define LDST_U_BIT(i) (i & (1 << 27)) /* Add offset */ 31 + #define LDST_W_BIT(i) (i & (1 << 25)) /* Writeback */ 32 + #define LDST_L_BIT(i) (i & (1 << 24)) /* Load */ 33 + 34 + #define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 27)) == 0) 35 + 36 + #define LDSTH_I_BIT(i) (i & (1 << 26)) /* half-word immed */ 37 + #define LDM_S_BIT(i) (i & (1 << 26)) /* write ASR from BSR */ 38 + #define LDM_H_BIT(i) (i & (1 << 6)) /* select r0-r15 or r16-r31 */ 39 + 40 + #define RN_BITS(i) ((i >> 19) & 31) /* Rn */ 41 + #define RD_BITS(i) ((i >> 14) & 31) /* Rd */ 42 + #define RM_BITS(i) (i & 31) /* Rm */ 43 + 44 + #define REGMASK_BITS(i) (((i & 0x7fe00) >> 3) | (i & 0x3f)) 45 + #define OFFSET_BITS(i) (i & 0x03fff) 46 + 47 + #define SHIFT_BITS(i) ((i >> 9) & 0x1f) 48 + #define SHIFT_TYPE(i) (i & 0xc0) 49 + #define SHIFT_LSL 0x00 50 + #define SHIFT_LSR 0x40 51 + #define SHIFT_ASR 0x80 52 + #define SHIFT_RORRRX 0xc0 53 + 54 + union offset_union { 55 + unsigned long un; 56 + signed long sn; 57 + }; 58 + 59 + #define TYPE_ERROR 0 60 + #define TYPE_FAULT 1 61 + #define TYPE_LDST 2 62 + #define TYPE_DONE 3 63 + #define TYPE_SWAP 4 64 + #define TYPE_COLS 5 /* Coprocessor load/store */ 65 + 66 + #define get8_unaligned_check(val, addr, err) \ 67 + __asm__( \ 68 + "1: ldb.u %1, [%2], #1\n" \ 69 + "2:\n" \ 70 + " .pushsection .fixup,\"ax\"\n" \ 71 + " .align 2\n" \ 72 + "3: mov %0, #1\n" \ 73 + " b 2b\n" \ 74 + " .popsection\n" \ 75 + " .pushsection __ex_table,\"a\"\n" \ 76 + " .align 3\n" \ 77 + " .long 1b, 3b\n" \ 78 + " .popsection\n" \ 79 + : "=r" (err), "=&r" (val), "=r" (addr) \ 80 + : "0" (err), "2" (addr)) 81 + 82 + #define get8t_unaligned_check(val, addr, err) \ 83 + __asm__( \ 84 + "1: ldb.u %1, [%2], #1\n" \ 85 + "2:\n" \ 86 + " .pushsection .fixup,\"ax\"\n" \ 87 + " .align 2\n" \ 88 + "3: mov %0, #1\n" \ 89 + " b 2b\n" \ 90 + " .popsection\n" \ 91 + " .pushsection __ex_table,\"a\"\n" \ 92 + " .align 3\n" \ 93 + " .long 1b, 3b\n" \ 94 + " .popsection\n" \ 95 + : "=r" (err), "=&r" (val), "=r" (addr) \ 96 + : "0" (err), "2" (addr)) 97 + 98 + #define get16_unaligned_check(val, addr) \ 99 + do { \ 100 + unsigned int err = 0, v, a = addr; \ 101 + get8_unaligned_check(val, a, err); \ 102 + get8_unaligned_check(v, a, err); \ 103 + val |= v << 8; \ 104 + if (err) \ 105 + goto fault; \ 106 + } while (0) 107 + 108 + #define put16_unaligned_check(val, addr) \ 109 + do { \ 110 + unsigned int err = 0, v = val, a = addr; \ 111 + __asm__( \ 112 + "1: stb.u %1, [%2], #1\n" \ 113 + " mov %1, %1 >> #8\n" \ 114 + "2: stb.u %1, [%2]\n" \ 115 + "3:\n" \ 116 + " .pushsection .fixup,\"ax\"\n" \ 117 + " .align 2\n" \ 118 + "4: mov %0, #1\n" \ 119 + " b 3b\n" \ 120 + " .popsection\n" \ 121 + " .pushsection __ex_table,\"a\"\n" \ 122 + " .align 3\n" \ 123 + " .long 1b, 4b\n" \ 124 + " .long 2b, 4b\n" \ 125 + " .popsection\n" \ 126 + : "=r" (err), "=&r" (v), "=&r" (a) \ 127 + : "0" (err), "1" (v), "2" (a)); \ 128 + if (err) \ 129 + goto fault; \ 130 + } while (0) 131 + 132 + #define __put32_unaligned_check(ins, val, addr) \ 133 + do { \ 134 + unsigned int err = 0, v = val, a = addr; \ 135 + __asm__( \ 136 + "1: "ins" %1, [%2], #1\n" \ 137 + " mov %1, %1 >> #8\n" \ 138 + "2: "ins" %1, [%2], #1\n" \ 139 + " mov %1, %1 >> #8\n" \ 140 + "3: "ins" %1, [%2], #1\n" \ 141 + " mov %1, %1 >> #8\n" \ 142 + "4: "ins" %1, [%2]\n" \ 143 + "5:\n" \ 144 + " .pushsection .fixup,\"ax\"\n" \ 145 + " .align 2\n" \ 146 + "6: mov %0, #1\n" \ 147 + " b 5b\n" \ 148 + " .popsection\n" \ 149 + " .pushsection __ex_table,\"a\"\n" \ 150 + " .align 3\n" \ 151 + " .long 1b, 6b\n" \ 152 + " .long 2b, 6b\n" \ 153 + " .long 3b, 6b\n" \ 154 + " .long 4b, 6b\n" \ 155 + " .popsection\n" \ 156 + : "=r" (err), "=&r" (v), "=&r" (a) \ 157 + : "0" (err), "1" (v), "2" (a)); \ 158 + if (err) \ 159 + goto fault; \ 160 + } while (0) 161 + 162 + #define get32_unaligned_check(val, addr) \ 163 + do { \ 164 + unsigned int err = 0, v, a = addr; \ 165 + get8_unaligned_check(val, a, err); \ 166 + get8_unaligned_check(v, a, err); \ 167 + val |= v << 8; \ 168 + get8_unaligned_check(v, a, err); \ 169 + val |= v << 16; \ 170 + get8_unaligned_check(v, a, err); \ 171 + val |= v << 24; \ 172 + if (err) \ 173 + goto fault; \ 174 + } while (0) 175 + 176 + #define put32_unaligned_check(val, addr) \ 177 + __put32_unaligned_check("stb.u", val, addr) 178 + 179 + #define get32t_unaligned_check(val, addr) \ 180 + do { \ 181 + unsigned int err = 0, v, a = addr; \ 182 + get8t_unaligned_check(val, a, err); \ 183 + get8t_unaligned_check(v, a, err); \ 184 + val |= v << 8; \ 185 + get8t_unaligned_check(v, a, err); \ 186 + val |= v << 16; \ 187 + get8t_unaligned_check(v, a, err); \ 188 + val |= v << 24; \ 189 + if (err) \ 190 + goto fault; \ 191 + } while (0) 192 + 193 + #define put32t_unaligned_check(val, addr) \ 194 + __put32_unaligned_check("stb.u", val, addr) 195 + 196 + static void 197 + do_alignment_finish_ldst(unsigned long addr, unsigned long instr, 198 + struct pt_regs *regs, union offset_union offset) 199 + { 200 + if (!LDST_U_BIT(instr)) 201 + offset.un = -offset.un; 202 + 203 + if (!LDST_P_BIT(instr)) 204 + addr += offset.un; 205 + 206 + if (!LDST_P_BIT(instr) || LDST_W_BIT(instr)) 207 + regs->uregs[RN_BITS(instr)] = addr; 208 + } 209 + 210 + static int 211 + do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, 212 + struct pt_regs *regs) 213 + { 214 + unsigned int rd = RD_BITS(instr); 215 + 216 + /* old value 0x40002120, can't judge swap instr correctly */ 217 + if ((instr & 0x4b003fe0) == 0x40000120) 218 + goto swp; 219 + 220 + if (LDST_L_BIT(instr)) { 221 + unsigned long val; 222 + get16_unaligned_check(val, addr); 223 + 224 + /* signed half-word? */ 225 + if (instr & 0x80) 226 + val = (signed long)((signed short)val); 227 + 228 + regs->uregs[rd] = val; 229 + } else 230 + put16_unaligned_check(regs->uregs[rd], addr); 231 + 232 + return TYPE_LDST; 233 + 234 + swp: 235 + /* only handle swap word 236 + * for swap byte should not active this alignment exception */ 237 + get32_unaligned_check(regs->uregs[RD_BITS(instr)], addr); 238 + put32_unaligned_check(regs->uregs[RM_BITS(instr)], addr); 239 + return TYPE_SWAP; 240 + 241 + fault: 242 + return TYPE_FAULT; 243 + } 244 + 245 + static int 246 + do_alignment_ldrstr(unsigned long addr, unsigned long instr, 247 + struct pt_regs *regs) 248 + { 249 + unsigned int rd = RD_BITS(instr); 250 + 251 + if (!LDST_P_BIT(instr) && LDST_W_BIT(instr)) 252 + goto trans; 253 + 254 + if (LDST_L_BIT(instr)) 255 + get32_unaligned_check(regs->uregs[rd], addr); 256 + else 257 + put32_unaligned_check(regs->uregs[rd], addr); 258 + return TYPE_LDST; 259 + 260 + trans: 261 + if (LDST_L_BIT(instr)) 262 + get32t_unaligned_check(regs->uregs[rd], addr); 263 + else 264 + put32t_unaligned_check(regs->uregs[rd], addr); 265 + return TYPE_LDST; 266 + 267 + fault: 268 + return TYPE_FAULT; 269 + } 270 + 271 + /* 272 + * LDM/STM alignment handler. 273 + * 274 + * There are 4 variants of this instruction: 275 + * 276 + * B = rn pointer before instruction, A = rn pointer after instruction 277 + * ------ increasing address -----> 278 + * | | r0 | r1 | ... | rx | | 279 + * PU = 01 B A 280 + * PU = 11 B A 281 + * PU = 00 A B 282 + * PU = 10 A B 283 + */ 284 + static int 285 + do_alignment_ldmstm(unsigned long addr, unsigned long instr, 286 + struct pt_regs *regs) 287 + { 288 + unsigned int rd, rn, pc_correction, reg_correction, nr_regs, regbits; 289 + unsigned long eaddr, newaddr; 290 + 291 + if (LDM_S_BIT(instr)) 292 + goto bad; 293 + 294 + pc_correction = 4; /* processor implementation defined */ 295 + 296 + /* count the number of registers in the mask to be transferred */ 297 + nr_regs = hweight16(REGMASK_BITS(instr)) * 4; 298 + 299 + rn = RN_BITS(instr); 300 + newaddr = eaddr = regs->uregs[rn]; 301 + 302 + if (!LDST_U_BIT(instr)) 303 + nr_regs = -nr_regs; 304 + newaddr += nr_regs; 305 + if (!LDST_U_BIT(instr)) 306 + eaddr = newaddr; 307 + 308 + if (LDST_P_EQ_U(instr)) /* U = P */ 309 + eaddr += 4; 310 + 311 + /* 312 + * This is a "hint" - we already have eaddr worked out by the 313 + * processor for us. 314 + */ 315 + if (addr != eaddr) { 316 + printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, " 317 + "addr = %08lx, eaddr = %08lx\n", 318 + instruction_pointer(regs), instr, addr, eaddr); 319 + show_regs(regs); 320 + } 321 + 322 + if (LDM_H_BIT(instr)) 323 + reg_correction = 0x10; 324 + else 325 + reg_correction = 0x00; 326 + 327 + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; 328 + regbits >>= 1, rd += 1) 329 + if (regbits & 1) { 330 + if (LDST_L_BIT(instr)) 331 + get32_unaligned_check(regs-> 332 + uregs[rd + reg_correction], eaddr); 333 + else 334 + put32_unaligned_check(regs-> 335 + uregs[rd + reg_correction], eaddr); 336 + eaddr += 4; 337 + } 338 + 339 + if (LDST_W_BIT(instr)) 340 + regs->uregs[rn] = newaddr; 341 + return TYPE_DONE; 342 + 343 + fault: 344 + regs->UCreg_pc -= pc_correction; 345 + return TYPE_FAULT; 346 + 347 + bad: 348 + printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); 349 + return TYPE_ERROR; 350 + } 351 + 352 + static int 353 + do_alignment(unsigned long addr, unsigned int error_code, struct pt_regs *regs) 354 + { 355 + union offset_union offset; 356 + unsigned long instr, instrptr; 357 + int (*handler) (unsigned long addr, unsigned long instr, 358 + struct pt_regs *regs); 359 + unsigned int type; 360 + 361 + instrptr = instruction_pointer(regs); 362 + if (instrptr >= PAGE_OFFSET) 363 + instr = *(unsigned long *)instrptr; 364 + else { 365 + __asm__ __volatile__( 366 + "ldw.u %0, [%1]\n" 367 + : "=&r"(instr) 368 + : "r"(instrptr)); 369 + } 370 + 371 + regs->UCreg_pc += 4; 372 + 373 + switch (CODING_BITS(instr)) { 374 + case 0x40000120: /* ldrh or strh */ 375 + if (LDSTH_I_BIT(instr)) 376 + offset.un = (instr & 0x3e00) >> 4 | (instr & 31); 377 + else 378 + offset.un = regs->uregs[RM_BITS(instr)]; 379 + handler = do_alignment_ldrhstrh; 380 + break; 381 + 382 + case 0x60000000: /* ldr or str immediate */ 383 + case 0x60000100: /* ldr or str immediate */ 384 + case 0x60000020: /* ldr or str immediate */ 385 + case 0x60000120: /* ldr or str immediate */ 386 + offset.un = OFFSET_BITS(instr); 387 + handler = do_alignment_ldrstr; 388 + break; 389 + 390 + case 0x40000000: /* ldr or str register */ 391 + offset.un = regs->uregs[RM_BITS(instr)]; 392 + { 393 + unsigned int shiftval = SHIFT_BITS(instr); 394 + 395 + switch (SHIFT_TYPE(instr)) { 396 + case SHIFT_LSL: 397 + offset.un <<= shiftval; 398 + break; 399 + 400 + case SHIFT_LSR: 401 + offset.un >>= shiftval; 402 + break; 403 + 404 + case SHIFT_ASR: 405 + offset.sn >>= shiftval; 406 + break; 407 + 408 + case SHIFT_RORRRX: 409 + if (shiftval == 0) { 410 + offset.un >>= 1; 411 + if (regs->UCreg_asr & PSR_C_BIT) 412 + offset.un |= 1 << 31; 413 + } else 414 + offset.un = offset.un >> shiftval | 415 + offset.un << (32 - shiftval); 416 + break; 417 + } 418 + } 419 + handler = do_alignment_ldrstr; 420 + break; 421 + 422 + case 0x80000000: /* ldm or stm */ 423 + case 0x80000020: /* ldm or stm */ 424 + handler = do_alignment_ldmstm; 425 + break; 426 + 427 + default: 428 + goto bad; 429 + } 430 + 431 + type = handler(addr, instr, regs); 432 + 433 + if (type == TYPE_ERROR || type == TYPE_FAULT) 434 + goto bad_or_fault; 435 + 436 + if (type == TYPE_LDST) 437 + do_alignment_finish_ldst(addr, instr, regs, offset); 438 + 439 + return 0; 440 + 441 + bad_or_fault: 442 + if (type == TYPE_ERROR) 443 + goto bad; 444 + regs->UCreg_pc -= 4; 445 + /* 446 + * We got a fault - fix it up, or die. 447 + */ 448 + do_bad_area(addr, error_code, regs); 449 + return 0; 450 + 451 + bad: 452 + /* 453 + * Oops, we didn't handle the instruction. 454 + * However, we must handle fpu instr firstly. 455 + */ 456 + #ifdef CONFIG_UNICORE_FPU_F64 457 + /* handle co.load/store */ 458 + #define CODING_COLS 0xc0000000 459 + #define COLS_OFFSET_BITS(i) (i & 0x1FF) 460 + #define COLS_L_BITS(i) (i & (1<<24)) 461 + #define COLS_FN_BITS(i) ((i>>14) & 31) 462 + if ((instr & 0xe0000000) == CODING_COLS) { 463 + unsigned int fn = COLS_FN_BITS(instr); 464 + unsigned long val = 0; 465 + if (COLS_L_BITS(instr)) { 466 + get32t_unaligned_check(val, addr); 467 + switch (fn) { 468 + #define ASM_MTF(n) case n: \ 469 + __asm__ __volatile__("MTF %0, F" __stringify(n) \ 470 + : : "r"(val)); \ 471 + break; 472 + ASM_MTF(0); ASM_MTF(1); ASM_MTF(2); ASM_MTF(3); 473 + ASM_MTF(4); ASM_MTF(5); ASM_MTF(6); ASM_MTF(7); 474 + ASM_MTF(8); ASM_MTF(9); ASM_MTF(10); ASM_MTF(11); 475 + ASM_MTF(12); ASM_MTF(13); ASM_MTF(14); ASM_MTF(15); 476 + ASM_MTF(16); ASM_MTF(17); ASM_MTF(18); ASM_MTF(19); 477 + ASM_MTF(20); ASM_MTF(21); ASM_MTF(22); ASM_MTF(23); 478 + ASM_MTF(24); ASM_MTF(25); ASM_MTF(26); ASM_MTF(27); 479 + ASM_MTF(28); ASM_MTF(29); ASM_MTF(30); ASM_MTF(31); 480 + #undef ASM_MTF 481 + } 482 + } else { 483 + switch (fn) { 484 + #define ASM_MFF(n) case n: \ 485 + __asm__ __volatile__("MFF %0, F" __stringify(n) \ 486 + : : "r"(val)); \ 487 + break; 488 + ASM_MFF(0); ASM_MFF(1); ASM_MFF(2); ASM_MFF(3); 489 + ASM_MFF(4); ASM_MFF(5); ASM_MFF(6); ASM_MFF(7); 490 + ASM_MFF(8); ASM_MFF(9); ASM_MFF(10); ASM_MFF(11); 491 + ASM_MFF(12); ASM_MFF(13); ASM_MFF(14); ASM_MFF(15); 492 + ASM_MFF(16); ASM_MFF(17); ASM_MFF(18); ASM_MFF(19); 493 + ASM_MFF(20); ASM_MFF(21); ASM_MFF(22); ASM_MFF(23); 494 + ASM_MFF(24); ASM_MFF(25); ASM_MFF(26); ASM_MFF(27); 495 + ASM_MFF(28); ASM_MFF(29); ASM_MFF(30); ASM_MFF(31); 496 + #undef ASM_MFF 497 + } 498 + put32t_unaligned_check(val, addr); 499 + } 500 + return TYPE_COLS; 501 + } 502 + fault: 503 + return TYPE_FAULT; 504 + #endif 505 + printk(KERN_ERR "Alignment trap: not handling instruction " 506 + "%08lx at [<%08lx>]\n", instr, instrptr); 507 + return 1; 508 + } 509 + 510 + /* 511 + * This needs to be done after sysctl_init, otherwise sys/ will be 512 + * overwritten. Actually, this shouldn't be in sys/ at all since 513 + * it isn't a sysctl, and it doesn't contain sysctl information. 514 + */ 515 + static int __init alignment_init(void) 516 + { 517 + hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN, 518 + "alignment exception"); 519 + 520 + return 0; 521 + } 522 + 523 + fs_initcall(alignment_init);
+24
arch/unicore32/mm/extable.c
··· 1 + /* 2 + * linux/arch/unicore32/mm/extable.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <linux/module.h> 13 + #include <linux/uaccess.h> 14 + 15 + int fixup_exception(struct pt_regs *regs) 16 + { 17 + const struct exception_table_entry *fixup; 18 + 19 + fixup = search_exception_tables(instruction_pointer(regs)); 20 + if (fixup) 21 + regs->UCreg_pc = fixup->fixup; 22 + 23 + return fixup != NULL; 24 + }
+479
arch/unicore32/mm/fault.c
··· 1 + /* 2 + * linux/arch/unicore32/mm/fault.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <linux/module.h> 13 + #include <linux/signal.h> 14 + #include <linux/mm.h> 15 + #include <linux/hardirq.h> 16 + #include <linux/init.h> 17 + #include <linux/kprobes.h> 18 + #include <linux/uaccess.h> 19 + #include <linux/page-flags.h> 20 + #include <linux/sched.h> 21 + #include <linux/io.h> 22 + 23 + #include <asm/system.h> 24 + #include <asm/pgtable.h> 25 + #include <asm/tlbflush.h> 26 + 27 + /* 28 + * Fault status register encodings. We steal bit 31 for our own purposes. 29 + */ 30 + #define FSR_LNX_PF (1 << 31) 31 + 32 + static inline int fsr_fs(unsigned int fsr) 33 + { 34 + /* xyabcde will be abcde+xy */ 35 + return (fsr & 31) + ((fsr & (3 << 5)) >> 5); 36 + } 37 + 38 + /* 39 + * This is useful to dump out the page tables associated with 40 + * 'addr' in mm 'mm'. 41 + */ 42 + void show_pte(struct mm_struct *mm, unsigned long addr) 43 + { 44 + pgd_t *pgd; 45 + 46 + if (!mm) 47 + mm = &init_mm; 48 + 49 + printk(KERN_ALERT "pgd = %p\n", mm->pgd); 50 + pgd = pgd_offset(mm, addr); 51 + printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd)); 52 + 53 + do { 54 + pmd_t *pmd; 55 + pte_t *pte; 56 + 57 + if (pgd_none(*pgd)) 58 + break; 59 + 60 + if (pgd_bad(*pgd)) { 61 + printk("(bad)"); 62 + break; 63 + } 64 + 65 + pmd = pmd_offset((pud_t *) pgd, addr); 66 + if (PTRS_PER_PMD != 1) 67 + printk(", *pmd=%08lx", pmd_val(*pmd)); 68 + 69 + if (pmd_none(*pmd)) 70 + break; 71 + 72 + if (pmd_bad(*pmd)) { 73 + printk("(bad)"); 74 + break; 75 + } 76 + 77 + /* We must not map this if we have highmem enabled */ 78 + if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT))) 79 + break; 80 + 81 + pte = pte_offset_map(pmd, addr); 82 + printk(", *pte=%08lx", pte_val(*pte)); 83 + pte_unmap(pte); 84 + } while (0); 85 + 86 + printk("\n"); 87 + } 88 + 89 + /* 90 + * Oops. The kernel tried to access some page that wasn't present. 91 + */ 92 + static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, 93 + unsigned int fsr, struct pt_regs *regs) 94 + { 95 + /* 96 + * Are we prepared to handle this kernel fault? 97 + */ 98 + if (fixup_exception(regs)) 99 + return; 100 + 101 + /* 102 + * No handler, we'll have to terminate things with extreme prejudice. 103 + */ 104 + bust_spinlocks(1); 105 + printk(KERN_ALERT 106 + "Unable to handle kernel %s at virtual address %08lx\n", 107 + (addr < PAGE_SIZE) ? "NULL pointer dereference" : 108 + "paging request", addr); 109 + 110 + show_pte(mm, addr); 111 + die("Oops", regs, fsr); 112 + bust_spinlocks(0); 113 + do_exit(SIGKILL); 114 + } 115 + 116 + /* 117 + * Something tried to access memory that isn't in our memory map.. 118 + * User mode accesses just cause a SIGSEGV 119 + */ 120 + static void __do_user_fault(struct task_struct *tsk, unsigned long addr, 121 + unsigned int fsr, unsigned int sig, int code, 122 + struct pt_regs *regs) 123 + { 124 + struct siginfo si; 125 + 126 + tsk->thread.address = addr; 127 + tsk->thread.error_code = fsr; 128 + tsk->thread.trap_no = 14; 129 + si.si_signo = sig; 130 + si.si_errno = 0; 131 + si.si_code = code; 132 + si.si_addr = (void __user *)addr; 133 + force_sig_info(sig, &si, tsk); 134 + } 135 + 136 + void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) 137 + { 138 + struct task_struct *tsk = current; 139 + struct mm_struct *mm = tsk->active_mm; 140 + 141 + /* 142 + * If we are in kernel mode at this point, we 143 + * have no context to handle this fault with. 144 + */ 145 + if (user_mode(regs)) 146 + __do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs); 147 + else 148 + __do_kernel_fault(mm, addr, fsr, regs); 149 + } 150 + 151 + #define VM_FAULT_BADMAP 0x010000 152 + #define VM_FAULT_BADACCESS 0x020000 153 + 154 + /* 155 + * Check that the permissions on the VMA allow for the fault which occurred. 156 + * If we encountered a write fault, we must have write permission, otherwise 157 + * we allow any permission. 158 + */ 159 + static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma) 160 + { 161 + unsigned int mask = VM_READ | VM_WRITE | VM_EXEC; 162 + 163 + if (!(fsr ^ 0x12)) /* write? */ 164 + mask = VM_WRITE; 165 + if (fsr & FSR_LNX_PF) 166 + mask = VM_EXEC; 167 + 168 + return vma->vm_flags & mask ? false : true; 169 + } 170 + 171 + static int __do_pf(struct mm_struct *mm, unsigned long addr, unsigned int fsr, 172 + struct task_struct *tsk) 173 + { 174 + struct vm_area_struct *vma; 175 + int fault; 176 + 177 + vma = find_vma(mm, addr); 178 + fault = VM_FAULT_BADMAP; 179 + if (unlikely(!vma)) 180 + goto out; 181 + if (unlikely(vma->vm_start > addr)) 182 + goto check_stack; 183 + 184 + /* 185 + * Ok, we have a good vm_area for this 186 + * memory access, so we can handle it. 187 + */ 188 + good_area: 189 + if (access_error(fsr, vma)) { 190 + fault = VM_FAULT_BADACCESS; 191 + goto out; 192 + } 193 + 194 + /* 195 + * If for any reason at all we couldn't handle the fault, make 196 + * sure we exit gracefully rather than endlessly redo the fault. 197 + */ 198 + fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, 199 + (!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0); 200 + if (unlikely(fault & VM_FAULT_ERROR)) 201 + return fault; 202 + if (fault & VM_FAULT_MAJOR) 203 + tsk->maj_flt++; 204 + else 205 + tsk->min_flt++; 206 + return fault; 207 + 208 + check_stack: 209 + if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) 210 + goto good_area; 211 + out: 212 + return fault; 213 + } 214 + 215 + static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs) 216 + { 217 + struct task_struct *tsk; 218 + struct mm_struct *mm; 219 + int fault, sig, code; 220 + 221 + tsk = current; 222 + mm = tsk->mm; 223 + 224 + /* 225 + * If we're in an interrupt or have no user 226 + * context, we must not take the fault.. 227 + */ 228 + if (in_atomic() || !mm) 229 + goto no_context; 230 + 231 + /* 232 + * As per x86, we may deadlock here. However, since the kernel only 233 + * validly references user space from well defined areas of the code, 234 + * we can bug out early if this is from code which shouldn't. 235 + */ 236 + if (!down_read_trylock(&mm->mmap_sem)) { 237 + if (!user_mode(regs) 238 + && !search_exception_tables(regs->UCreg_pc)) 239 + goto no_context; 240 + down_read(&mm->mmap_sem); 241 + } else { 242 + /* 243 + * The above down_read_trylock() might have succeeded in 244 + * which case, we'll have missed the might_sleep() from 245 + * down_read() 246 + */ 247 + might_sleep(); 248 + #ifdef CONFIG_DEBUG_VM 249 + if (!user_mode(regs) && 250 + !search_exception_tables(regs->UCreg_pc)) 251 + goto no_context; 252 + #endif 253 + } 254 + 255 + fault = __do_pf(mm, addr, fsr, tsk); 256 + up_read(&mm->mmap_sem); 257 + 258 + /* 259 + * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR 260 + */ 261 + if (likely(!(fault & 262 + (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS)))) 263 + return 0; 264 + 265 + if (fault & VM_FAULT_OOM) { 266 + /* 267 + * We ran out of memory, call the OOM killer, and return to 268 + * userspace (which will retry the fault, or kill us if we 269 + * got oom-killed) 270 + */ 271 + pagefault_out_of_memory(); 272 + return 0; 273 + } 274 + 275 + /* 276 + * If we are in kernel mode at this point, we 277 + * have no context to handle this fault with. 278 + */ 279 + if (!user_mode(regs)) 280 + goto no_context; 281 + 282 + if (fault & VM_FAULT_SIGBUS) { 283 + /* 284 + * We had some memory, but were unable to 285 + * successfully fix up this page fault. 286 + */ 287 + sig = SIGBUS; 288 + code = BUS_ADRERR; 289 + } else { 290 + /* 291 + * Something tried to access memory that 292 + * isn't in our memory map.. 293 + */ 294 + sig = SIGSEGV; 295 + code = fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR; 296 + } 297 + 298 + __do_user_fault(tsk, addr, fsr, sig, code, regs); 299 + return 0; 300 + 301 + no_context: 302 + __do_kernel_fault(mm, addr, fsr, regs); 303 + return 0; 304 + } 305 + 306 + /* 307 + * First Level Translation Fault Handler 308 + * 309 + * We enter here because the first level page table doesn't contain 310 + * a valid entry for the address. 311 + * 312 + * If the address is in kernel space (>= TASK_SIZE), then we are 313 + * probably faulting in the vmalloc() area. 314 + * 315 + * If the init_task's first level page tables contains the relevant 316 + * entry, we copy the it to this task. If not, we send the process 317 + * a signal, fixup the exception, or oops the kernel. 318 + * 319 + * NOTE! We MUST NOT take any locks for this case. We may be in an 320 + * interrupt or a critical region, and should only copy the information 321 + * from the master page table, nothing more. 322 + */ 323 + static int do_ifault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) 324 + { 325 + unsigned int index; 326 + pgd_t *pgd, *pgd_k; 327 + pmd_t *pmd, *pmd_k; 328 + 329 + if (addr < TASK_SIZE) 330 + return do_pf(addr, fsr, regs); 331 + 332 + if (user_mode(regs)) 333 + goto bad_area; 334 + 335 + index = pgd_index(addr); 336 + 337 + pgd = cpu_get_pgd() + index; 338 + pgd_k = init_mm.pgd + index; 339 + 340 + if (pgd_none(*pgd_k)) 341 + goto bad_area; 342 + 343 + pmd_k = pmd_offset((pud_t *) pgd_k, addr); 344 + pmd = pmd_offset((pud_t *) pgd, addr); 345 + 346 + if (pmd_none(*pmd_k)) 347 + goto bad_area; 348 + 349 + set_pmd(pmd, *pmd_k); 350 + flush_pmd_entry(pmd); 351 + return 0; 352 + 353 + bad_area: 354 + do_bad_area(addr, fsr, regs); 355 + return 0; 356 + } 357 + 358 + /* 359 + * This abort handler always returns "fault". 360 + */ 361 + static int do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) 362 + { 363 + return 1; 364 + } 365 + 366 + static int do_good(unsigned long addr, unsigned int fsr, struct pt_regs *regs) 367 + { 368 + unsigned int res1, res2; 369 + 370 + printk("dabt exception but no error!\n"); 371 + 372 + __asm__ __volatile__( 373 + "mff %0,f0\n" 374 + "mff %1,f1\n" 375 + : "=r"(res1), "=r"(res2) 376 + : 377 + : "memory"); 378 + 379 + printk(KERN_EMERG "r0 :%08x r1 :%08x\n", res1, res2); 380 + panic("shut up\n"); 381 + return 0; 382 + } 383 + 384 + static struct fsr_info { 385 + int (*fn) (unsigned long addr, unsigned int fsr, struct pt_regs *regs); 386 + int sig; 387 + int code; 388 + const char *name; 389 + } fsr_info[] = { 390 + /* 391 + * The following are the standard Unicore-I and UniCore-II aborts. 392 + */ 393 + { do_good, SIGBUS, 0, "no error" }, 394 + { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, 395 + { do_bad, SIGBUS, BUS_OBJERR, "external exception" }, 396 + { do_bad, SIGBUS, 0, "burst operation" }, 397 + { do_bad, SIGBUS, 0, "unknown 00100" }, 398 + { do_ifault, SIGSEGV, SEGV_MAPERR, "2nd level pt non-exist"}, 399 + { do_bad, SIGBUS, 0, "2nd lvl large pt non-exist" }, 400 + { do_bad, SIGBUS, 0, "invalid pte" }, 401 + { do_pf, SIGSEGV, SEGV_MAPERR, "page miss" }, 402 + { do_bad, SIGBUS, 0, "middle page miss" }, 403 + { do_bad, SIGBUS, 0, "large page miss" }, 404 + { do_pf, SIGSEGV, SEGV_MAPERR, "super page (section) miss" }, 405 + { do_bad, SIGBUS, 0, "unknown 01100" }, 406 + { do_bad, SIGBUS, 0, "unknown 01101" }, 407 + { do_bad, SIGBUS, 0, "unknown 01110" }, 408 + { do_bad, SIGBUS, 0, "unknown 01111" }, 409 + { do_bad, SIGBUS, 0, "addr: up 3G or IO" }, 410 + { do_pf, SIGSEGV, SEGV_ACCERR, "read unreadable addr" }, 411 + { do_pf, SIGSEGV, SEGV_ACCERR, "write unwriteable addr"}, 412 + { do_pf, SIGSEGV, SEGV_ACCERR, "exec unexecutable addr"}, 413 + { do_bad, SIGBUS, 0, "unknown 10100" }, 414 + { do_bad, SIGBUS, 0, "unknown 10101" }, 415 + { do_bad, SIGBUS, 0, "unknown 10110" }, 416 + { do_bad, SIGBUS, 0, "unknown 10111" }, 417 + { do_bad, SIGBUS, 0, "unknown 11000" }, 418 + { do_bad, SIGBUS, 0, "unknown 11001" }, 419 + { do_bad, SIGBUS, 0, "unknown 11010" }, 420 + { do_bad, SIGBUS, 0, "unknown 11011" }, 421 + { do_bad, SIGBUS, 0, "unknown 11100" }, 422 + { do_bad, SIGBUS, 0, "unknown 11101" }, 423 + { do_bad, SIGBUS, 0, "unknown 11110" }, 424 + { do_bad, SIGBUS, 0, "unknown 11111" } 425 + }; 426 + 427 + void __init hook_fault_code(int nr, 428 + int (*fn) (unsigned long, unsigned int, struct pt_regs *), 429 + int sig, int code, const char *name) 430 + { 431 + if (nr < 0 || nr >= ARRAY_SIZE(fsr_info)) 432 + BUG(); 433 + 434 + fsr_info[nr].fn = fn; 435 + fsr_info[nr].sig = sig; 436 + fsr_info[nr].code = code; 437 + fsr_info[nr].name = name; 438 + } 439 + 440 + /* 441 + * Dispatch a data abort to the relevant handler. 442 + */ 443 + asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr, 444 + struct pt_regs *regs) 445 + { 446 + const struct fsr_info *inf = fsr_info + fsr_fs(fsr); 447 + struct siginfo info; 448 + 449 + if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) 450 + return; 451 + 452 + printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", 453 + inf->name, fsr, addr); 454 + 455 + info.si_signo = inf->sig; 456 + info.si_errno = 0; 457 + info.si_code = inf->code; 458 + info.si_addr = (void __user *)addr; 459 + uc32_notify_die("", regs, &info, fsr, 0); 460 + } 461 + 462 + asmlinkage void do_PrefetchAbort(unsigned long addr, 463 + unsigned int ifsr, struct pt_regs *regs) 464 + { 465 + const struct fsr_info *inf = fsr_info + fsr_fs(ifsr); 466 + struct siginfo info; 467 + 468 + if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) 469 + return; 470 + 471 + printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", 472 + inf->name, ifsr, addr); 473 + 474 + info.si_signo = inf->sig; 475 + info.si_errno = 0; 476 + info.si_code = inf->code; 477 + info.si_addr = (void __user *)addr; 478 + uc32_notify_die("", regs, &info, ifsr, 0); 479 + }
+533
arch/unicore32/mm/mmu.c
··· 1 + /* 2 + * linux/arch/unicore32/mm/mmu.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <linux/module.h> 13 + #include <linux/kernel.h> 14 + #include <linux/errno.h> 15 + #include <linux/init.h> 16 + #include <linux/mman.h> 17 + #include <linux/nodemask.h> 18 + #include <linux/memblock.h> 19 + #include <linux/fs.h> 20 + #include <linux/bootmem.h> 21 + #include <linux/io.h> 22 + 23 + #include <asm/cputype.h> 24 + #include <asm/sections.h> 25 + #include <asm/setup.h> 26 + #include <asm/sizes.h> 27 + #include <asm/tlb.h> 28 + 29 + #include <mach/map.h> 30 + 31 + #include "mm.h" 32 + 33 + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); 34 + 35 + /* 36 + * empty_zero_page is a special page that is used for 37 + * zero-initialized data and COW. 38 + */ 39 + struct page *empty_zero_page; 40 + EXPORT_SYMBOL(empty_zero_page); 41 + 42 + /* 43 + * The pmd table for the upper-most set of pages. 44 + */ 45 + pmd_t *top_pmd; 46 + 47 + pgprot_t pgprot_user; 48 + EXPORT_SYMBOL(pgprot_user); 49 + 50 + pgprot_t pgprot_kernel; 51 + EXPORT_SYMBOL(pgprot_kernel); 52 + 53 + static int __init noalign_setup(char *__unused) 54 + { 55 + cr_alignment &= ~CR_A; 56 + cr_no_alignment &= ~CR_A; 57 + set_cr(cr_alignment); 58 + return 1; 59 + } 60 + __setup("noalign", noalign_setup); 61 + 62 + void adjust_cr(unsigned long mask, unsigned long set) 63 + { 64 + unsigned long flags; 65 + 66 + mask &= ~CR_A; 67 + 68 + set &= mask; 69 + 70 + local_irq_save(flags); 71 + 72 + cr_no_alignment = (cr_no_alignment & ~mask) | set; 73 + cr_alignment = (cr_alignment & ~mask) | set; 74 + 75 + set_cr((get_cr() & ~mask) | set); 76 + 77 + local_irq_restore(flags); 78 + } 79 + 80 + struct map_desc { 81 + unsigned long virtual; 82 + unsigned long pfn; 83 + unsigned long length; 84 + unsigned int type; 85 + }; 86 + 87 + #define PROT_PTE_DEVICE (PTE_PRESENT | PTE_YOUNG | \ 88 + PTE_DIRTY | PTE_READ | PTE_WRITE) 89 + #define PROT_SECT_DEVICE (PMD_TYPE_SECT | PMD_PRESENT | \ 90 + PMD_SECT_READ | PMD_SECT_WRITE) 91 + 92 + static struct mem_type mem_types[] = { 93 + [MT_DEVICE] = { /* Strongly ordered */ 94 + .prot_pte = PROT_PTE_DEVICE, 95 + .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT, 96 + .prot_sect = PROT_SECT_DEVICE, 97 + }, 98 + /* 99 + * MT_KUSER: pte for vecpage -- cacheable, 100 + * and sect for unigfx mmap -- noncacheable 101 + */ 102 + [MT_KUSER] = { 103 + .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY | 104 + PTE_CACHEABLE | PTE_READ | PTE_EXEC, 105 + .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT, 106 + .prot_sect = PROT_SECT_DEVICE, 107 + }, 108 + [MT_HIGH_VECTORS] = { 109 + .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY | 110 + PTE_CACHEABLE | PTE_READ | PTE_WRITE | 111 + PTE_EXEC, 112 + .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT, 113 + }, 114 + [MT_MEMORY] = { 115 + .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY | 116 + PTE_WRITE | PTE_EXEC, 117 + .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT, 118 + .prot_sect = PMD_TYPE_SECT | PMD_PRESENT | PMD_SECT_CACHEABLE | 119 + PMD_SECT_READ | PMD_SECT_WRITE | PMD_SECT_EXEC, 120 + }, 121 + [MT_ROM] = { 122 + .prot_sect = PMD_TYPE_SECT | PMD_PRESENT | PMD_SECT_CACHEABLE | 123 + PMD_SECT_READ, 124 + }, 125 + }; 126 + 127 + const struct mem_type *get_mem_type(unsigned int type) 128 + { 129 + return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL; 130 + } 131 + EXPORT_SYMBOL(get_mem_type); 132 + 133 + /* 134 + * Adjust the PMD section entries according to the CPU in use. 135 + */ 136 + static void __init build_mem_type_table(void) 137 + { 138 + pgprot_user = __pgprot(PTE_PRESENT | PTE_YOUNG | PTE_CACHEABLE); 139 + pgprot_kernel = __pgprot(PTE_PRESENT | PTE_YOUNG | 140 + PTE_DIRTY | PTE_READ | PTE_WRITE | 141 + PTE_EXEC | PTE_CACHEABLE); 142 + } 143 + 144 + #define vectors_base() (vectors_high() ? 0xffff0000 : 0) 145 + 146 + static void __init *early_alloc(unsigned long sz) 147 + { 148 + void *ptr = __va(memblock_alloc(sz, sz)); 149 + memset(ptr, 0, sz); 150 + return ptr; 151 + } 152 + 153 + static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, 154 + unsigned long prot) 155 + { 156 + if (pmd_none(*pmd)) { 157 + pte_t *pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t)); 158 + __pmd_populate(pmd, __pa(pte) | prot); 159 + } 160 + BUG_ON(pmd_bad(*pmd)); 161 + return pte_offset_kernel(pmd, addr); 162 + } 163 + 164 + static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, 165 + unsigned long end, unsigned long pfn, 166 + const struct mem_type *type) 167 + { 168 + pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1); 169 + do { 170 + set_pte(pte, pfn_pte(pfn, __pgprot(type->prot_pte))); 171 + pfn++; 172 + } while (pte++, addr += PAGE_SIZE, addr != end); 173 + } 174 + 175 + static void __init alloc_init_section(pgd_t *pgd, unsigned long addr, 176 + unsigned long end, unsigned long phys, 177 + const struct mem_type *type) 178 + { 179 + pmd_t *pmd = pmd_offset((pud_t *)pgd, addr); 180 + 181 + /* 182 + * Try a section mapping - end, addr and phys must all be aligned 183 + * to a section boundary. 184 + */ 185 + if (((addr | end | phys) & ~SECTION_MASK) == 0) { 186 + pmd_t *p = pmd; 187 + 188 + do { 189 + set_pmd(pmd, __pmd(phys | type->prot_sect)); 190 + phys += SECTION_SIZE; 191 + } while (pmd++, addr += SECTION_SIZE, addr != end); 192 + 193 + flush_pmd_entry(p); 194 + } else { 195 + /* 196 + * No need to loop; pte's aren't interested in the 197 + * individual L1 entries. 198 + */ 199 + alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type); 200 + } 201 + } 202 + 203 + /* 204 + * Create the page directory entries and any necessary 205 + * page tables for the mapping specified by `md'. We 206 + * are able to cope here with varying sizes and address 207 + * offsets, and we take full advantage of sections. 208 + */ 209 + static void __init create_mapping(struct map_desc *md) 210 + { 211 + unsigned long phys, addr, length, end; 212 + const struct mem_type *type; 213 + pgd_t *pgd; 214 + 215 + if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) { 216 + printk(KERN_WARNING "BUG: not creating mapping for " 217 + "0x%08llx at 0x%08lx in user region\n", 218 + __pfn_to_phys((u64)md->pfn), md->virtual); 219 + return; 220 + } 221 + 222 + if ((md->type == MT_DEVICE || md->type == MT_ROM) && 223 + md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) { 224 + printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx " 225 + "overlaps vmalloc space\n", 226 + __pfn_to_phys((u64)md->pfn), md->virtual); 227 + } 228 + 229 + type = &mem_types[md->type]; 230 + 231 + addr = md->virtual & PAGE_MASK; 232 + phys = (unsigned long)__pfn_to_phys(md->pfn); 233 + length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); 234 + 235 + if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) { 236 + printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not " 237 + "be mapped using pages, ignoring.\n", 238 + __pfn_to_phys(md->pfn), addr); 239 + return; 240 + } 241 + 242 + pgd = pgd_offset_k(addr); 243 + end = addr + length; 244 + do { 245 + unsigned long next = pgd_addr_end(addr, end); 246 + 247 + alloc_init_section(pgd, addr, next, phys, type); 248 + 249 + phys += next - addr; 250 + addr = next; 251 + } while (pgd++, addr != end); 252 + } 253 + 254 + static void * __initdata vmalloc_min = (void *)(VMALLOC_END - SZ_128M); 255 + 256 + /* 257 + * vmalloc=size forces the vmalloc area to be exactly 'size' 258 + * bytes. This can be used to increase (or decrease) the vmalloc 259 + * area - the default is 128m. 260 + */ 261 + static int __init early_vmalloc(char *arg) 262 + { 263 + unsigned long vmalloc_reserve = memparse(arg, NULL); 264 + 265 + if (vmalloc_reserve < SZ_16M) { 266 + vmalloc_reserve = SZ_16M; 267 + printk(KERN_WARNING 268 + "vmalloc area too small, limiting to %luMB\n", 269 + vmalloc_reserve >> 20); 270 + } 271 + 272 + if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) { 273 + vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M); 274 + printk(KERN_WARNING 275 + "vmalloc area is too big, limiting to %luMB\n", 276 + vmalloc_reserve >> 20); 277 + } 278 + 279 + vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve); 280 + return 0; 281 + } 282 + early_param("vmalloc", early_vmalloc); 283 + 284 + static phys_addr_t lowmem_limit __initdata = SZ_1G; 285 + 286 + static void __init sanity_check_meminfo(void) 287 + { 288 + int i, j; 289 + 290 + lowmem_limit = __pa(vmalloc_min - 1) + 1; 291 + memblock_set_current_limit(lowmem_limit); 292 + 293 + for (i = 0, j = 0; i < meminfo.nr_banks; i++) { 294 + struct membank *bank = &meminfo.bank[j]; 295 + *bank = meminfo.bank[i]; 296 + j++; 297 + } 298 + meminfo.nr_banks = j; 299 + } 300 + 301 + static inline void prepare_page_table(void) 302 + { 303 + unsigned long addr; 304 + phys_addr_t end; 305 + 306 + /* 307 + * Clear out all the mappings below the kernel image. 308 + */ 309 + for (addr = 0; addr < MODULES_VADDR; addr += PGDIR_SIZE) 310 + pmd_clear(pmd_off_k(addr)); 311 + 312 + for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE) 313 + pmd_clear(pmd_off_k(addr)); 314 + 315 + /* 316 + * Find the end of the first block of lowmem. 317 + */ 318 + end = memblock.memory.regions[0].base + memblock.memory.regions[0].size; 319 + if (end >= lowmem_limit) 320 + end = lowmem_limit; 321 + 322 + /* 323 + * Clear out all the kernel space mappings, except for the first 324 + * memory bank, up to the end of the vmalloc region. 325 + */ 326 + for (addr = __phys_to_virt(end); 327 + addr < VMALLOC_END; addr += PGDIR_SIZE) 328 + pmd_clear(pmd_off_k(addr)); 329 + } 330 + 331 + /* 332 + * Reserve the special regions of memory 333 + */ 334 + void __init uc32_mm_memblock_reserve(void) 335 + { 336 + /* 337 + * Reserve the page tables. These are already in use, 338 + * and can only be in node 0. 339 + */ 340 + memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t)); 341 + 342 + #ifdef CONFIG_PUV3_UNIGFX 343 + /* 344 + * These should likewise go elsewhere. They pre-reserve the 345 + * screen/video memory region at the 48M~64M of main system memory. 346 + */ 347 + memblock_reserve(PKUNITY_UNIGFX_MMAP_BASE, PKUNITY_UNIGFX_MMAP_SIZE); 348 + memblock_reserve(PKUNITY_UVC_MMAP_BASE, PKUNITY_UVC_MMAP_SIZE); 349 + #endif 350 + } 351 + 352 + /* 353 + * Set up device the mappings. Since we clear out the page tables for all 354 + * mappings above VMALLOC_END, we will remove any debug device mappings. 355 + * This means you have to be careful how you debug this function, or any 356 + * called function. This means you can't use any function or debugging 357 + * method which may touch any device, otherwise the kernel _will_ crash. 358 + */ 359 + static void __init devicemaps_init(void) 360 + { 361 + struct map_desc map; 362 + unsigned long addr; 363 + void *vectors; 364 + 365 + /* 366 + * Allocate the vector page early. 367 + */ 368 + vectors = early_alloc(PAGE_SIZE); 369 + 370 + for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) 371 + pmd_clear(pmd_off_k(addr)); 372 + 373 + /* 374 + * Create a mapping for UniGFX VRAM 375 + */ 376 + #ifdef CONFIG_PUV3_UNIGFX 377 + map.pfn = __phys_to_pfn(PKUNITY_UNIGFX_MMAP_BASE); 378 + map.virtual = KUSER_UNIGFX_BASE; 379 + map.length = PKUNITY_UNIGFX_MMAP_SIZE; 380 + map.type = MT_KUSER; 381 + create_mapping(&map); 382 + #endif 383 + 384 + /* 385 + * Create a mapping for the machine vectors at the high-vectors 386 + * location (0xffff0000). If we aren't using high-vectors, also 387 + * create a mapping at the low-vectors virtual address. 388 + */ 389 + map.pfn = __phys_to_pfn(virt_to_phys(vectors)); 390 + map.virtual = VECTORS_BASE; 391 + map.length = PAGE_SIZE; 392 + map.type = MT_HIGH_VECTORS; 393 + create_mapping(&map); 394 + 395 + /* 396 + * Create a mapping for the kuser page at the special 397 + * location (0xbfff0000) to the same vectors location. 398 + */ 399 + map.pfn = __phys_to_pfn(virt_to_phys(vectors)); 400 + map.virtual = KUSER_VECPAGE_BASE; 401 + map.length = PAGE_SIZE; 402 + map.type = MT_KUSER; 403 + create_mapping(&map); 404 + 405 + /* 406 + * Finally flush the caches and tlb to ensure that we're in a 407 + * consistent state wrt the writebuffer. This also ensures that 408 + * any write-allocated cache lines in the vector page are written 409 + * back. After this point, we can start to touch devices again. 410 + */ 411 + local_flush_tlb_all(); 412 + flush_cache_all(); 413 + } 414 + 415 + static void __init map_lowmem(void) 416 + { 417 + struct memblock_region *reg; 418 + 419 + /* Map all the lowmem memory banks. */ 420 + for_each_memblock(memory, reg) { 421 + phys_addr_t start = reg->base; 422 + phys_addr_t end = start + reg->size; 423 + struct map_desc map; 424 + 425 + if (end > lowmem_limit) 426 + end = lowmem_limit; 427 + if (start >= end) 428 + break; 429 + 430 + map.pfn = __phys_to_pfn(start); 431 + map.virtual = __phys_to_virt(start); 432 + map.length = end - start; 433 + map.type = MT_MEMORY; 434 + 435 + create_mapping(&map); 436 + } 437 + } 438 + 439 + /* 440 + * paging_init() sets up the page tables, initialises the zone memory 441 + * maps, and sets up the zero page, bad page and bad page tables. 442 + */ 443 + void __init paging_init(void) 444 + { 445 + void *zero_page; 446 + 447 + build_mem_type_table(); 448 + sanity_check_meminfo(); 449 + prepare_page_table(); 450 + map_lowmem(); 451 + devicemaps_init(); 452 + 453 + top_pmd = pmd_off_k(0xffff0000); 454 + 455 + /* allocate the zero page. */ 456 + zero_page = early_alloc(PAGE_SIZE); 457 + 458 + bootmem_init(); 459 + 460 + empty_zero_page = virt_to_page(zero_page); 461 + __flush_dcache_page(NULL, empty_zero_page); 462 + } 463 + 464 + /* 465 + * In order to soft-boot, we need to insert a 1:1 mapping in place of 466 + * the user-mode pages. This will then ensure that we have predictable 467 + * results when turning the mmu off 468 + */ 469 + void setup_mm_for_reboot(char mode) 470 + { 471 + unsigned long base_pmdval; 472 + pgd_t *pgd; 473 + int i; 474 + 475 + /* 476 + * We need to access to user-mode page tables here. For kernel threads 477 + * we don't have any user-mode mappings so we use the context that we 478 + * "borrowed". 479 + */ 480 + pgd = current->active_mm->pgd; 481 + 482 + base_pmdval = PMD_SECT_WRITE | PMD_SECT_READ | PMD_TYPE_SECT; 483 + 484 + for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) { 485 + unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval; 486 + pmd_t *pmd; 487 + 488 + pmd = pmd_off(pgd, i << PGDIR_SHIFT); 489 + set_pmd(pmd, __pmd(pmdval)); 490 + flush_pmd_entry(pmd); 491 + } 492 + 493 + local_flush_tlb_all(); 494 + } 495 + 496 + /* 497 + * Take care of architecture specific things when placing a new PTE into 498 + * a page table, or changing an existing PTE. Basically, there are two 499 + * things that we need to take care of: 500 + * 501 + * 1. If PG_dcache_clean is not set for the page, we need to ensure 502 + * that any cache entries for the kernels virtual memory 503 + * range are written back to the page. 504 + * 2. If we have multiple shared mappings of the same space in 505 + * an object, we need to deal with the cache aliasing issues. 506 + * 507 + * Note that the pte lock will be held. 508 + */ 509 + void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, 510 + pte_t *ptep) 511 + { 512 + unsigned long pfn = pte_pfn(*ptep); 513 + struct address_space *mapping; 514 + struct page *page; 515 + 516 + if (!pfn_valid(pfn)) 517 + return; 518 + 519 + /* 520 + * The zero page is never written to, so never has any dirty 521 + * cache lines, and therefore never needs to be flushed. 522 + */ 523 + page = pfn_to_page(pfn); 524 + if (page == ZERO_PAGE(0)) 525 + return; 526 + 527 + mapping = page_mapping(page); 528 + if (!test_and_set_bit(PG_dcache_clean, &page->flags)) 529 + __flush_dcache_page(mapping, page); 530 + if (mapping) 531 + if (vma->vm_flags & VM_EXEC) 532 + __flush_icache_all(); 533 + }
+102
arch/unicore32/mm/pgd.c
··· 1 + /* 2 + * linux/arch/unicore32/mm/pgd.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <linux/mm.h> 13 + #include <linux/gfp.h> 14 + #include <linux/highmem.h> 15 + 16 + #include <asm/pgalloc.h> 17 + #include <asm/page.h> 18 + #include <asm/tlbflush.h> 19 + 20 + #include "mm.h" 21 + 22 + #define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) 23 + 24 + /* 25 + * need to get a 4k page for level 1 26 + */ 27 + pgd_t *get_pgd_slow(struct mm_struct *mm) 28 + { 29 + pgd_t *new_pgd, *init_pgd; 30 + pmd_t *new_pmd, *init_pmd; 31 + pte_t *new_pte, *init_pte; 32 + 33 + new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 0); 34 + if (!new_pgd) 35 + goto no_pgd; 36 + 37 + memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); 38 + 39 + /* 40 + * Copy over the kernel and IO PGD entries 41 + */ 42 + init_pgd = pgd_offset_k(0); 43 + memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, 44 + (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); 45 + 46 + clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); 47 + 48 + if (!vectors_high()) { 49 + /* 50 + * On UniCore, first page must always be allocated since it 51 + * contains the machine vectors. 52 + */ 53 + new_pmd = pmd_alloc(mm, (pud_t *)new_pgd, 0); 54 + if (!new_pmd) 55 + goto no_pmd; 56 + 57 + new_pte = pte_alloc_map(mm, new_pmd, 0); 58 + if (!new_pte) 59 + goto no_pte; 60 + 61 + init_pmd = pmd_offset((pud_t *)init_pgd, 0); 62 + init_pte = pte_offset_map(init_pmd, 0); 63 + set_pte(new_pte, *init_pte); 64 + pte_unmap(init_pte); 65 + pte_unmap(new_pte); 66 + } 67 + 68 + return new_pgd; 69 + 70 + no_pte: 71 + pmd_free(mm, new_pmd); 72 + no_pmd: 73 + free_pages((unsigned long)new_pgd, 0); 74 + no_pgd: 75 + return NULL; 76 + } 77 + 78 + void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd) 79 + { 80 + pmd_t *pmd; 81 + pgtable_t pte; 82 + 83 + if (!pgd) 84 + return; 85 + 86 + /* pgd is always present and good */ 87 + pmd = pmd_off(pgd, 0); 88 + if (pmd_none(*pmd)) 89 + goto free; 90 + if (pmd_bad(*pmd)) { 91 + pmd_ERROR(*pmd); 92 + pmd_clear(pmd); 93 + goto free; 94 + } 95 + 96 + pte = pmd_pgtable(*pmd); 97 + pmd_clear(pmd); 98 + pte_free(mm, pte); 99 + pmd_free(mm, pmd); 100 + free: 101 + free_pages((unsigned long) pgd, 0); 102 + }