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