fault.c (6879B)
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3 4#include <linux/extable.h> 5#include <linux/kprobes.h> 6#include <linux/mmu_context.h> 7#include <linux/perf_event.h> 8 9int fixup_exception(struct pt_regs *regs) 10{ 11 const struct exception_table_entry *fixup; 12 13 fixup = search_exception_tables(instruction_pointer(regs)); 14 if (fixup) { 15 regs->pc = fixup->fixup; 16 17 return 1; 18 } 19 20 return 0; 21} 22 23static inline bool is_write(struct pt_regs *regs) 24{ 25 switch (trap_no(regs)) { 26 case VEC_TLBINVALIDS: 27 return true; 28 case VEC_TLBMODIFIED: 29 return true; 30 } 31 32 return false; 33} 34 35#ifdef CONFIG_CPU_HAS_LDSTEX 36static inline void csky_cmpxchg_fixup(struct pt_regs *regs) 37{ 38 return; 39} 40#else 41extern unsigned long csky_cmpxchg_ldw; 42extern unsigned long csky_cmpxchg_stw; 43static inline void csky_cmpxchg_fixup(struct pt_regs *regs) 44{ 45 if (trap_no(regs) != VEC_TLBMODIFIED) 46 return; 47 48 if (instruction_pointer(regs) == csky_cmpxchg_stw) 49 instruction_pointer_set(regs, csky_cmpxchg_ldw); 50 return; 51} 52#endif 53 54static inline void no_context(struct pt_regs *regs, unsigned long addr) 55{ 56 current->thread.trap_no = trap_no(regs); 57 58 /* Are we prepared to handle this kernel fault? */ 59 if (fixup_exception(regs)) 60 return; 61 62 /* 63 * Oops. The kernel tried to access some bad page. We'll have to 64 * terminate things with extreme prejudice. 65 */ 66 bust_spinlocks(1); 67 pr_alert("Unable to handle kernel paging request at virtual " 68 "addr 0x%08lx, pc: 0x%08lx\n", addr, regs->pc); 69 die(regs, "Oops"); 70 make_task_dead(SIGKILL); 71} 72 73static inline void mm_fault_error(struct pt_regs *regs, unsigned long addr, vm_fault_t fault) 74{ 75 current->thread.trap_no = trap_no(regs); 76 77 if (fault & VM_FAULT_OOM) { 78 /* 79 * We ran out of memory, call the OOM killer, and return the userspace 80 * (which will retry the fault, or kill us if we got oom-killed). 81 */ 82 if (!user_mode(regs)) { 83 no_context(regs, addr); 84 return; 85 } 86 pagefault_out_of_memory(); 87 return; 88 } else if (fault & VM_FAULT_SIGBUS) { 89 /* Kernel mode? Handle exceptions or die */ 90 if (!user_mode(regs)) { 91 no_context(regs, addr); 92 return; 93 } 94 do_trap(regs, SIGBUS, BUS_ADRERR, addr); 95 return; 96 } 97 BUG(); 98} 99 100static inline void bad_area(struct pt_regs *regs, struct mm_struct *mm, int code, unsigned long addr) 101{ 102 /* 103 * Something tried to access memory that isn't in our memory map. 104 * Fix it, but check if it's kernel or user first. 105 */ 106 mmap_read_unlock(mm); 107 /* User mode accesses just cause a SIGSEGV */ 108 if (user_mode(regs)) { 109 do_trap(regs, SIGSEGV, code, addr); 110 return; 111 } 112 113 no_context(regs, addr); 114} 115 116static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long addr) 117{ 118 pgd_t *pgd, *pgd_k; 119 pud_t *pud, *pud_k; 120 pmd_t *pmd, *pmd_k; 121 pte_t *pte_k; 122 int offset; 123 124 /* User mode accesses just cause a SIGSEGV */ 125 if (user_mode(regs)) { 126 do_trap(regs, SIGSEGV, code, addr); 127 return; 128 } 129 130 /* 131 * Synchronize this task's top level page-table 132 * with the 'reference' page table. 133 * 134 * Do _not_ use "tsk" here. We might be inside 135 * an interrupt in the middle of a task switch.. 136 */ 137 offset = pgd_index(addr); 138 139 pgd = get_pgd() + offset; 140 pgd_k = init_mm.pgd + offset; 141 142 if (!pgd_present(*pgd_k)) { 143 no_context(regs, addr); 144 return; 145 } 146 set_pgd(pgd, *pgd_k); 147 148 pud = (pud_t *)pgd; 149 pud_k = (pud_t *)pgd_k; 150 if (!pud_present(*pud_k)) { 151 no_context(regs, addr); 152 return; 153 } 154 155 pmd = pmd_offset(pud, addr); 156 pmd_k = pmd_offset(pud_k, addr); 157 if (!pmd_present(*pmd_k)) { 158 no_context(regs, addr); 159 return; 160 } 161 set_pmd(pmd, *pmd_k); 162 163 pte_k = pte_offset_kernel(pmd_k, addr); 164 if (!pte_present(*pte_k)) { 165 no_context(regs, addr); 166 return; 167 } 168 169 flush_tlb_one(addr); 170} 171 172static inline bool access_error(struct pt_regs *regs, struct vm_area_struct *vma) 173{ 174 if (is_write(regs)) { 175 if (!(vma->vm_flags & VM_WRITE)) 176 return true; 177 } else { 178 if (unlikely(!vma_is_accessible(vma))) 179 return true; 180 } 181 return false; 182} 183 184/* 185 * This routine handles page faults. It determines the address and the 186 * problem, and then passes it off to one of the appropriate routines. 187 */ 188asmlinkage void do_page_fault(struct pt_regs *regs) 189{ 190 struct task_struct *tsk; 191 struct vm_area_struct *vma; 192 struct mm_struct *mm; 193 unsigned long addr = read_mmu_entryhi() & PAGE_MASK; 194 unsigned int flags = FAULT_FLAG_DEFAULT; 195 int code = SEGV_MAPERR; 196 vm_fault_t fault; 197 198 tsk = current; 199 mm = tsk->mm; 200 201 csky_cmpxchg_fixup(regs); 202 203 if (kprobe_page_fault(regs, tsk->thread.trap_no)) 204 return; 205 206 /* 207 * Fault-in kernel-space virtual memory on-demand. 208 * The 'reference' page table is init_mm.pgd. 209 * 210 * NOTE! We MUST NOT take any locks for this case. We may 211 * be in an interrupt or a critical region, and should 212 * only copy the information from the master page table, 213 * nothing more. 214 */ 215 if (unlikely((addr >= VMALLOC_START) && (addr <= VMALLOC_END))) { 216 vmalloc_fault(regs, code, addr); 217 return; 218 } 219 220 /* Enable interrupts if they were enabled in the parent context. */ 221 if (likely(regs->sr & BIT(6))) 222 local_irq_enable(); 223 224 /* 225 * If we're in an interrupt, have no user context, or are running 226 * in an atomic region, then we must not take the fault. 227 */ 228 if (unlikely(faulthandler_disabled() || !mm)) { 229 no_context(regs, addr); 230 return; 231 } 232 233 if (user_mode(regs)) 234 flags |= FAULT_FLAG_USER; 235 236 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); 237 238 if (is_write(regs)) 239 flags |= FAULT_FLAG_WRITE; 240retry: 241 mmap_read_lock(mm); 242 vma = find_vma(mm, addr); 243 if (unlikely(!vma)) { 244 bad_area(regs, mm, code, addr); 245 return; 246 } 247 if (likely(vma->vm_start <= addr)) 248 goto good_area; 249 if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) { 250 bad_area(regs, mm, code, addr); 251 return; 252 } 253 if (unlikely(expand_stack(vma, addr))) { 254 bad_area(regs, mm, code, addr); 255 return; 256 } 257 258 /* 259 * Ok, we have a good vm_area for this memory access, so 260 * we can handle it. 261 */ 262good_area: 263 code = SEGV_ACCERR; 264 265 if (unlikely(access_error(regs, vma))) { 266 bad_area(regs, mm, code, addr); 267 return; 268 } 269 270 /* 271 * If for any reason at all we could not handle the fault, 272 * make sure we exit gracefully rather than endlessly redo 273 * the fault. 274 */ 275 fault = handle_mm_fault(vma, addr, flags, regs); 276 277 /* 278 * If we need to retry but a fatal signal is pending, handle the 279 * signal first. We do not need to release the mmap_lock because it 280 * would already be released in __lock_page_or_retry in mm/filemap.c. 281 */ 282 if (fault_signal_pending(fault, regs)) { 283 if (!user_mode(regs)) 284 no_context(regs, addr); 285 return; 286 } 287 288 if (unlikely((fault & VM_FAULT_RETRY) && (flags & FAULT_FLAG_ALLOW_RETRY))) { 289 flags |= FAULT_FLAG_TRIED; 290 291 /* 292 * No need to mmap_read_unlock(mm) as we would 293 * have already released it in __lock_page_or_retry 294 * in mm/filemap.c. 295 */ 296 goto retry; 297 } 298 299 mmap_read_unlock(mm); 300 301 if (unlikely(fault & VM_FAULT_ERROR)) { 302 mm_fault_error(regs, addr, fault); 303 return; 304 } 305 return; 306}